xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/proto/v8_module.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/importers/proto/v8_module.h"
18 
19 #include <cstdint>
20 #include <optional>
21 
22 #include "perfetto/base/logging.h"
23 #include "protos/perfetto/trace/chrome/v8.pbzero.h"
24 #include "protos/perfetto/trace/trace_packet.pbzero.h"
25 #include "src/trace_processor/importers/common/parser_types.h"
26 #include "src/trace_processor/importers/common/process_tracker.h"
27 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
28 #include "src/trace_processor/importers/proto/v8_sequence_state.h"
29 #include "src/trace_processor/importers/proto/v8_tracker.h"
30 #include "src/trace_processor/storage/stats.h"
31 #include "src/trace_processor/storage/trace_storage.h"
32 #include "src/trace_processor/tables/metadata_tables_py.h"
33 #include "src/trace_processor/tables/v8_tables_py.h"
34 
35 namespace perfetto {
36 namespace trace_processor {
37 namespace {
38 
39 using ::perfetto::protos::pbzero::TracePacket;
40 using ::perfetto::protos::pbzero::V8CodeDefaults;
41 using ::perfetto::protos::pbzero::V8CodeMove;
42 using ::perfetto::protos::pbzero::V8InternalCode;
43 using ::perfetto::protos::pbzero::V8JsCode;
44 using ::perfetto::protos::pbzero::V8RegExpCode;
45 using ::perfetto::protos::pbzero::V8WasmCode;
46 
47 }  // namespace
48 
V8Module(TraceProcessorContext * context)49 V8Module::V8Module(TraceProcessorContext* context)
50     : context_(context), v8_tracker_(V8Tracker::GetOrCreate(context_)) {
51   RegisterForField(TracePacket::kV8JsCodeFieldNumber, context_);
52   RegisterForField(TracePacket::kV8InternalCodeFieldNumber, context_);
53   RegisterForField(TracePacket::kV8WasmCodeFieldNumber, context_);
54   RegisterForField(TracePacket::kV8RegExpCodeFieldNumber, context_);
55   RegisterForField(TracePacket::kV8CodeMoveFieldNumber, context_);
56 }
57 
58 V8Module::~V8Module() = default;
59 
TokenizePacket(const TracePacket::Decoder &,TraceBlobView *,int64_t,RefPtr<PacketSequenceStateGeneration>,uint32_t)60 ModuleResult V8Module::TokenizePacket(
61     const TracePacket::Decoder&,
62     TraceBlobView* /*packet*/,
63     int64_t /*packet_timestamp*/,
64     RefPtr<PacketSequenceStateGeneration> /*state*/,
65     uint32_t /*field_id*/) {
66   return ModuleResult::Ignored();
67 }
68 
ParseTracePacketData(const TracePacket::Decoder & decoder,int64_t ts,const TracePacketData & data,uint32_t field_id)69 void V8Module::ParseTracePacketData(const TracePacket::Decoder& decoder,
70                                     int64_t ts,
71                                     const TracePacketData& data,
72                                     uint32_t field_id) {
73   switch (field_id) {
74     case TracePacket::kV8JsCodeFieldNumber:
75       ParseV8JsCode(decoder.v8_js_code(), ts, data);
76       break;
77     case TracePacket::kV8InternalCodeFieldNumber:
78       ParseV8InternalCode(decoder.v8_internal_code(), ts, data);
79       break;
80     case TracePacket::kV8WasmCodeFieldNumber:
81       ParseV8WasmCode(decoder.v8_wasm_code(), ts, data);
82       break;
83     case TracePacket::kV8RegExpCodeFieldNumber:
84       ParseV8RegExpCode(decoder.v8_reg_exp_code(), ts, data);
85       break;
86     case TracePacket::kV8CodeMoveFieldNumber:
87       ParseV8CodeMove(decoder.v8_code_move(), ts, data);
88       break;
89     default:
90       break;
91   }
92 }
93 
94 template <typename CodeDecoder>
GetUtid(PacketSequenceStateGeneration & generation,IsolateId isolate_id,const CodeDecoder & code)95 std::optional<UniqueTid> V8Module::GetUtid(
96     PacketSequenceStateGeneration& generation,
97     IsolateId isolate_id,
98     const CodeDecoder& code) {
99   auto* pid = isolate_to_pid_.Find(isolate_id);
100   if (!pid) {
101     tables::ProcessTable::Id upid(
102         context_->storage->v8_isolate_table().FindById(isolate_id)->upid());
103     pid = isolate_to_pid_
104               .Insert(isolate_id,
105                       context_->storage->process_table().FindById(upid)->pid())
106               .first;
107   }
108 
109   if (code.has_tid()) {
110     return context_->process_tracker->UpdateThread(code.tid(), *pid);
111   }
112 
113   if (auto tid = GetDefaultTid(generation); tid.has_value()) {
114     return context_->process_tracker->UpdateThread(*tid, *pid);
115   }
116 
117   return std::nullopt;
118 }
119 
GetDefaultTid(PacketSequenceStateGeneration & generation) const120 std::optional<uint32_t> V8Module::GetDefaultTid(
121     PacketSequenceStateGeneration& generation) const {
122   auto* tp_defaults = generation.GetTracePacketDefaults();
123   if (!tp_defaults) {
124     context_->storage->IncrementStats(stats::v8_no_defaults);
125     return std::nullopt;
126   }
127   if (!tp_defaults->has_v8_code_defaults()) {
128     context_->storage->IncrementStats(stats::v8_no_defaults);
129     return std::nullopt;
130   }
131 
132   V8CodeDefaults::Decoder v8_defaults(tp_defaults->v8_code_defaults());
133 
134   if (!v8_defaults.has_tid()) {
135     context_->storage->IncrementStats(stats::v8_no_defaults);
136     return std::nullopt;
137   }
138 
139   return v8_defaults.tid();
140 }
141 
ParseV8JsCode(protozero::ConstBytes bytes,int64_t ts,const TracePacketData & data)142 void V8Module::ParseV8JsCode(protozero::ConstBytes bytes,
143                              int64_t ts,
144                              const TracePacketData& data) {
145   V8SequenceState& state =
146       *data.sequence_state->GetCustomState<V8SequenceState>();
147 
148   V8JsCode::Decoder code(bytes);
149 
150   auto v8_isolate_id = state.GetOrInsertIsolate(code.v8_isolate_iid());
151   if (!v8_isolate_id) {
152     return;
153   }
154 
155   std::optional<UniqueTid> utid =
156       GetUtid(*data.sequence_state, *v8_isolate_id, code);
157   if (!utid) {
158     return;
159   }
160 
161   auto v8_function_id =
162       state.GetOrInsertJsFunction(code.v8_js_function_iid(), *v8_isolate_id);
163   if (!v8_function_id) {
164     return;
165   }
166 
167   v8_tracker_->AddJsCode(ts, *utid, *v8_isolate_id, *v8_function_id, code);
168 }
169 
ParseV8InternalCode(protozero::ConstBytes bytes,int64_t ts,const TracePacketData & data)170 void V8Module::ParseV8InternalCode(protozero::ConstBytes bytes,
171                                    int64_t ts,
172                                    const TracePacketData& data) {
173   V8SequenceState& state =
174       *data.sequence_state->GetCustomState<V8SequenceState>();
175 
176   V8InternalCode::Decoder code(bytes);
177 
178   auto v8_isolate_id = state.GetOrInsertIsolate(code.v8_isolate_iid());
179   if (!v8_isolate_id) {
180     return;
181   }
182 
183   std::optional<UniqueTid> utid =
184       GetUtid(*data.sequence_state, *v8_isolate_id, code);
185   if (!utid) {
186     return;
187   }
188 
189   v8_tracker_->AddInternalCode(ts, *utid, *v8_isolate_id, code);
190 }
191 
ParseV8WasmCode(protozero::ConstBytes bytes,int64_t ts,const TracePacketData & data)192 void V8Module::ParseV8WasmCode(protozero::ConstBytes bytes,
193                                int64_t ts,
194                                const TracePacketData& data) {
195   V8SequenceState& state =
196       *data.sequence_state->GetCustomState<V8SequenceState>();
197 
198   V8WasmCode::Decoder code(bytes);
199 
200   auto v8_isolate_id = state.GetOrInsertIsolate(code.v8_isolate_iid());
201   if (!v8_isolate_id) {
202     return;
203   }
204 
205   auto v8_wasm_script_id =
206       state.GetOrInsertWasmScript(code.v8_wasm_script_iid(), *v8_isolate_id);
207   if (!v8_wasm_script_id) {
208     return;
209   }
210 
211   std::optional<UniqueTid> utid =
212       GetUtid(*data.sequence_state, *v8_isolate_id, code);
213   if (!utid) {
214     return;
215   }
216 
217   v8_tracker_->AddWasmCode(ts, *utid, *v8_isolate_id, *v8_wasm_script_id, code);
218 }
219 
ParseV8RegExpCode(protozero::ConstBytes bytes,int64_t ts,const TracePacketData & data)220 void V8Module::ParseV8RegExpCode(protozero::ConstBytes bytes,
221                                  int64_t ts,
222                                  const TracePacketData& data) {
223   V8SequenceState& state =
224       *data.sequence_state->GetCustomState<V8SequenceState>();
225 
226   V8RegExpCode::Decoder code(bytes);
227 
228   auto v8_isolate_id = state.GetOrInsertIsolate(code.v8_isolate_iid());
229   if (!v8_isolate_id) {
230     return;
231   }
232 
233   std::optional<UniqueTid> utid =
234       GetUtid(*data.sequence_state, *v8_isolate_id, code);
235   if (!utid) {
236     return;
237   }
238 
239   v8_tracker_->AddRegExpCode(ts, *utid, *v8_isolate_id, code);
240 }
241 
ParseV8CodeMove(protozero::ConstBytes bytes,int64_t,const TracePacketData & data)242 void V8Module::ParseV8CodeMove(protozero::ConstBytes bytes,
243                                int64_t,
244                                const TracePacketData& data) {
245   V8SequenceState& state =
246       *data.sequence_state->GetCustomState<V8SequenceState>();
247   protos::pbzero::V8CodeMove::Decoder v8_code_move(bytes);
248 
249   std::optional<IsolateId> isolate_id =
250       state.GetOrInsertIsolate(v8_code_move.isolate_iid());
251   if (!isolate_id) {
252     return;
253   }
254 
255   // TODO(carlscab): Implement
256 }
257 
258 }  // namespace trace_processor
259 }  // namespace perfetto
260