1 /*
2 * Copyright (C) 2019 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 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_SYSTRACE_SYSTRACE_PARSER_H_
18 #define SRC_TRACE_PROCESSOR_IMPORTERS_SYSTRACE_SYSTRACE_PARSER_H_
19
20 #include <ostream>
21
22 #include "src/trace_processor/types/trace_processor_context.h"
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 "src/trace_processor/storage/trace_storage.h"
28
29 namespace perfetto {
30 namespace trace_processor {
31
32 namespace systrace_utils {
33
34 // Visible for unittesting.
35 enum class SystraceParseResult { kFailure = 0, kUnsupported, kSuccess };
36
37 // Visible for unittesting.
38 struct SystraceTracePoint {
SystraceTracePointSystraceTracePoint39 SystraceTracePoint() {}
40
BSystraceTracePoint41 static SystraceTracePoint B(uint32_t tgid, base::StringView name) {
42 return SystraceTracePoint('B', tgid, std::move(name), 0);
43 }
44
ESystraceTracePoint45 static SystraceTracePoint E(uint32_t tgid) {
46 return SystraceTracePoint('E', tgid, {}, 0);
47 }
48
49 static SystraceTracePoint C(uint32_t tgid,
50 base::StringView name,
51 double value,
52 base::StringView category_group = "") {
53 return SystraceTracePoint('C', tgid, std::move(name), value,
54 category_group);
55 }
56
SSystraceTracePoint57 static SystraceTracePoint S(uint32_t tgid,
58 base::StringView name,
59 double value) {
60 return SystraceTracePoint('S', tgid, std::move(name), value);
61 }
62
FSystraceTracePoint63 static SystraceTracePoint F(uint32_t tgid,
64 base::StringView name,
65 double value) {
66 return SystraceTracePoint('F', tgid, std::move(name), value);
67 }
68
69 SystraceTracePoint(char p,
70 uint32_t tg,
71 base::StringView n,
72 double v,
73 base::StringView c = "")
phaseSystraceTracePoint74 : phase(p), tgid(tg), name(std::move(n)), value(v), category_group(c) {}
75
76 // Phase can be one of B, E, C, S, F.
77 char phase = '\0';
78
79 uint32_t tgid = 0;
80
81 // For phase = 'B' and phase = 'C' only.
82 base::StringView name;
83
84 // For phase = 'C' only.
85 double value = 0;
86
87 // For phase = 'C' only (from Chrome).
88 base::StringView category_group;
89
90 // Visible for unittesting.
91 friend std::ostream& operator<<(std::ostream& os,
92 const SystraceTracePoint& point) {
93 return os << "SystraceTracePoint{'" << point.phase << "', " << point.tgid
94 << ", \"" << point.name.ToStdString() << "\", " << point.value
95 << "}";
96 }
97 };
98
99 // We have to handle trace_marker events of a few different types:
100 // 1. some random text
101 // 2. B|1636|pokeUserActivity
102 // 3. E|1636
103 // 4. C|1636|wq:monitor|0
104 // 5. S|1636|frame_capture|123
105 // 6. F|1636|frame_capture|456
106 // 7. C|3209|TransfersBytesPendingOnDisk-value|0|Blob
107 // Visible for unittesting.
ParseSystraceTracePoint(base::StringView str,SystraceTracePoint * out)108 inline SystraceParseResult ParseSystraceTracePoint(base::StringView str,
109 SystraceTracePoint* out) {
110 const char* s = str.data();
111 size_t len = str.size();
112 *out = {};
113
114 // We don't support empty events.
115 if (len == 0)
116 return SystraceParseResult::kFailure;
117
118 constexpr const char* kClockSyncPrefix = "trace_event_clock_sync:";
119 if (len >= strlen(kClockSyncPrefix) &&
120 strncmp(kClockSyncPrefix, s, strlen(kClockSyncPrefix)) == 0)
121 return SystraceParseResult::kUnsupported;
122
123 char ph = s[0];
124 if (ph != 'B' && ph != 'E' && ph != 'C' && ph != 'S' && ph != 'F')
125 return SystraceParseResult::kFailure;
126
127 out->phase = ph;
128
129 // We only support E events with no arguments.
130 if (len == 1 && ph != 'E')
131 return SystraceParseResult::kFailure;
132
133 // If str matches '[BEC]\|[0-9]+[\|\n]?' set tgid_length to the length of
134 // the number. Otherwise return kFailure.
135 if (len >= 2 && s[1] != '|' && s[1] != '\n')
136 return SystraceParseResult::kFailure;
137
138 size_t tgid_length = 0;
139 for (size_t i = 2; i < len; i++) {
140 if (s[i] == '|' || s[i] == '\n') {
141 break;
142 }
143 if (s[i] < '0' || s[i] > '9')
144 return SystraceParseResult::kFailure;
145 tgid_length++;
146 }
147
148 // If len == 1, tgid_length will be 0 which will ensure we don't do
149 // an out of bounds read.
150 std::string tgid_str(s + 2, tgid_length);
151 out->tgid = base::StringToUInt32(tgid_str).value_or(0);
152
153 switch (ph) {
154 case 'B': {
155 size_t name_index = 2 + tgid_length + 1;
156 out->name = base::StringView(
157 s + name_index, len - name_index - (s[len - 1] == '\n' ? 1 : 0));
158 if (out->name.empty()) {
159 static const char kEmptySliceName[] = "[empty slice name]";
160 out->name = base::StringView(kEmptySliceName);
161 }
162 return SystraceParseResult::kSuccess;
163 }
164 case 'E': {
165 return SystraceParseResult::kSuccess;
166 }
167 case 'S':
168 case 'F':
169 case 'C': {
170 size_t name_index = 2 + tgid_length + 1;
171 base::Optional<size_t> name_length;
172 for (size_t i = name_index; i < len; i++) {
173 if (s[i] == '|') {
174 name_length = i - name_index;
175 break;
176 }
177 }
178 if (!name_length.has_value())
179 return SystraceParseResult::kFailure;
180 out->name = base::StringView(s + name_index, name_length.value());
181
182 size_t value_index = name_index + name_length.value() + 1;
183 size_t value_pipe = str.find('|', value_index);
184 size_t value_len = value_pipe == base::StringView::npos
185 ? len - value_index
186 : value_pipe - value_index;
187 if (value_len == 0)
188 return SystraceParseResult::kFailure;
189 if (s[value_index + value_len - 1] == '\n')
190 value_len--;
191 std::string value_str(s + value_index, value_len);
192 base::Optional<double> maybe_value = base::StringToDouble(value_str);
193 if (!maybe_value.has_value()) {
194 return SystraceParseResult::kFailure;
195 }
196 out->value = maybe_value.value();
197
198 if (value_pipe != base::StringView::npos) {
199 size_t group_len = len - value_pipe - 1;
200 if (group_len == 0)
201 return SystraceParseResult::kFailure;
202 if (s[len - 1] == '\n')
203 group_len--;
204 out->category_group = base::StringView(s + value_pipe + 1, group_len);
205 }
206
207 return SystraceParseResult::kSuccess;
208 }
209 default:
210 return SystraceParseResult::kFailure;
211 }
212 }
213
214 // Visible for unittesting.
215 inline bool operator==(const SystraceTracePoint& x,
216 const SystraceTracePoint& y) {
217 return std::tie(x.phase, x.tgid, x.name, x.value) ==
218 std::tie(y.phase, y.tgid, y.name, y.value);
219 }
220
221 } // namespace systrace_utils
222
223 class SystraceParser : public Destructible {
224 public:
GetOrCreate(TraceProcessorContext * context)225 static SystraceParser* GetOrCreate(TraceProcessorContext* context) {
226 if (!context->systrace_parser) {
227 context->systrace_parser.reset(new SystraceParser(context));
228 }
229 return static_cast<SystraceParser*>(context->systrace_parser.get());
230 }
231 ~SystraceParser() override;
232
233 void ParsePrintEvent(int64_t ts, uint32_t pid, base::StringView event);
234
235 void ParseTracingMarkWrite(int64_t ts,
236 uint32_t pid,
237 char trace_type,
238 bool trace_begin,
239 base::StringView trace_name,
240 uint32_t tgid,
241 int64_t value);
242
243 void ParseZeroEvent(int64_t ts,
244 uint32_t pid,
245 int32_t flag,
246 base::StringView name,
247 uint32_t tgid,
248 int64_t value);
249
250 private:
251 explicit SystraceParser(TraceProcessorContext*);
252 void ParseSystracePoint(int64_t ts,
253 uint32_t pid,
254 systrace_utils::SystraceTracePoint event);
255
256 TraceProcessorContext* const context_;
257 const StringId lmk_id_;
258 const StringId screen_state_id_;
259 const StringId cookie_id_;
260 };
261
262 } // namespace trace_processor
263 } // namespace perfetto
264
265 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_SYSTRACE_SYSTRACE_PARSER_H_
266