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