• 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/systrace/systrace_parser.h"
18 
19 #include "perfetto/ext/base/optional.h"
20 #include "src/trace_processor/importers/common/event_tracker.h"
21 #include "src/trace_processor/importers/common/process_tracker.h"
22 #include "src/trace_processor/importers/common/slice_tracker.h"
23 #include "src/trace_processor/importers/common/track_tracker.h"
24 
25 namespace perfetto {
26 namespace trace_processor {
27 
SystraceParser(TraceProcessorContext * ctx)28 SystraceParser::SystraceParser(TraceProcessorContext* ctx)
29     : context_(ctx),
30       lmk_id_(ctx->storage->InternString("mem.lmk")),
31       screen_state_id_(ctx->storage->InternString("ScreenState")) {}
32 
33 SystraceParser::~SystraceParser() = default;
34 
ParsePrintEvent(int64_t ts,uint32_t pid,base::StringView event)35 void SystraceParser::ParsePrintEvent(int64_t ts,
36                                      uint32_t pid,
37                                      base::StringView event) {
38   systrace_utils::SystraceTracePoint point{};
39   switch (ParseSystraceTracePoint(event, &point)) {
40     case systrace_utils::SystraceParseResult::kSuccess:
41       ParseSystracePoint(ts, pid, point);
42       break;
43     case systrace_utils::SystraceParseResult::kFailure:
44       context_->storage->IncrementStats(stats::systrace_parse_failure);
45       break;
46     case systrace_utils::SystraceParseResult::kUnsupported:
47       // Silently ignore unsupported results.
48       break;
49   }
50 }
51 
ParseZeroEvent(int64_t ts,uint32_t pid,int32_t flag,base::StringView name,uint32_t tgid,int64_t value)52 void SystraceParser::ParseZeroEvent(int64_t ts,
53                                     uint32_t pid,
54                                     int32_t flag,
55                                     base::StringView name,
56                                     uint32_t tgid,
57                                     int64_t value) {
58   systrace_utils::SystraceTracePoint point{};
59   point.name = name;
60   point.tgid = tgid;
61   point.value = value;
62 
63   // The value of these constants can be found in the msm-google kernel.
64   constexpr int32_t kSystraceEventBegin = 1 << 0;
65   constexpr int32_t kSystraceEventEnd = 1 << 1;
66   constexpr int32_t kSystraceEventInt64 = 1 << 2;
67 
68   if ((flag & kSystraceEventBegin) != 0) {
69     point.phase = 'B';
70   } else if ((flag & kSystraceEventEnd) != 0) {
71     point.phase = 'E';
72   } else if ((flag & kSystraceEventInt64) != 0) {
73     point.phase = 'C';
74   } else {
75     context_->storage->IncrementStats(stats::systrace_parse_failure);
76     return;
77   }
78   ParseSystracePoint(ts, pid, point);
79 }
80 
ParseSdeTracingMarkWrite(int64_t ts,uint32_t pid,char trace_type,bool trace_begin,base::StringView trace_name,uint32_t,int64_t value)81 void SystraceParser::ParseSdeTracingMarkWrite(int64_t ts,
82                                               uint32_t pid,
83                                               char trace_type,
84                                               bool trace_begin,
85                                               base::StringView trace_name,
86                                               uint32_t /* tgid */,
87                                               int64_t value) {
88   systrace_utils::SystraceTracePoint point{};
89   point.name = trace_name;
90 
91   // Hardcode the tgid to 0 (i.e. no tgid available) because
92   // sde_tracing_mark_write events can come from kernel threads and because we
93   // group kernel threads into the kthreadd process, we would want |point.tgid
94   // == kKthreaddPid|. However, we don't have acces to the ppid of this process
95   // so we have to not associate to any process and leave the resolution of
96   // process to other events.
97   // TODO(lalitm): remove this hack once we move kernel thread grouping to
98   // the UI.
99   point.tgid = 0;
100 
101   point.value = value;
102   // Some versions of this trace point fill trace_type with one of (B/E/C),
103   // others use the trace_begin boolean and only support begin/end events:
104   if (trace_type == 0) {
105     point.phase = trace_begin ? 'B' : 'E';
106   } else if (trace_type == 'B' || trace_type == 'E' || trace_type == 'C') {
107     point.phase = trace_type;
108   } else {
109     context_->storage->IncrementStats(stats::systrace_parse_failure);
110     return;
111   }
112 
113   ParseSystracePoint(ts, pid, point);
114 }
115 
ParseSystracePoint(int64_t ts,uint32_t pid,systrace_utils::SystraceTracePoint point)116 void SystraceParser::ParseSystracePoint(
117     int64_t ts,
118     uint32_t pid,
119     systrace_utils::SystraceTracePoint point) {
120   switch (point.phase) {
121     case 'B': {
122       StringId name_id = context_->storage->InternString(point.name);
123       UniqueTid utid;
124       if (point.tgid == 0) {
125         utid = context_->process_tracker->GetOrCreateThread(pid);
126       } else {
127         utid = context_->process_tracker->UpdateThread(pid, point.tgid);
128       }
129       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
130       context_->slice_tracker->Begin(ts, track_id, kNullStringId /* cat */,
131                                      name_id);
132       break;
133     }
134 
135     case 'E': {
136       // |point.tgid| can be 0 in older android versions where the end event
137       // would not contain the value.
138       UniqueTid utid;
139       if (point.tgid == 0) {
140         // If we haven't seen this thread before, there can't have been a Begin
141         // event for it so just ignore the event.
142         auto opt_utid = context_->process_tracker->GetThreadOrNull(pid);
143         if (!opt_utid)
144           break;
145         utid = *opt_utid;
146       } else {
147         utid = context_->process_tracker->UpdateThread(pid, point.tgid);
148       }
149       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
150       context_->slice_tracker->End(ts, track_id);
151       break;
152     }
153 
154     case 'S':
155     case 'F': {
156       StringId name_id = context_->storage->InternString(point.name);
157       int64_t cookie = static_cast<int64_t>(point.value);
158       UniquePid upid =
159           context_->process_tracker->GetOrCreateProcess(point.tgid);
160 
161       TrackId track_id = context_->track_tracker->InternAndroidAsyncTrack(
162           name_id, upid, cookie);
163       if (point.phase == 'S') {
164         context_->slice_tracker->Begin(ts, track_id, kNullStringId, name_id);
165       } else {
166         context_->slice_tracker->End(ts, track_id);
167       }
168       break;
169     }
170 
171     case 'C': {
172       // LMK events from userspace are hacked as counter events with the "value"
173       // of the counter representing the pid of the killed process which is
174       // reset to 0 once the kill is complete.
175       // Homogenise this with kernel LMK events as an instant event, ignoring
176       // the resets to 0.
177       if (point.name == "kill_one_process") {
178         auto killed_pid = static_cast<uint32_t>(point.value);
179         if (killed_pid != 0) {
180           UniquePid killed_upid =
181               context_->process_tracker->GetOrCreateProcess(killed_pid);
182           context_->event_tracker->PushInstant(ts, lmk_id_, killed_upid,
183                                                RefType::kRefUpid);
184         }
185         // TODO(lalitm): we should not add LMK events to the counters table
186         // once the UI has support for displaying instants.
187       } else if (point.name == "ScreenState") {
188         // Promote ScreenState to its own top level counter.
189         TrackId track =
190             context_->track_tracker->InternGlobalCounterTrack(screen_state_id_);
191         context_->event_tracker->PushCounter(ts, point.value, track);
192         return;
193       }
194       // This is per upid on purpose. Some counters are pushed from arbitrary
195       // threads but are really per process.
196       UniquePid upid =
197           context_->process_tracker->GetOrCreateProcess(point.tgid);
198       StringId name_id = context_->storage->InternString(point.name);
199       TrackId track =
200           context_->track_tracker->InternProcessCounterTrack(name_id, upid);
201       context_->event_tracker->PushCounter(ts, point.value, track);
202     }
203   }
204 }
205 
206 }  // namespace trace_processor
207 }  // namespace perfetto
208