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 "src/trace_processor/importers/proto/async_track_set_tracker.h"
18
19 #include "src/trace_processor/importers/common/track_tracker.h"
20 #include "src/trace_processor/types/trace_processor_context.h"
21
22 namespace perfetto {
23 namespace trace_processor {
24
AsyncTrackSetTracker(TraceProcessorContext * context)25 AsyncTrackSetTracker::AsyncTrackSetTracker(TraceProcessorContext* context)
26 : context_(context) {}
27
InternGlobalTrackSet(StringId name)28 AsyncTrackSetTracker::TrackSetId AsyncTrackSetTracker::InternGlobalTrackSet(
29 StringId name) {
30 auto it = global_track_set_ids_.find(name);
31 if (it != global_track_set_ids_.end()) {
32 return it->second;
33 }
34
35 uint32_t id = static_cast<uint32_t>(track_sets_.size());
36 TrackSet set;
37 set.global_track_name = name;
38 set.type = TrackSetType::kGlobal;
39 set.nesting_behaviour = NestingBehaviour::kUnnestable;
40 track_sets_.emplace_back(set);
41
42 return global_track_set_ids_[name] = id;
43 }
44
InternAndroidSet(UniquePid upid,StringId name)45 AsyncTrackSetTracker::TrackSetId AsyncTrackSetTracker::InternAndroidSet(
46 UniquePid upid,
47 StringId name) {
48 AndroidTuple tuple{upid, name};
49
50 auto it = android_track_set_ids_.find(tuple);
51 if (it != android_track_set_ids_.end())
52 return it->second;
53
54 uint32_t id = static_cast<uint32_t>(track_sets_.size());
55
56 TrackSet set;
57 set.android_tuple = tuple;
58 set.type = TrackSetType::kAndroid;
59 set.nesting_behaviour = NestingBehaviour::kLegacySaturatingUnnestable;
60 track_sets_.emplace_back(set);
61
62 android_track_set_ids_[tuple] = id;
63 return id;
64 }
65
InternFrameTimelineSet(UniquePid upid,StringId name)66 AsyncTrackSetTracker::TrackSetId AsyncTrackSetTracker::InternFrameTimelineSet(
67 UniquePid upid,
68 StringId name) {
69 FrameTimelineTuple tuple{upid, name};
70
71 auto it = frame_timeline_track_set_ids_.find(tuple);
72 if (it != frame_timeline_track_set_ids_.end())
73 return it->second;
74
75 uint32_t id = static_cast<uint32_t>(track_sets_.size());
76
77 TrackSet set;
78 set.frame_timeline_tuple = tuple;
79 set.type = TrackSetType::kFrameTimeline;
80 set.nesting_behaviour = NestingBehaviour::kUnnestable;
81 track_sets_.emplace_back(set);
82
83 frame_timeline_track_set_ids_[tuple] = id;
84 return id;
85 }
86
Begin(TrackSetId id,int64_t cookie)87 TrackId AsyncTrackSetTracker::Begin(TrackSetId id, int64_t cookie) {
88 PERFETTO_DCHECK(id < track_sets_.size());
89
90 TrackSet& set = track_sets_[id];
91 TrackState& state = GetOrCreateTrackForCookie(set, cookie);
92 switch (set.nesting_behaviour) {
93 case NestingBehaviour::kLegacySaturatingUnnestable:
94 PERFETTO_DCHECK(state.nest_count <= 1);
95 state.nest_count = 1;
96 break;
97 case NestingBehaviour::kUnnestable:
98 PERFETTO_DCHECK(state.nest_count == 0);
99 state.nest_count++;
100 break;
101 }
102 return state.id;
103 }
104
End(TrackSetId id,int64_t cookie)105 TrackId AsyncTrackSetTracker::End(TrackSetId id, int64_t cookie) {
106 PERFETTO_DCHECK(id < track_sets_.size());
107
108 TrackSet& set = track_sets_[id];
109 TrackState& state = GetOrCreateTrackForCookie(set, cookie);
110
111 // It's possible to have a nest count of 0 even when we know about the track.
112 // Suppose the following sequence of events for some |id| and |cookie|:
113 // Begin
114 // (trace starts)
115 // Begin
116 // End
117 // End <- nest count == 0 here even though we have a record of this track.
118 if (state.nest_count > 0)
119 state.nest_count--;
120 return state.id;
121 }
122
Scoped(TrackSetId id,int64_t ts,int64_t dur)123 TrackId AsyncTrackSetTracker::Scoped(TrackSetId id, int64_t ts, int64_t dur) {
124 PERFETTO_DCHECK(id < track_sets_.size());
125
126 TrackSet& set = track_sets_[id];
127 PERFETTO_DCHECK(set.nesting_behaviour == NestingBehaviour::kUnnestable);
128
129 auto it = std::find_if(
130 set.tracks.begin(), set.tracks.end(), [ts](const TrackState& state) {
131 return state.slice_type == TrackState::SliceType::kTimestamp &&
132 state.ts_end <= ts;
133 });
134 if (it != set.tracks.end())
135 return it->id;
136
137 TrackState state;
138 state.slice_type = TrackState::SliceType::kTimestamp;
139 state.ts_end = ts + dur;
140 state.id = CreateTrackForSet(set);
141 set.tracks.emplace_back(state);
142
143 return state.id;
144 }
145
146 AsyncTrackSetTracker::TrackState&
GetOrCreateTrackForCookie(TrackSet & set,int64_t cookie)147 AsyncTrackSetTracker::GetOrCreateTrackForCookie(TrackSet& set, int64_t cookie) {
148 auto it = std::find_if(
149 set.tracks.begin(), set.tracks.end(), [cookie](const TrackState& state) {
150 return state.slice_type == TrackState::SliceType::kCookie &&
151 state.cookie == cookie;
152 });
153 if (it != set.tracks.end())
154 return *it;
155
156 it = std::find_if(
157 set.tracks.begin(), set.tracks.end(), [](const TrackState& state) {
158 return state.slice_type == TrackState::SliceType::kCookie &&
159 state.nest_count == 0;
160 });
161 if (it != set.tracks.end()) {
162 // Adopt this track for the cookie to make sure future slices with this
163 // cookie also get associated to this track.
164 it->cookie = cookie;
165 return *it;
166 }
167
168 TrackState state;
169 state.id = CreateTrackForSet(set);
170 state.slice_type = TrackState::SliceType::kCookie;
171 state.cookie = cookie;
172 state.nest_count = 0;
173 set.tracks.emplace_back(state);
174
175 return set.tracks.back();
176 }
177
CreateTrackForSet(const TrackSet & set)178 TrackId AsyncTrackSetTracker::CreateTrackForSet(const TrackSet& set) {
179 switch (set.type) {
180 case TrackSetType::kGlobal:
181 return context_->track_tracker->CreateGlobalAsyncTrack(
182 set.global_track_name);
183 case TrackSetType::kAndroid:
184 return context_->track_tracker->CreateAndroidAsyncTrack(
185 set.android_tuple.name, set.android_tuple.upid);
186 case TrackSetType::kFrameTimeline:
187 return context_->track_tracker->CreateFrameTimelineAsyncTrack(
188 set.frame_timeline_tuple.name, set.frame_timeline_tuple.upid);
189 }
190 PERFETTO_FATAL("For GCC");
191 }
192
193 } // namespace trace_processor
194 } // namespace perfetto
195