• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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_COMMON_TRACK_TRACKER_H_
18 #define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_TRACK_TRACKER_H_
19 
20 #include <array>
21 #include <cstddef>
22 #include <cstdint>
23 #include <functional>
24 #include <tuple>
25 #include <type_traits>
26 #include <utility>
27 
28 #include "perfetto/base/compiler.h"
29 #include "perfetto/ext/base/flat_hash_map.h"
30 #include "perfetto/ext/base/hash.h"
31 #include "perfetto/ext/base/string_view.h"
32 #include "perfetto/public/compiler.h"
33 #include "src/trace_processor/importers/common/args_tracker.h"
34 #include "src/trace_processor/importers/common/global_args_tracker.h"
35 #include "src/trace_processor/importers/common/tracks.h"
36 #include "src/trace_processor/importers/common/tracks_common.h"
37 #include "src/trace_processor/importers/common/tracks_internal.h"
38 #include "src/trace_processor/storage/trace_storage.h"
39 #include "src/trace_processor/tables/track_tables_py.h"
40 #include "src/trace_processor/types/trace_processor_context.h"
41 #include "src/trace_processor/types/variadic.h"
42 
43 namespace perfetto::trace_processor {
44 
45 // Tracks and stores tracks based on track types, ids and scopes.
46 class TrackTracker {
47  public:
48   using SetArgsCallback = std::function<void(ArgsTracker::BoundInserter&)>;
49 
50   explicit TrackTracker(TraceProcessorContext*);
51 
52   // Given a blueprint (i.e. the schema of a track), and the dimensions checks
53   // whether the track has been seen before and if so, returns the id of the
54   // seen track.
55   //
56   // If the track was *not* seen before, creates an entry in the track table
57   // and returns the id.
58   //
59   // Usage (for slice tracks):
60   //   ```
61   //   void ParseMySpecialThreadScopedSlice(UniqueTid utid, ...(other args)) {
62   //     static constexpr auto kBlueprint = tracks::SliceBlueprint(
63   //       // The type of the track.
64   //       "my_special_thread_scoped_slice",
65   //       // The dimensions of the track. Can be >1 if the track is broken down
66   //       // by multiple fields.
67   //       tracks::DimensionBlueprints(tracks::kThreadDimension)
68   //     );
69   //     TrackId track_id = track_tracker_->InternTrack(
70   //         kBlueprint, tracks::Dimensions(utid));
71   //
72   //     ... add slices using SliceTracker
73   //   }
74   //   ```
75   //
76   // Usage (for counter tracks):
77   //   ```
78   //   void ParseMySpecialCustomScopedCounter(uint32_t custom_scope,
79   //                                          ... other args) {
80   //     static constexpr auto kBlueprint = tracks::CounterBlueprint(
81   //       // The type of the track.
82   //       "my_special_custom_scoped_counter",
83   //       // The dimensions of the track. Can be >1 if the track is broken down
84   //       // by multiple fields.
85   //       tracks::DimensionBlueprints(
86   //           tracks::UnitDimensionBlueprint("custom_scope"))
87   //     );
88   //     TrackId track_id = track_tracker_->InternTrack(
89   //         kBlueprint, tracks::Dimensions(custom_scope));
90   //
91   //     ... add counters using EventTracker
92   //   }
93   //   ```
94   //
95   // Note: when using this function, always try and check the blueprints in
96   // `tracks_common.h` to see if there is a blueprint there which already does
97   // what you need.
98   template <typename BlueprintT>
99   PERFETTO_ALWAYS_INLINE TrackId InternTrack(
100       const BlueprintT& bp,
101       const typename BlueprintT::dimensions_t& dims = {},
102       const typename BlueprintT::name_t& name = tracks::BlueprintName(),
103       const SetArgsCallback& args = {},
104       const typename BlueprintT::unit_t& unit = tracks::BlueprintUnit()) {
105     return InternTrackInner(bp, dims, name, args, unit).first;
106   }
107 
108   // Wrapper function for `InternTrack` in cases where you want the "main"
109   // slice track for the thread.
110   //
111   // This function should be used in situations where the thread cannot be
112   // executing anything else while the slice is active. It should *not* be used
113   // in cases where the function could overlap; use InternTrack directly with a
114   // custom blueprint.
InternThreadTrack(UniqueTid utid)115   TrackId InternThreadTrack(UniqueTid utid) {
116     static constexpr auto kBlueprint = tracks::SliceBlueprint(
117         "thread_execution",
118         tracks::DimensionBlueprints(tracks::kThreadDimensionBlueprint));
119     return InternTrack(kBlueprint, tracks::Dimensions(utid));
120   }
121 
122   // Wrapper function for `InternTrack` for legacy "async" style tracks which
123   // is supported by the Chrome JSON format and other derivative formats
124   // (e.g. Fuchsia).
125   //
126   // WARNING: this function should *not* be used by any users not explicitly
127   // approved and discussed with a trace processor maintainer.
128   TrackId InternLegacyAsyncTrack(StringId name,
129                                  uint32_t upid,
130                                  int64_t trace_id,
131                                  bool trace_id_is_process_scoped,
132                                  StringId source_scope);
133 
134  private:
135   friend class TrackCompressor;
136   friend class TrackEventTracker;
137 
138   TrackId AddTrack(const tracks::BlueprintBase&,
139                    StringId,
140                    StringId,
141                    GlobalArgsTracker::CompactArg*,
142                    uint32_t,
143                    const SetArgsCallback&);
144 
145   template <typename BlueprintT>
146   PERFETTO_ALWAYS_INLINE std::pair<TrackId, bool> InternTrackInner(
147       const BlueprintT& bp,
148       const typename BlueprintT::dimensions_t& dims = {},
149       const typename BlueprintT::name_t& name = tracks::BlueprintName(),
150       const SetArgsCallback& args = {},
151       const typename BlueprintT::unit_t& unit = tracks::BlueprintUnit()) {
152     uint64_t hash = tracks::HashFromBlueprintAndDimensions(bp, dims);
153     auto [it, inserted] = tracks_.Insert(hash, {});
154     if (inserted) {
155       std::array<GlobalArgsTracker::CompactArg, 8> a;
156       DimensionsToArgs<0>(dims, bp.dimension_blueprints.data(), a.data());
157       StringId n;
158       using NBT = tracks::NameBlueprintT;
159       using name_blueprint_t = typename BlueprintT::name_blueprint_t;
160       if constexpr (std::is_same_v<NBT::Auto, name_blueprint_t>) {
161         n = kNullStringId;
162       } else if constexpr (std::is_same_v<NBT::Static, name_blueprint_t>) {
163         n = context_->storage->InternString(bp.name_blueprint.name);
164       } else if constexpr (std::is_base_of_v<NBT::FnBase, name_blueprint_t>) {
165         n = context_->storage->InternString(
166             std::apply(bp.name_blueprint.fn, dims).string_view());
167       } else {
168         static_assert(std::is_same_v<NBT::Dynamic, name_blueprint_t>);
169         n = name;
170       }
171       using UBT = tracks::UnitBlueprintT;
172       using unit_blueprint_t = typename BlueprintT::unit_blueprint_t;
173       StringId u;
174       if constexpr (std::is_same_v<UBT::Unknown, unit_blueprint_t>) {
175         u = kNullStringId;
176       } else if constexpr (std::is_same_v<UBT::Static, unit_blueprint_t>) {
177         u = context_->storage->InternString(bp.unit_blueprint.name);
178       } else {
179         static_assert(std::is_same_v<UBT::Dynamic, unit_blueprint_t>);
180         u = unit;
181       }
182       // GCC warns about the variables being unused even they are in certain
183       // constexpr branches above. Just use them here to suppress the warning.
184       base::ignore_result(name, unit);
185       static constexpr uint32_t kDimensionCount =
186           std::tuple_size_v<typename BlueprintT::dimensions_t>;
187       *it = AddTrack(bp, n, u, a.data(), kDimensionCount, args);
188     }
189     return std::make_pair(*it, inserted);
190   }
191 
192   template <size_t i, typename TupleDimensions>
DimensionsToArgs(const TupleDimensions & dimensions,const tracks::DimensionBlueprintBase * dimensions_schema,GlobalArgsTracker::CompactArg * a)193   void DimensionsToArgs(const TupleDimensions& dimensions,
194                         const tracks::DimensionBlueprintBase* dimensions_schema,
195                         GlobalArgsTracker::CompactArg* a) {
196     static constexpr size_t kTupleSize = std::tuple_size_v<TupleDimensions>;
197     if constexpr (i < kTupleSize) {
198       using elem_t = std::tuple_element_t<i, TupleDimensions>;
199       if constexpr (std::is_same_v<elem_t, uint32_t>) {
200         a[i].value = Variadic::Integer(std::get<i>(dimensions));
201       } else if constexpr (std::is_integral_v<elem_t>) {
202         a[i].value = Variadic::Integer(std::get<i>(dimensions));
203       } else {
204         static_assert(std::is_same_v<elem_t, base::StringView>,
205                       "Unknown type for dimension");
206         a[i].value = Variadic::String(
207             context_->storage->InternString(std::get<i>(dimensions)));
208       }
209       DimensionsToArgs<i + 1>(dimensions, dimensions_schema, a);
210     }
211     // Required for GCC to not complain.
212     base::ignore_result(dimensions_schema);
213   }
214 
215   base::FlatHashMap<uint64_t, TrackId, base::AlreadyHashed<uint64_t>> tracks_;
216 
217   const StringId source_key_;
218   const StringId trace_id_key_;
219   const StringId trace_id_is_process_scoped_key_;
220   const StringId upid_;
221   const StringId source_scope_key_;
222   const StringId chrome_source_;
223 
224   TraceProcessorContext* const context_;
225   ArgsTracker args_tracker_;
226 };
227 
228 }  // namespace perfetto::trace_processor
229 
230 #endif  // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_TRACK_TRACKER_H_
231