• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 "perfetto/tracing/track_event_state_tracker.h"
18 
19 #include "perfetto/ext/base/hash.h"
20 
21 #include "protos/perfetto/common/interceptor_descriptor.gen.h"
22 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
23 #include "protos/perfetto/trace/trace_packet.pbzero.h"
24 #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
25 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
26 #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
27 #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
28 #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
29 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
30 
31 namespace perfetto {
32 
33 TrackEventStateTracker::~TrackEventStateTracker() = default;
34 TrackEventStateTracker::Delegate::~Delegate() = default;
35 
36 // static
ProcessTracePacket(Delegate & delegate,SequenceState & sequence_state,const protos::pbzero::TracePacket_Decoder & packet)37 void TrackEventStateTracker::ProcessTracePacket(
38     Delegate& delegate,
39     SequenceState& sequence_state,
40     const protos::pbzero::TracePacket_Decoder& packet) {
41   UpdateIncrementalState(delegate, sequence_state, packet);
42 
43   if (!packet.has_track_event())
44     return;
45   perfetto::protos::pbzero::TrackEvent::Decoder track_event(
46       packet.track_event());
47 
48   // TODO(skyostil): Support incremental timestamps.
49   uint64_t timestamp = packet.timestamp();
50 
51   Track* track = &sequence_state.track;
52   if (track_event.has_track_uuid()) {
53     auto* session_state = delegate.GetSessionState();
54     if (!session_state)
55       return;  // Tracing must have ended.
56     track = &session_state->tracks[track_event.track_uuid()];
57   }
58 
59   // We only log the first category of each event.
60   protozero::ConstChars category{};
61   uint64_t category_iid = 0;
62   if (auto iid_it = track_event.category_iids()) {
63     category_iid = *iid_it;
64     category.data = sequence_state.event_categories[category_iid].data();
65     category.size = sequence_state.event_categories[category_iid].size();
66   } else if (auto cat_it = track_event.categories()) {
67     category.data = reinterpret_cast<const char*>(cat_it->data());
68     category.size = cat_it->size();
69   }
70 
71   protozero::ConstChars name{};
72   uint64_t name_iid = track_event.name_iid();
73   uint64_t name_hash = 0;
74   uint64_t duration = 0;
75   if (name_iid) {
76     name.data = sequence_state.event_names[name_iid].data();
77     name.size = sequence_state.event_names[name_iid].size();
78   } else if (track_event.has_name()) {
79     name.data = track_event.name().data;
80     name.size = track_event.name().size;
81   }
82 
83   if (name.data) {
84     base::Hash hash;
85     hash.Update(name.data, name.size);
86     name_hash = hash.digest();
87   }
88 
89   size_t depth = track->stack.size();
90   switch (track_event.type()) {
91     case protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN: {
92       StackFrame frame;
93       frame.timestamp = timestamp;
94       frame.name_hash = name_hash;
95       if (track_event.has_track_uuid()) {
96         frame.name = name.ToStdString();
97         frame.category = category.ToStdString();
98       } else {
99         frame.name_iid = name_iid;
100         frame.category_iid = category_iid;
101       }
102       track->stack.push_back(std::move(frame));
103       break;
104     }
105     case protos::pbzero::TrackEvent::TYPE_SLICE_END:
106       if (!track->stack.empty()) {
107         const auto& prev_frame = track->stack.back();
108         if (prev_frame.name_iid) {
109           name.data = sequence_state.event_names[prev_frame.name_iid].data();
110           name.size = sequence_state.event_names[prev_frame.name_iid].size();
111         } else {
112           name.data = prev_frame.name.data();
113           name.size = prev_frame.name.size();
114         }
115         name_hash = prev_frame.name_hash;
116         if (prev_frame.category_iid) {
117           category.data =
118               sequence_state.event_categories[prev_frame.category_iid].data();
119           category.size =
120               sequence_state.event_categories[prev_frame.category_iid].size();
121         } else {
122           category.data = prev_frame.category.data();
123           category.size = prev_frame.category.size();
124         }
125         duration = timestamp - prev_frame.timestamp;
126         depth--;
127       }
128       break;
129     case protos::pbzero::TrackEvent::TYPE_INSTANT:
130       break;
131     case protos::pbzero::TrackEvent::TYPE_COUNTER:
132     case protos::pbzero::TrackEvent::TYPE_UNSPECIFIED:
133       // TODO(skyostil): Support counters.
134       return;
135   }
136 
137   ParsedTrackEvent parsed_event{track_event};
138   parsed_event.timestamp_ns = timestamp;
139   parsed_event.duration_ns = duration;
140   parsed_event.stack_depth = depth;
141   parsed_event.category = category;
142   parsed_event.name = name;
143   parsed_event.name_hash = name_hash;
144   delegate.OnTrackEvent(*track, parsed_event);
145 
146   if (track_event.type() == protos::pbzero::TrackEvent::TYPE_SLICE_END &&
147       !track->stack.empty()) {
148     track->stack.pop_back();
149   }
150 }
151 
152 // static
UpdateIncrementalState(Delegate & delegate,SequenceState & sequence_state,const protos::pbzero::TracePacket_Decoder & packet)153 void TrackEventStateTracker::UpdateIncrementalState(
154     Delegate& delegate,
155     SequenceState& sequence_state,
156     const protos::pbzero::TracePacket_Decoder& packet) {
157 #if PERFETTO_DCHECK_IS_ON()
158   if (!sequence_state.sequence_id) {
159     sequence_state.sequence_id = packet.trusted_packet_sequence_id();
160   } else {
161     PERFETTO_DCHECK(sequence_state.sequence_id ==
162                     packet.trusted_packet_sequence_id());
163   }
164 #endif
165 
166   if (packet.sequence_flags() &
167       perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED) {
168     // Convert any existing event names and categories on the stack to
169     // non-interned strings so we can look up their names even after the
170     // incremental state is gone.
171     for (auto& frame : sequence_state.track.stack) {
172       if (frame.name_iid) {
173         frame.name = sequence_state.event_names[frame.name_iid];
174         frame.name_iid = 0u;
175       }
176       if (frame.category_iid) {
177         frame.category = sequence_state.event_categories[frame.category_iid];
178         frame.category_iid = 0u;
179       }
180     }
181     sequence_state.event_names.clear();
182     sequence_state.event_categories.clear();
183     sequence_state.debug_annotation_names.clear();
184     sequence_state.track.uuid = 0u;
185     sequence_state.track.index = 0u;
186   }
187   if (packet.has_interned_data()) {
188     perfetto::protos::pbzero::InternedData::Decoder interned_data(
189         packet.interned_data());
190     for (auto it = interned_data.event_names(); it; it++) {
191       perfetto::protos::pbzero::EventName::Decoder entry(*it);
192       sequence_state.event_names[entry.iid()] = entry.name().ToStdString();
193     }
194     for (auto it = interned_data.event_categories(); it; it++) {
195       perfetto::protos::pbzero::EventCategory::Decoder entry(*it);
196       sequence_state.event_categories[entry.iid()] = entry.name().ToStdString();
197     }
198     for (auto it = interned_data.debug_annotation_names(); it; it++) {
199       perfetto::protos::pbzero::DebugAnnotationName::Decoder entry(*it);
200       sequence_state.debug_annotation_names[entry.iid()] =
201           entry.name().ToStdString();
202     }
203   }
204   if (packet.has_trace_packet_defaults()) {
205     perfetto::protos::pbzero::TracePacketDefaults::Decoder defaults(
206         packet.trace_packet_defaults());
207     if (defaults.has_track_event_defaults()) {
208       perfetto::protos::pbzero::TrackEventDefaults::Decoder
209           track_event_defaults(defaults.track_event_defaults());
210       sequence_state.track.uuid = track_event_defaults.track_uuid();
211     }
212   }
213   if (packet.has_track_descriptor()) {
214     perfetto::protos::pbzero::TrackDescriptor::Decoder track_descriptor(
215         packet.track_descriptor());
216     auto* session_state = delegate.GetSessionState();
217     auto& track = session_state->tracks[track_descriptor.uuid()];
218     if (!track.index)
219       track.index = static_cast<uint32_t>(session_state->tracks.size() + 1);
220     track.uuid = track_descriptor.uuid();
221 
222     track.name = track_descriptor.name().ToStdString();
223     track.pid = 0;
224     track.tid = 0;
225     if (track_descriptor.has_process()) {
226       perfetto::protos::pbzero::ProcessDescriptor::Decoder process(
227           track_descriptor.process());
228       track.pid = process.pid();
229       if (track.name.empty())
230         track.name = process.process_name().ToStdString();
231     } else if (track_descriptor.has_thread()) {
232       perfetto::protos::pbzero::ThreadDescriptor::Decoder thread(
233           track_descriptor.thread());
234       track.pid = thread.pid();
235       track.tid = thread.tid();
236       if (track.name.empty())
237         track.name = thread.thread_name().ToStdString();
238     }
239     delegate.OnTrackUpdated(track);
240 
241     // Mirror properties to the default track of the sequence. Note that
242     // this does not catch updates to the default track written through other
243     // sequences.
244     if (track.uuid == sequence_state.track.uuid) {
245       sequence_state.track.index = track.index;
246       sequence_state.track.name = track.name;
247       sequence_state.track.pid = track.pid;
248       sequence_state.track.tid = track.tid;
249       sequence_state.track.user_data = track.user_data;
250     }
251   }
252 }
253 
ParsedTrackEvent(const perfetto::protos::pbzero::TrackEvent::Decoder & track_event_)254 TrackEventStateTracker::ParsedTrackEvent::ParsedTrackEvent(
255     const perfetto::protos::pbzero::TrackEvent::Decoder& track_event_)
256     : track_event(track_event_) {}
257 
258 }  // namespace perfetto
259