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