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 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_TRACKER_H_ 18 #define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_TRACKER_H_ 19 20 #include <unordered_set> 21 22 #include "src/trace_processor/importers/common/args_tracker.h" 23 #include "src/trace_processor/storage/trace_storage.h" 24 #include "src/trace_processor/types/trace_processor_context.h" 25 26 namespace perfetto { 27 namespace trace_processor { 28 29 // Tracks and stores tracks based on track types, ids and scopes. 30 class TrackEventTracker { 31 public: 32 explicit TrackEventTracker(TraceProcessorContext*); 33 34 // Associate a TrackDescriptor track identified by the given |uuid| with a 35 // process's |pid|. This is called during tokenization. If a reservation for 36 // the same |uuid| already exists, verifies that the present reservation 37 // matches the new one. 38 // 39 // The track will be resolved to the process track (see InternProcessTrack()) 40 // upon the first call to GetDescriptorTrack() with the same |uuid|. At this 41 // time, |pid| will also be resolved to a |upid|. 42 void ReserveDescriptorProcessTrack(uint64_t uuid, 43 StringId name, 44 uint32_t pid, 45 int64_t timestamp); 46 47 // Associate a TrackDescriptor track identified by the given |uuid| with a 48 // thread's |pid| and |tid|. This is called during tokenization. If a 49 // reservation for the same |uuid| already exists, verifies that the present 50 // reservation matches the new one. 51 // 52 // The track will be resolved to the thread track (see InternThreadTrack()) 53 // upon the first call to GetDescriptorTrack() with the same |uuid|. At this 54 // time, |pid| will also be resolved to a |upid|. 55 void ReserveDescriptorThreadTrack(uint64_t uuid, 56 uint64_t parent_uuid, 57 StringId name, 58 uint32_t pid, 59 uint32_t tid, 60 int64_t timestamp, 61 bool use_separate_track); 62 63 // Associate a TrackDescriptor track identified by the given |uuid| with a 64 // parent track (usually a process- or thread-associated track). This is 65 // called during tokenization. If a reservation for the same |uuid| already 66 // exists, will attempt to update it. 67 // 68 // The track will be created upon the first call to GetDescriptorTrack() with 69 // the same |uuid|. If |parent_uuid| is 0, the track will become a global 70 // track. Otherwise, it will become a new track of the same type as its parent 71 // track. 72 void ReserveDescriptorChildTrack(uint64_t uuid, 73 uint64_t parent_uuid, 74 StringId name); 75 76 // Associate a counter-type TrackDescriptor track identified by the given 77 // |uuid| with a parent track (usually a process or thread track). This is 78 // called during tokenization. If a reservation for the same |uuid| already 79 // exists, will attempt to update it. The provided |category| will be stored 80 // into the track's args. 81 // 82 // If |is_incremental| is true, the counter will only be valid on the packet 83 // sequence identified by |packet_sequence_id|. |unit_multiplier| is an 84 // optional multiplication factor applied to counter values. Values for the 85 // counter will be translated during tokenization via 86 // ConvertToAbsoluteCounterValue(). 87 // 88 // The track will be created upon the first call to GetDescriptorTrack() with 89 // the same |uuid|. If |parent_uuid| is 0, the track will become a global 90 // track. Otherwise, it will become a new counter track for the same 91 // process/thread as its parent track. 92 void ReserveDescriptorCounterTrack(uint64_t uuid, 93 uint64_t parent_uuid, 94 StringId name, 95 StringId category, 96 int64_t unit_multiplier, 97 bool is_incremental, 98 uint32_t packet_sequence_id); 99 100 // Returns the ID of the track for the TrackDescriptor with the given |uuid|. 101 // This is called during parsing. The first call to GetDescriptorTrack() for 102 // each |uuid| resolves and inserts the track (and its parent tracks, 103 // following the parent_uuid chain recursively) based on reservations made for 104 // the |uuid|. If the track is a child track and doesn't have a name yet, 105 // updates the track's name to event_name. Returns std::nullopt if no track 106 // for a descriptor with this |uuid| has been reserved. 107 // TODO(lalitm): this method needs to be split up and moved back to 108 // TrackTracker. 109 std::optional<TrackId> GetDescriptorTrack( 110 uint64_t uuid, 111 StringId event_name = kNullStringId, 112 std::optional<uint32_t> packet_sequence_id = std::nullopt); 113 114 // Converts the given counter value to an absolute value in the unit of the 115 // counter, applying incremental delta encoding or unit multipliers as 116 // necessary. If the counter uses incremental encoding, |packet_sequence_id| 117 // must match the one in its track reservation. Returns std::nullopt if the 118 // counter track is unknown or an invalid |packet_sequence_id| was passed. 119 std::optional<double> ConvertToAbsoluteCounterValue( 120 uint64_t counter_track_uuid, 121 uint32_t packet_sequence_id, 122 double value); 123 124 // Returns the ID of the implicit trace-global default TrackDescriptor track. 125 // TODO(lalitm): this method needs to be moved back to TrackTracker once 126 // GetDescriptorTrack is moved back. 127 TrackId GetOrCreateDefaultDescriptorTrack(); 128 129 // Track events timestamps in Chrome have microsecond resolution, while 130 // system events use nanoseconds. It results in broken event nesting when 131 // track events and system events share a track. 132 // So TrackEventTracker needs to support its own tracks, separate from the 133 // ones in the TrackTracker. 134 TrackId InternThreadTrack(UniqueTid utid); 135 136 // Called by ProtoTraceReader whenever incremental state is cleared on a 137 // packet sequence. Resets counter values for any incremental counters of 138 // the sequence identified by |packet_sequence_id|. 139 void OnIncrementalStateCleared(uint32_t packet_sequence_id); 140 141 void OnFirstPacketOnSequence(uint32_t packet_sequence_id); 142 SetRangeOfInterestStartUs(int64_t range_of_interest_start_us)143 void SetRangeOfInterestStartUs(int64_t range_of_interest_start_us) { 144 range_of_interest_start_us_ = range_of_interest_start_us; 145 } 146 range_of_interest_start_us()147 std::optional<int64_t> range_of_interest_start_us() const { 148 return range_of_interest_start_us_; 149 } 150 151 private: 152 struct DescriptorTrackReservation { 153 uint64_t parent_uuid = 0; 154 std::optional<uint32_t> pid; 155 std::optional<uint32_t> tid; 156 int64_t min_timestamp = 0; // only set if |pid| and/or |tid| is set. 157 StringId name = kNullStringId; 158 bool use_separate_track = false; 159 160 // For counter tracks. 161 bool is_counter = false; 162 StringId category = kNullStringId; 163 int64_t unit_multiplier = 1; 164 bool is_incremental = false; 165 uint32_t packet_sequence_id = 0; 166 double latest_value = 0; 167 168 // Whether |other| is a valid descriptor for this track reservation. A track 169 // should always remain nested underneath its original parent. IsForSameTrackDescriptorTrackReservation170 bool IsForSameTrack(const DescriptorTrackReservation& other) { 171 // Note that |min_timestamp|, |latest_value|, and |name| are ignored for 172 // this comparison. 173 return std::tie(parent_uuid, pid, tid, is_counter, category, 174 unit_multiplier, is_incremental, packet_sequence_id) == 175 std::tie(other.parent_uuid, pid, tid, is_counter, category, 176 unit_multiplier, is_incremental, packet_sequence_id); 177 } 178 }; 179 180 class ResolvedDescriptorTrack { 181 public: 182 enum class Scope { 183 kThread, 184 kProcess, 185 kGlobal, 186 }; 187 188 static ResolvedDescriptorTrack Process(UniquePid upid, 189 bool is_counter, 190 bool is_root); 191 static ResolvedDescriptorTrack Thread(UniqueTid utid, 192 bool is_counter, 193 bool is_root, 194 bool use_separate_track); 195 static ResolvedDescriptorTrack Global(bool is_counter, bool is_root); 196 scope()197 Scope scope() const { return scope_; } is_counter()198 bool is_counter() const { return is_counter_; } utid()199 UniqueTid utid() const { 200 PERFETTO_DCHECK(scope() == Scope::kThread); 201 return utid_; 202 } upid()203 UniquePid upid() const { 204 PERFETTO_DCHECK(scope() == Scope::kProcess); 205 return upid_; 206 } is_root_in_scope()207 UniqueTid is_root_in_scope() const { return is_root_in_scope_; } use_separate_track()208 bool use_separate_track() const { return use_separate_track_; } 209 210 private: 211 Scope scope_; 212 bool is_counter_; 213 bool is_root_in_scope_; 214 bool use_separate_track_; 215 216 // Only set when |scope| == |Scope::kThread|. 217 UniqueTid utid_; 218 219 // Only set when |scope| == |Scope::kProcess|. 220 UniquePid upid_; 221 }; 222 223 std::optional<TrackId> GetDescriptorTrackImpl( 224 uint64_t uuid, 225 std::optional<uint32_t> packet_sequence_id = std::nullopt); 226 TrackId CreateTrackFromResolved(const ResolvedDescriptorTrack&); 227 std::optional<ResolvedDescriptorTrack> ResolveDescriptorTrack( 228 uint64_t uuid, 229 std::vector<uint64_t>* descendent_uuids); 230 std::optional<ResolvedDescriptorTrack> ResolveDescriptorTrackImpl( 231 uint64_t uuid, 232 const DescriptorTrackReservation&, 233 std::vector<uint64_t>* descendent_uuids); 234 TrackId InsertThreadTrack(UniqueTid utid); 235 236 static constexpr uint64_t kDefaultDescriptorTrackUuid = 0u; 237 238 std::map<UniqueTid, TrackId> thread_tracks_; 239 std::map<UniquePid, TrackId> process_tracks_; 240 241 std::map<uint64_t /* uuid */, DescriptorTrackReservation> 242 reserved_descriptor_tracks_; 243 std::map<uint64_t /* uuid */, ResolvedDescriptorTrack> 244 resolved_descriptor_tracks_; 245 std::map<uint64_t /* uuid */, TrackId> descriptor_tracks_; 246 247 // Stores the descriptor uuid used for the primary process/thread track 248 // for the given upid / utid. Used for pid/tid reuse detection. 249 std::map<UniquePid, uint64_t /*uuid*/> descriptor_uuids_by_upid_; 250 std::map<UniqueTid, uint64_t /*uuid*/> descriptor_uuids_by_utid_; 251 252 std::unordered_set<uint32_t> sequences_with_first_packet_; 253 254 const StringId source_key_ = kNullStringId; 255 const StringId source_id_key_ = kNullStringId; 256 const StringId is_root_in_scope_key_ = kNullStringId; 257 const StringId category_key_ = kNullStringId; 258 const StringId has_first_packet_on_sequence_key_id_ = kNullStringId; 259 260 const StringId descriptor_source_ = kNullStringId; 261 262 const StringId default_descriptor_track_name_ = kNullStringId; 263 264 std::optional<int64_t> range_of_interest_start_us_; 265 266 TraceProcessorContext* const context_; 267 }; 268 269 } // namespace trace_processor 270 } // namespace perfetto 271 272 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_TRACKER_H_ 273