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 <cstdint> 21 #include <map> 22 #include <optional> 23 #include <tuple> 24 #include <unordered_set> 25 #include <vector> 26 27 #include "perfetto/base/logging.h" 28 #include "src/trace_processor/importers/common/args_tracker.h" 29 #include "src/trace_processor/storage/trace_storage.h" 30 #include "src/trace_processor/types/trace_processor_context.h" 31 32 namespace perfetto::trace_processor { 33 34 // Tracks and stores tracks based on track types, ids and scopes. 35 class TrackEventTracker { 36 public: 37 // Data from TrackDescriptor proto used to reserve a track before interning it 38 // with |TrackTracker|. 39 struct DescriptorTrackReservation { 40 // Maps to TrackDescriptor::ChildTracksOrdering proto values 41 enum class ChildTracksOrdering { 42 kUnknown = 0, 43 kLexicographic = 1, 44 kChronological = 2, 45 kExplicit = 3, 46 }; 47 struct CounterDetails { 48 StringId category = kNullStringId; 49 int64_t unit_multiplier = 1; 50 bool is_incremental = false; 51 uint32_t packet_sequence_id = 0; 52 double latest_value = 0; 53 StringId unit = kNullStringId; 54 55 bool operator==(const CounterDetails& o) const { 56 return std::tie(category, unit_multiplier, is_incremental, 57 packet_sequence_id, latest_value) == 58 std::tie(o.category, o.unit_multiplier, o.is_incremental, 59 o.packet_sequence_id, o.latest_value); 60 } 61 }; 62 63 uint64_t parent_uuid = 0; 64 std::optional<uint32_t> pid; 65 std::optional<uint32_t> tid; 66 int64_t min_timestamp = 0; // only set if |pid| and/or |tid| is set. 67 StringId name = kNullStringId; 68 bool use_separate_track = false; 69 bool is_counter = false; 70 71 // For counter tracks. 72 std::optional<CounterDetails> counter_details; 73 74 // For UI visualisation 75 ChildTracksOrdering ordering = ChildTracksOrdering::kUnknown; 76 std::optional<int32_t> sibling_order_rank; 77 78 // Whether |other| is a valid descriptor for this track reservation. A track 79 // should always remain nested underneath its original parent. IsForSameTrackDescriptorTrackReservation80 bool IsForSameTrack(const DescriptorTrackReservation& other) { 81 // Note that |min_timestamp|, |latest_value|, and |name| are ignored for 82 // this comparison. 83 return std::tie(parent_uuid, pid, tid, is_counter, counter_details) == 84 std::tie(other.parent_uuid, other.pid, other.tid, other.is_counter, 85 other.counter_details); 86 } 87 }; 88 explicit TrackEventTracker(TraceProcessorContext*); 89 90 // Associate a TrackDescriptor track identified by the given |uuid| with a 91 // given track description. This is called during tokenization. If a 92 // reservation for the same |uuid| already exists, verifies that the present 93 // reservation matches the new one. 94 // 95 // The track will be resolved to the track (see TrackTracker::InternTrack()) 96 // upon the first call to GetDescriptorTrack() with the same |uuid|. At this 97 // time, |pid| will be resolved to a |upid| and |tid| to |utid|. 98 void ReserveDescriptorTrack(uint64_t uuid, const DescriptorTrackReservation&); 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 // Called by ProtoTraceReader whenever incremental state is cleared on a 130 // packet sequence. Resets counter values for any incremental counters of 131 // the sequence identified by |packet_sequence_id|. 132 void OnIncrementalStateCleared(uint32_t packet_sequence_id); 133 134 void OnFirstPacketOnSequence(uint32_t packet_sequence_id); 135 SetRangeOfInterestStartUs(int64_t range_of_interest_start_us)136 void SetRangeOfInterestStartUs(int64_t range_of_interest_start_us) { 137 range_of_interest_start_us_ = range_of_interest_start_us; 138 } 139 range_of_interest_start_us()140 std::optional<int64_t> range_of_interest_start_us() const { 141 return range_of_interest_start_us_; 142 } 143 144 private: 145 class ResolvedDescriptorTrack { 146 public: 147 enum class Scope { 148 kThread, 149 kProcess, 150 kGlobal, 151 }; 152 153 static ResolvedDescriptorTrack Process(UniquePid upid, 154 bool is_counter, 155 bool is_root); 156 static ResolvedDescriptorTrack Thread(UniqueTid utid, 157 bool is_counter, 158 bool is_root, 159 bool use_separate_track); 160 static ResolvedDescriptorTrack Global(bool is_counter, bool is_root); 161 scope()162 Scope scope() const { return scope_; } is_counter()163 bool is_counter() const { return is_counter_; } utid()164 UniqueTid utid() const { 165 PERFETTO_DCHECK(scope() == Scope::kThread); 166 return utid_; 167 } upid()168 UniquePid upid() const { 169 PERFETTO_DCHECK(scope() == Scope::kProcess); 170 return upid_; 171 } is_root_in_scope()172 UniqueTid is_root_in_scope() const { return is_root_in_scope_; } use_separate_track()173 bool use_separate_track() const { return use_separate_track_; } 174 175 private: 176 Scope scope_; 177 bool is_counter_; 178 bool is_root_in_scope_; 179 bool use_separate_track_; 180 181 // Only set when |scope| == |Scope::kThread|. 182 UniqueTid utid_; 183 184 // Only set when |scope| == |Scope::kProcess|. 185 UniquePid upid_; 186 }; 187 188 std::optional<TrackId> GetDescriptorTrackImpl( 189 uint64_t uuid, 190 std::optional<uint32_t> packet_sequence_id = std::nullopt); 191 TrackId CreateTrackFromResolved(uint64_t uuid, 192 std::optional<uint32_t> packet_sequence_id, 193 const DescriptorTrackReservation&, 194 const ResolvedDescriptorTrack&); 195 std::optional<ResolvedDescriptorTrack> ResolveDescriptorTrack( 196 uint64_t uuid, 197 std::vector<uint64_t>* descendent_uuids); 198 std::optional<ResolvedDescriptorTrack> ResolveDescriptorTrackImpl( 199 uint64_t uuid, 200 const DescriptorTrackReservation&, 201 std::vector<uint64_t>* descendent_uuids); 202 203 void AddTrackArgs(uint64_t uuid, 204 std::optional<uint32_t> packet_sequence_id, 205 const DescriptorTrackReservation&, 206 const ResolvedDescriptorTrack&, 207 ArgsTracker::BoundInserter&); 208 209 static constexpr uint64_t kDefaultDescriptorTrackUuid = 0u; 210 211 std::map<UniqueTid, TrackId> thread_tracks_; 212 std::map<UniquePid, TrackId> process_tracks_; 213 214 std::map<uint64_t /* uuid */, DescriptorTrackReservation> 215 reserved_descriptor_tracks_; 216 std::map<uint64_t /* uuid */, ResolvedDescriptorTrack> 217 resolved_descriptor_tracks_; 218 std::map<uint64_t /* uuid */, TrackId> descriptor_tracks_; 219 220 // Stores the descriptor uuid used for the primary process/thread track 221 // for the given upid / utid. Used for pid/tid reuse detection. 222 std::map<UniquePid, uint64_t /*uuid*/> descriptor_uuids_by_upid_; 223 std::map<UniqueTid, uint64_t /*uuid*/> descriptor_uuids_by_utid_; 224 225 std::unordered_set<uint32_t> sequences_with_first_packet_; 226 227 const StringId source_key_; 228 const StringId source_id_key_; 229 const StringId is_root_in_scope_key_; 230 const StringId category_key_; 231 const StringId has_first_packet_on_sequence_key_id_; 232 const StringId child_ordering_key_; 233 const StringId explicit_id_; 234 const StringId lexicographic_id_; 235 const StringId chronological_id_; 236 const StringId sibling_order_rank_key_; 237 238 const StringId descriptor_source_; 239 240 const StringId default_descriptor_track_name_; 241 242 std::optional<int64_t> range_of_interest_start_us_; 243 244 TraceProcessorContext* const context_; 245 }; 246 247 } // namespace perfetto::trace_processor 248 249 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_TRACKER_H_ 250