• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.size() == 0)
159         return SystraceParseResult::kFailure;
160       return SystraceParseResult::kSuccess;
161     }
162     case 'E': {
163       return SystraceParseResult::kSuccess;
164     }
165     case 'S':
166     case 'F':
167     case 'C': {
168       size_t name_index = 2 + tgid_length + 1;
169       base::Optional<size_t> name_length;
170       for (size_t i = name_index; i < len; i++) {
171         if (s[i] == '|') {
172           name_length = i - name_index;
173           break;
174         }
175       }
176       if (!name_length.has_value())
177         return SystraceParseResult::kFailure;
178       out->name = base::StringView(s + name_index, name_length.value());
179 
180       size_t value_index = name_index + name_length.value() + 1;
181       size_t value_pipe = str.find('|', value_index);
182       size_t value_len = value_pipe == base::StringView::npos
183                              ? len - value_index
184                              : value_pipe - value_index;
185       if (value_len == 0)
186         return SystraceParseResult::kFailure;
187       if (s[value_index + value_len - 1] == '\n')
188         value_len--;
189       std::string value_str(s + value_index, value_len);
190       base::Optional<double> maybe_value = base::StringToDouble(value_str);
191       if (!maybe_value.has_value()) {
192         return SystraceParseResult::kFailure;
193       }
194       out->value = maybe_value.value();
195 
196       if (value_pipe != base::StringView::npos) {
197         size_t group_len = len - value_pipe - 1;
198         if (group_len == 0)
199           return SystraceParseResult::kFailure;
200         if (s[len - 1] == '\n')
201           group_len--;
202         out->category_group = base::StringView(s + value_pipe + 1, group_len);
203       }
204 
205       return SystraceParseResult::kSuccess;
206     }
207     default:
208       return SystraceParseResult::kFailure;
209   }
210 }
211 
212 // Visible for unittesting.
213 inline bool operator==(const SystraceTracePoint& x,
214                        const SystraceTracePoint& y) {
215   return std::tie(x.phase, x.tgid, x.name, x.value) ==
216          std::tie(y.phase, y.tgid, y.name, y.value);
217 }
218 
219 }  // namespace systrace_utils
220 
221 class SystraceParser : public Destructible {
222  public:
GetOrCreate(TraceProcessorContext * context)223   static SystraceParser* GetOrCreate(TraceProcessorContext* context) {
224     if (!context->systrace_parser) {
225       context->systrace_parser.reset(new SystraceParser(context));
226     }
227     return static_cast<SystraceParser*>(context->systrace_parser.get());
228   }
229   ~SystraceParser() override;
230 
231   void ParsePrintEvent(int64_t ts, uint32_t pid, base::StringView event);
232 
233   void ParseSdeTracingMarkWrite(int64_t ts,
234                                 uint32_t pid,
235                                 char trace_type,
236                                 bool trace_begin,
237                                 base::StringView trace_name,
238                                 uint32_t tgid,
239                                 int64_t value);
240 
241   void ParseZeroEvent(int64_t ts,
242                       uint32_t pid,
243                       int32_t flag,
244                       base::StringView name,
245                       uint32_t tgid,
246                       int64_t value);
247 
248  private:
249   explicit SystraceParser(TraceProcessorContext*);
250   void ParseSystracePoint(int64_t ts,
251                           uint32_t pid,
252                           systrace_utils::SystraceTracePoint event);
253 
254   TraceProcessorContext* const context_;
255   const StringId lmk_id_;
256   const StringId screen_state_id_;
257 };
258 
259 }  // namespace trace_processor
260 }  // namespace perfetto
261 
262 #endif  // SRC_TRACE_PROCESSOR_IMPORTERS_SYSTRACE_SYSTRACE_PARSER_H_
263