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