• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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/json/json_trace_parser.h"
18 
19 #include <inttypes.h>
20 
21 #include <limits>
22 #include <string>
23 
24 #include "perfetto/base/logging.h"
25 #include "perfetto/ext/base/string_utils.h"
26 #include "perfetto/ext/base/string_view.h"
27 #include "perfetto/ext/base/utils.h"
28 #include "src/trace_processor/importers/common/flow_tracker.h"
29 #include "src/trace_processor/importers/common/process_tracker.h"
30 #include "src/trace_processor/importers/common/slice_tracker.h"
31 #include "src/trace_processor/importers/common/track_tracker.h"
32 #include "src/trace_processor/importers/json/json_tracker.h"
33 #include "src/trace_processor/importers/json/json_utils.h"
34 #include "src/trace_processor/types/trace_processor_context.h"
35 
36 namespace perfetto {
37 namespace trace_processor {
38 
39 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
40 namespace {
41 
MaybeExtractFlowIdentifier(const Json::Value & value,bool version2)42 base::Optional<uint64_t> MaybeExtractFlowIdentifier(const Json::Value& value,
43                                                     bool version2) {
44   std::string id_key = (version2 ? "bind_id" : "id");
45   if (!value.isMember(id_key))
46     return base::nullopt;
47   auto id = value[id_key];
48   if (id.isNumeric())
49     return id.asUInt64();
50   if (!id.isString())
51     return base::nullopt;
52   const char* c_string = id.asCString();
53   return base::CStringToUInt64(c_string, 16);
54 }
55 
56 }  // namespace
57 #endif  // PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
58 
JsonTraceParser(TraceProcessorContext * context)59 JsonTraceParser::JsonTraceParser(TraceProcessorContext* context)
60     : context_(context), systrace_line_parser_(context) {}
61 
62 JsonTraceParser::~JsonTraceParser() = default;
63 
ParseFtracePacket(uint32_t,int64_t,TimestampedTracePiece)64 void JsonTraceParser::ParseFtracePacket(uint32_t,
65                                         int64_t,
66                                         TimestampedTracePiece) {
67   PERFETTO_FATAL("Json Trace Parser cannot handle ftrace packets.");
68 }
69 
ParseTracePacket(int64_t timestamp,TimestampedTracePiece ttp)70 void JsonTraceParser::ParseTracePacket(int64_t timestamp,
71                                        TimestampedTracePiece ttp) {
72   PERFETTO_DCHECK(json::IsJsonSupported());
73 
74 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
75   PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kJsonValue ||
76                   ttp.type == TimestampedTracePiece::Type::kSystraceLine);
77   if (ttp.type == TimestampedTracePiece::Type::kSystraceLine) {
78     systrace_line_parser_.ParseLine(*ttp.systrace_line);
79     return;
80   }
81 
82   auto opt_value = json::ParseJsonString(base::StringView(ttp.json_value));
83   if (!opt_value) {
84     context_->storage->IncrementStats(stats::json_parser_failure);
85     return;
86   }
87 
88   ProcessTracker* procs = context_->process_tracker.get();
89   TraceStorage* storage = context_->storage.get();
90   SliceTracker* slice_tracker = context_->slice_tracker.get();
91   FlowTracker* flow_tracker = context_->flow_tracker.get();
92 
93   const Json::Value& value = *opt_value;
94   auto& ph = value["ph"];
95   if (!ph.isString())
96     return;
97   char phase = *ph.asCString();
98 
99   base::Optional<uint32_t> opt_pid;
100   base::Optional<uint32_t> opt_tid;
101 
102   if (value.isMember("pid"))
103     opt_pid = json::CoerceToUint32(value["pid"]);
104   if (value.isMember("tid"))
105     opt_tid = json::CoerceToUint32(value["tid"]);
106 
107   uint32_t pid = opt_pid.value_or(0);
108   uint32_t tid = opt_tid.value_or(pid);
109 
110   base::StringView cat = value.isMember("cat")
111                              ? base::StringView(value["cat"].asCString())
112                              : base::StringView();
113   base::StringView name = value.isMember("name")
114                               ? base::StringView(value["name"].asCString())
115                               : base::StringView();
116 
117   StringId cat_id = storage->InternString(cat);
118   StringId name_id = storage->InternString(name);
119   UniqueTid utid = procs->UpdateThread(tid, pid);
120 
121   auto args_inserter = [this, &value](ArgsTracker::BoundInserter* inserter) {
122     if (value.isMember("args")) {
123       json::AddJsonValueToArgs(value["args"], /* flat_key = */ "args",
124                                /* key = */ "args", context_->storage.get(),
125                                inserter);
126     }
127   };
128   switch (phase) {
129     case 'B': {  // TRACE_EVENT_BEGIN.
130       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
131       slice_tracker->Begin(timestamp, track_id, cat_id, name_id, args_inserter);
132       MaybeAddFlow(track_id, value);
133       break;
134     }
135     case 'E': {  // TRACE_EVENT_END.
136       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
137       slice_tracker->End(timestamp, track_id, cat_id, name_id, args_inserter);
138       break;
139     }
140     case 'X': {  // TRACE_EVENT (scoped event).
141       base::Optional<int64_t> opt_dur =
142           JsonTracker::GetOrCreate(context_)->CoerceToTs(value["dur"]);
143       if (!opt_dur.has_value())
144         return;
145       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
146       slice_tracker->Scoped(timestamp, track_id, cat_id, name_id,
147                             opt_dur.value(), args_inserter);
148       MaybeAddFlow(track_id, value);
149       break;
150     }
151     case 's': {  // TRACE_EVENT_FLOW_START
152       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
153       auto opt_source_id =
154           MaybeExtractFlowIdentifier(value, /* version2 = */ false);
155       if (opt_source_id) {
156         FlowId flow_id = flow_tracker->GetFlowIdForV1Event(
157             opt_source_id.value(), cat_id, name_id);
158         flow_tracker->Begin(track_id, flow_id);
159       } else {
160         context_->storage->IncrementStats(stats::flow_invalid_id);
161       }
162       break;
163     }
164     case 't': {  // TRACE_EVENT_FLOW_STEP
165       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
166       auto opt_source_id =
167           MaybeExtractFlowIdentifier(value, /* version2 = */ false);
168       if (opt_source_id) {
169         FlowId flow_id = flow_tracker->GetFlowIdForV1Event(
170             opt_source_id.value(), cat_id, name_id);
171         flow_tracker->Step(track_id, flow_id);
172       } else {
173         context_->storage->IncrementStats(stats::flow_invalid_id);
174       }
175       break;
176     }
177     case 'f': {  // TRACE_EVENT_FLOW_END
178       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
179       auto opt_source_id =
180           MaybeExtractFlowIdentifier(value, /* version2 = */ false);
181       if (opt_source_id) {
182         FlowId flow_id = flow_tracker->GetFlowIdForV1Event(
183             opt_source_id.value(), cat_id, name_id);
184         bool bind_enclosing_slice =
185             value.isMember("bp") && strcmp(value["bp"].asCString(), "e") == 0;
186         flow_tracker->End(track_id, flow_id, bind_enclosing_slice,
187                           /* close_flow = */ false);
188       } else {
189         context_->storage->IncrementStats(stats::flow_invalid_id);
190       }
191       break;
192     }
193     case 'M': {  // Metadata events (process and thread names).
194       if (strcmp(value["name"].asCString(), "thread_name") == 0 &&
195           !value["args"]["name"].empty()) {
196         const char* thread_name = value["args"]["name"].asCString();
197         auto thread_name_id = context_->storage->InternString(thread_name);
198         procs->UpdateThreadName(tid, thread_name_id,
199                                 ThreadNamePriority::kOther);
200         break;
201       }
202       if (strcmp(value["name"].asCString(), "process_name") == 0 &&
203           !value["args"]["name"].empty()) {
204         const char* proc_name = value["args"]["name"].asCString();
205         procs->SetProcessMetadata(pid, base::nullopt, proc_name,
206                                   base::StringView());
207         break;
208       }
209     }
210   }
211 #else
212   perfetto::base::ignore_result(timestamp);
213   perfetto::base::ignore_result(ttp);
214   perfetto::base::ignore_result(context_);
215   PERFETTO_ELOG("Cannot parse JSON trace due to missing JSON support");
216 #endif  // PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
217 }
218 
MaybeAddFlow(TrackId track_id,const Json::Value & event)219 void JsonTraceParser::MaybeAddFlow(TrackId track_id, const Json::Value& event) {
220   PERFETTO_DCHECK(json::IsJsonSupported());
221 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
222   auto opt_bind_id = MaybeExtractFlowIdentifier(event, /* version2 = */ true);
223   if (opt_bind_id) {
224     FlowTracker* flow_tracker = context_->flow_tracker.get();
225     bool flow_out = event.isMember("flow_out") && event["flow_out"].asBool();
226     bool flow_in = event.isMember("flow_in") && event["flow_in"].asBool();
227     if (flow_in && flow_out) {
228       flow_tracker->Step(track_id, opt_bind_id.value());
229     } else if (flow_out) {
230       flow_tracker->Begin(track_id, opt_bind_id.value());
231     } else if (flow_in) {
232       // bind_enclosing_slice is always true for v2 flow events
233       flow_tracker->End(track_id, opt_bind_id.value(), true,
234                         /* close_flow = */ false);
235     } else {
236       context_->storage->IncrementStats(stats::flow_without_direction);
237     }
238   }
239 #endif  // PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
240 }
241 
242 }  // namespace trace_processor
243 }  // namespace perfetto
244 
245