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 <optional> 22 #include <tuple> 23 #include <unordered_set> 24 25 #include "perfetto/base/logging.h" 26 #include "perfetto/ext/base/flat_hash_map.h" 27 #include "protos/perfetto/trace/track_event/counter_descriptor.pbzero.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 static constexpr uint64_t kDefaultDescriptorTrackUuid = 0u; 38 39 // Data from TrackDescriptor proto used to reserve a track before interning it 40 // with |TrackTracker|. 41 struct DescriptorTrackReservation { 42 // Maps to TrackDescriptor::ChildTracksOrdering proto values 43 enum class ChildTracksOrdering { 44 kUnknown = 0, 45 kLexicographic = 1, 46 kChronological = 2, 47 kExplicit = 3, 48 }; 49 struct CounterDetails { 50 StringId category = kNullStringId; 51 int64_t unit_multiplier = 1; 52 bool is_incremental = false; 53 uint32_t packet_sequence_id = 0; 54 double latest_value = 0; 55 StringId unit = kNullStringId; 56 StringId builtin_type_str; 57 IsForSameTrackDescriptorTrackReservation::CounterDetails58 bool IsForSameTrack(const CounterDetails& o) const { 59 return std::tie(category, unit_multiplier, is_incremental, 60 packet_sequence_id, builtin_type_str) == 61 std::tie(o.category, o.unit_multiplier, o.is_incremental, 62 o.packet_sequence_id, o.builtin_type_str); 63 } 64 }; 65 66 uint64_t parent_uuid = 0; 67 std::optional<uint32_t> pid; 68 std::optional<uint32_t> tid; 69 int64_t min_timestamp = 0; 70 StringId name = kNullStringId; 71 bool use_separate_track = false; 72 bool is_counter = false; 73 74 // For counter tracks. 75 std::optional<CounterDetails> counter_details; 76 77 // For UI visualisation 78 ChildTracksOrdering ordering = ChildTracksOrdering::kUnknown; 79 std::optional<int32_t> sibling_order_rank; 80 81 // Whether |other| is a valid descriptor for this track reservation. A track 82 // should always remain nested underneath its original parent. IsForSameTrackDescriptorTrackReservation83 bool IsForSameTrack(const DescriptorTrackReservation& other) { 84 if (counter_details.has_value() != other.counter_details.has_value()) { 85 return false; 86 } 87 if (counter_details && 88 !counter_details->IsForSameTrack(*other.counter_details)) { 89 return false; 90 } 91 return std::tie(parent_uuid, pid, tid, is_counter) == 92 std::tie(other.parent_uuid, other.pid, other.tid, 93 other.is_counter); 94 } 95 }; 96 explicit TrackEventTracker(TraceProcessorContext*); 97 98 // Associate a TrackDescriptor track identified by the given |uuid| with a 99 // given track description. This is called during tokenization. If a 100 // reservation for the same |uuid| already exists, verifies that the present 101 // reservation matches the new one. 102 // 103 // The track will be resolved to the track (see TrackTracker::InternTrack()) 104 // upon the first call to GetDescriptorTrack() with the same |uuid|. At this 105 // time, |pid| will be resolved to a |upid| and |tid| to |utid|. 106 void ReserveDescriptorTrack(uint64_t uuid, const DescriptorTrackReservation&); 107 108 // Returns the ID of the track for the TrackDescriptor with the given |uuid|. 109 // This is called during parsing. The first call to GetDescriptorTrack() for 110 // each |uuid| resolves and inserts the track (and its parent tracks, 111 // following the parent_uuid chain recursively) based on reservations made for 112 // the |uuid|. If the track is a child track and doesn't have a name yet, 113 // updates the track's name to event_name. Returns std::nullopt if no track 114 // for a descriptor with this |uuid| has been reserved. 115 std::optional<TrackId> GetDescriptorTrack( 116 uint64_t uuid, 117 StringId event_name = kNullStringId, 118 std::optional<uint32_t> packet_sequence_id = std::nullopt) { 119 auto res = GetDescriptorTrackImpl(uuid, event_name, packet_sequence_id); 120 if (!res) { 121 return std::nullopt; 122 } 123 return res->track_id(); 124 } 125 126 // Converts the given counter value to an absolute value in the unit of the 127 // counter, applying incremental delta encoding or unit multipliers as 128 // necessary. If the counter uses incremental encoding, |packet_sequence_id| 129 // must match the one in its track reservation. Returns std::nullopt if the 130 // counter track is unknown or an invalid |packet_sequence_id| was passed. 131 std::optional<double> ConvertToAbsoluteCounterValue( 132 uint64_t counter_track_uuid, 133 uint32_t packet_sequence_id, 134 double value); 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 range_of_interest_start_us()143 std::optional<int64_t> range_of_interest_start_us() const { 144 return range_of_interest_start_us_; 145 } 146 set_range_of_interest_us(int64_t range_of_interest_start_us)147 void set_range_of_interest_us(int64_t range_of_interest_start_us) { 148 range_of_interest_start_us_ = range_of_interest_start_us; 149 } 150 151 private: 152 class ResolvedDescriptorTrack { 153 public: 154 enum class Scope { 155 kThread, 156 kProcess, 157 kGlobal, 158 }; 159 160 static ResolvedDescriptorTrack Process(TrackId, 161 UniquePid upid, 162 bool is_counter, 163 bool is_root); 164 static ResolvedDescriptorTrack Thread(TrackId, 165 UniqueTid utid, 166 bool is_counter, 167 bool is_root); 168 static ResolvedDescriptorTrack Global(TrackId, bool is_counter); 169 track_id()170 TrackId track_id() const { return track_id_; } scope()171 Scope scope() const { return scope_; } is_counter()172 bool is_counter() const { return is_counter_; } utid()173 UniqueTid utid() const { 174 PERFETTO_DCHECK(scope() == Scope::kThread); 175 return utid_; 176 } upid()177 UniquePid upid() const { 178 PERFETTO_DCHECK(scope() == Scope::kProcess); 179 return upid_; 180 } is_root()181 bool is_root() const { return is_root_; } 182 183 private: 184 TrackId track_id_; 185 Scope scope_; 186 bool is_counter_; 187 bool is_root_; 188 189 // Only set when |scope| == |Scope::kThread|. 190 UniqueTid utid_; 191 192 // Only set when |scope| == |Scope::kProcess|. 193 UniquePid upid_; 194 }; 195 196 std::optional<ResolvedDescriptorTrack> GetDescriptorTrackImpl( 197 uint64_t uuid, 198 StringId event_name, 199 std::optional<uint32_t> packet_sequence_id); 200 201 ResolvedDescriptorTrack ResolveDescriptorTrack( 202 uint64_t uuid, 203 const DescriptorTrackReservation& reservation, 204 std::optional<uint32_t> packet_sequence_id); 205 206 bool IsTrackHierarchyValid(uint64_t uuid); 207 208 void AddTrackArgs(uint64_t uuid, 209 std::optional<uint32_t> packet_sequence_id, 210 const DescriptorTrackReservation&, 211 bool, 212 ArgsTracker::BoundInserter&); 213 214 base::FlatHashMap<uint64_t /* uuid */, DescriptorTrackReservation> 215 reserved_descriptor_tracks_; 216 base::FlatHashMap<uint64_t /* uuid */, ResolvedDescriptorTrack> 217 resolved_descriptor_tracks_; 218 219 // Stores the descriptor uuid used for the primary process/thread track 220 // for the given upid / utid. Used for pid/tid reuse detection. 221 base::FlatHashMap<UniquePid, uint64_t /*uuid*/> descriptor_uuids_by_upid_; 222 base::FlatHashMap<UniqueTid, uint64_t /*uuid*/> descriptor_uuids_by_utid_; 223 224 std::unordered_set<uint32_t> sequences_with_first_packet_; 225 226 const StringId source_key_; 227 const StringId source_id_key_; 228 const StringId is_root_in_scope_key_; 229 const StringId category_key_; 230 const StringId builtin_counter_type_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 const StringId descriptor_source_; 238 const StringId default_descriptor_track_name_; 239 240 std::optional<int64_t> range_of_interest_start_us_; 241 TraceProcessorContext* const context_; 242 }; 243 244 } // namespace perfetto::trace_processor 245 246 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_TRACKER_H_ 247