• 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 INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_INTERNAL_H_
18 #define INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_INTERNAL_H_
19 
20 #include "perfetto/base/flat_set.h"
21 #include "perfetto/protozero/scattered_heap_buffer.h"
22 #include "perfetto/tracing/core/forward_decls.h"
23 #include "perfetto/tracing/data_source.h"
24 #include "perfetto/tracing/debug_annotation.h"
25 #include "perfetto/tracing/trace_writer_base.h"
26 #include "perfetto/tracing/traced_value.h"
27 #include "perfetto/tracing/track.h"
28 #include "protos/perfetto/common/builtin_clock.pbzero.h"
29 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
30 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
31 
32 #include <unordered_map>
33 
34 namespace perfetto {
35 
36 // Represents a point in time for the clock specified by |clock_id|.
37 struct TraceTimestamp {
38   // Clock IDs have the following semantic:
39   // [1, 63]:    Builtin types, see BuiltinClock from
40   //             ../common/builtin_clock.proto.
41   // [64, 127]:  User-defined clocks. These clocks are sequence-scoped. They
42   //             are only valid within the same |trusted_packet_sequence_id|
43   //             (i.e. only for TracePacket(s) emitted by the same TraceWriter
44   //             that emitted the clock snapshot).
45   // [128, MAX]: Reserved for future use. The idea is to allow global clock
46   //             IDs and setting this ID to hash(full_clock_name) & ~127.
47   // Learn more: `clock_snapshot.proto`
48   uint32_t clock_id;
49   uint64_t value;
50 };
51 
52 class EventContext;
53 class TrackEventSessionObserver;
54 struct Category;
55 struct TraceTimestamp;
56 namespace protos {
57 namespace gen {
58 class TrackEventConfig;
59 }  // namespace gen
60 namespace pbzero {
61 class DebugAnnotation;
62 }  // namespace pbzero
63 }  // namespace protos
64 
65 // A callback interface for observing track event tracing sessions starting and
66 // stopping. See TrackEvent::{Add,Remove}SessionObserver. Note that all methods
67 // will be called on an internal Perfetto thread.
68 class PERFETTO_EXPORT_COMPONENT TrackEventSessionObserver {
69  public:
70   virtual ~TrackEventSessionObserver();
71   // Called when a track event tracing session is configured. Note tracing isn't
72   // active yet, so track events emitted here won't be recorded. See
73   // DataSourceBase::OnSetup.
74   virtual void OnSetup(const DataSourceBase::SetupArgs&);
75   // Called when a track event tracing session is started. It is possible to
76   // emit track events from this callback.
77   virtual void OnStart(const DataSourceBase::StartArgs&);
78   // Called when a track event tracing session is stopped. It is still possible
79   // to emit track events from this callback.
80   virtual void OnStop(const DataSourceBase::StopArgs&);
81   // Called when tracing muxer requests to clear incremental state.
82   virtual void WillClearIncrementalState(
83       const DataSourceBase::ClearIncrementalStateArgs&);
84 };
85 
86 // A class that the embedder can store arbitrary data user data per thread.
87 class PERFETTO_EXPORT_COMPONENT TrackEventTlsStateUserData {
88  public:
89   TrackEventTlsStateUserData() = default;
90   // Not clonable.
91   TrackEventTlsStateUserData(const TrackEventTlsStateUserData&) = delete;
92   TrackEventTlsStateUserData& operator=(const TrackEventTlsStateUserData&) =
93       delete;
94 
95   virtual ~TrackEventTlsStateUserData();
96 };
97 
98 namespace internal {
99 class TrackEventCategoryRegistry;
100 
101 class PERFETTO_EXPORT_COMPONENT BaseTrackEventInternedDataIndex {
102  public:
103   virtual ~BaseTrackEventInternedDataIndex();
104 
105 #if PERFETTO_DCHECK_IS_ON()
106   const char* type_id_ = nullptr;
107   const void* add_function_ptr_ = nullptr;
108 #endif  // PERFETTO_DCHECK_IS_ON()
109 };
110 
111 struct TrackEventTlsState {
112   template <typename TraceContext>
113   explicit TrackEventTlsState(const TraceContext& trace_context);
114   bool enable_thread_time_sampling = false;
115   bool filter_debug_annotations = false;
116   bool filter_dynamic_event_names = false;
117   uint64_t timestamp_unit_multiplier = 1;
118   uint32_t default_clock;
119   std::map<const void*, std::unique_ptr<TrackEventTlsStateUserData>> user_data;
120 };
121 
122 struct TrackEventIncrementalState {
123   static constexpr size_t kMaxInternedDataFields = 32;
124 
125   // Packet-sequence-scoped clock that encodes nanosecond timestamps in the
126   // domain of the clock returned by GetClockId() as delta values - see
127   // Clock::is_incremental in perfetto/trace/clock_snapshot.proto.
128   // Default unit: nanoseconds.
129   static constexpr uint32_t kClockIdIncremental = 64;
130 
131   // Packet-sequence-scoped clock that encodes timestamps in the domain of the
132   // clock returned by GetClockId() with custom unit_multiplier.
133   // Default unit: nanoseconds.
134   static constexpr uint32_t kClockIdAbsolute = 65;
135 
136   bool was_cleared = true;
137 
138   // A heap-allocated message for storing newly seen interned data while we are
139   // in the middle of writing a track event. When a track event wants to write
140   // new interned data into the trace, it is first serialized into this message
141   // and then flushed to the real trace in EventContext when the packet ends.
142   // The message is cached here as a part of incremental state so that we can
143   // reuse the underlying buffer allocation for subsequently written interned
144   // data.
145   protozero::HeapBuffered<protos::pbzero::InternedData>
146       serialized_interned_data;
147 
148   // In-memory indices for looking up interned data ids.
149   // For each intern-able field (up to a max of 32) we keep a dictionary of
150   // field-value -> interning-key. Depending on the type we either keep the full
151   // value or a hash of it (See track_event_interned_data_index.h)
152   using InternedDataIndex =
153       std::pair</* interned_data.proto field number */ size_t,
154                 std::unique_ptr<BaseTrackEventInternedDataIndex>>;
155   std::array<InternedDataIndex, kMaxInternedDataFields> interned_data_indices =
156       {};
157 
158   // Track uuids for which we have written descriptors into the trace. If a
159   // trace event uses a track which is not in this set, we'll write out a
160   // descriptor for it.
161   base::FlatSet<uint64_t> seen_tracks;
162 
163   // Dynamically registered category names that have been encountered during
164   // this tracing session. The value in the map indicates whether the category
165   // is enabled or disabled.
166   std::unordered_map<std::string, bool> dynamic_categories;
167 
168   // The latest reference timestamp that was used in a TracePacket or in a
169   // ClockSnapshot. The increment between this timestamp and the current trace
170   // time (GetTimeNs) is a value in kClockIdIncremental's domain.
171   uint64_t last_timestamp_ns = 0;
172 
173   // The latest known counter values that was used in a TracePacket for each
174   // counter track. The key (uint64_t) is the uuid of counter track.
175   // The value is used for delta encoding of counter values.
176   std::unordered_map<uint64_t, int64_t> last_counter_value_per_track;
177   int64_t last_thread_time_ns = 0;
178 };
179 
180 // The backend portion of the track event trace point implemention. Outlined to
181 // a separate .cc file so it can be shared by different track event category
182 // namespaces.
183 class PERFETTO_EXPORT_COMPONENT TrackEventInternal {
184  public:
185   static bool Initialize(
186       const TrackEventCategoryRegistry&,
187       bool (*register_data_source)(const DataSourceDescriptor&));
188 
189   static bool AddSessionObserver(const TrackEventCategoryRegistry&,
190                                  TrackEventSessionObserver*);
191   static void RemoveSessionObserver(const TrackEventCategoryRegistry&,
192                                     TrackEventSessionObserver*);
193 
194   static void EnableTracing(const TrackEventCategoryRegistry& registry,
195                             const protos::gen::TrackEventConfig& config,
196                             const DataSourceBase::SetupArgs&);
197   static void OnStart(const TrackEventCategoryRegistry&,
198                       const DataSourceBase::StartArgs&);
199   static void OnStop(const TrackEventCategoryRegistry&,
200                      const DataSourceBase::StopArgs&);
201   static void DisableTracing(const TrackEventCategoryRegistry& registry,
202                              uint32_t internal_instance_index);
203   static void WillClearIncrementalState(
204       const TrackEventCategoryRegistry&,
205       const DataSourceBase::ClearIncrementalStateArgs&);
206 
207   static bool IsCategoryEnabled(const TrackEventCategoryRegistry& registry,
208                                 const protos::gen::TrackEventConfig& config,
209                                 const Category& category);
210 
211   static void WriteEventName(perfetto::DynamicString event_name,
212                              perfetto::EventContext& event_ctx,
213                              const TrackEventTlsState&);
214 
215   static void WriteEventName(perfetto::StaticString event_name,
216                              perfetto::EventContext& event_ctx,
217                              const TrackEventTlsState&);
218 
219   static perfetto::EventContext WriteEvent(
220       TraceWriterBase*,
221       TrackEventIncrementalState*,
222       TrackEventTlsState& tls_state,
223       const Category* category,
224       perfetto::protos::pbzero::TrackEvent::Type,
225       const TraceTimestamp& timestamp,
226       bool on_current_thread_track);
227 
ResetIncrementalStateIfRequired(TraceWriterBase * trace_writer,TrackEventIncrementalState * incr_state,const TrackEventTlsState & tls_state,const TraceTimestamp & timestamp)228   static void ResetIncrementalStateIfRequired(
229       TraceWriterBase* trace_writer,
230       TrackEventIncrementalState* incr_state,
231       const TrackEventTlsState& tls_state,
232       const TraceTimestamp& timestamp) {
233     if (incr_state->was_cleared) {
234       incr_state->was_cleared = false;
235       ResetIncrementalState(trace_writer, incr_state, tls_state, timestamp);
236     }
237   }
238 
239   // TODO(altimin): Remove this method once Chrome uses
240   // EventContext::AddDebugAnnotation directly.
241   template <typename NameType, typename ValueType>
AddDebugAnnotation(perfetto::EventContext * event_ctx,NameType && name,ValueType && value)242   static void AddDebugAnnotation(perfetto::EventContext* event_ctx,
243                                  NameType&& name,
244                                  ValueType&& value) {
245     auto annotation =
246         AddDebugAnnotation(event_ctx, std::forward<NameType>(name));
247     WriteIntoTracedValue(
248         internal::CreateTracedValueFromProto(annotation, event_ctx),
249         std::forward<ValueType>(value));
250   }
251 
252   // If the given track hasn't been seen by the trace writer yet, write a
253   // descriptor for it into the trace. Doesn't take a lock unless the track
254   // descriptor is new.
255   template <typename TrackType>
WriteTrackDescriptorIfNeeded(const TrackType & track,TraceWriterBase * trace_writer,TrackEventIncrementalState * incr_state,const TrackEventTlsState & tls_state,const TraceTimestamp & timestamp)256   static void WriteTrackDescriptorIfNeeded(
257       const TrackType& track,
258       TraceWriterBase* trace_writer,
259       TrackEventIncrementalState* incr_state,
260       const TrackEventTlsState& tls_state,
261       const TraceTimestamp& timestamp) {
262     uint64_t uuid = track.uuid;
263     if (uuid) {
264       auto it_and_inserted = incr_state->seen_tracks.insert(uuid);
265       if (PERFETTO_LIKELY(!it_and_inserted.second))
266         return;
267       uuid = WriteTrackDescriptor(track, trace_writer, incr_state, tls_state,
268                                   timestamp);
269     }
270     while (uuid) {
271       auto it_and_inserted = incr_state->seen_tracks.insert(uuid);
272       if (PERFETTO_LIKELY(!it_and_inserted.second))
273         return;
274       std::optional<TrackRegistry::TrackInfo> track_info =
275           TrackRegistry::Get()->FindTrackInfo(uuid);
276       if (!track_info) {
277         return;
278       }
279       TrackRegistry::WriteTrackDescriptor(
280           std::move(track_info->desc),
281           NewTracePacket(trace_writer, incr_state, tls_state, timestamp));
282       uuid = track_info->parent_uuid;
283     }
284   }
285 
286   // Unconditionally write a track descriptor into the trace.
287   //
288   // Returns the parent track uuid.
289   template <typename TrackType>
WriteTrackDescriptor(const TrackType & track,TraceWriterBase * trace_writer,TrackEventIncrementalState * incr_state,const TrackEventTlsState & tls_state,const TraceTimestamp & timestamp)290   static uint64_t WriteTrackDescriptor(const TrackType& track,
291                                        TraceWriterBase* trace_writer,
292                                        TrackEventIncrementalState* incr_state,
293                                        const TrackEventTlsState& tls_state,
294                                        const TraceTimestamp& timestamp) {
295     ResetIncrementalStateIfRequired(trace_writer, incr_state, tls_state,
296                                     timestamp);
297     return TrackRegistry::Get()->SerializeTrack(
298         track, NewTracePacket(trace_writer, incr_state, tls_state, timestamp));
299   }
300 
301   // Get the current time in nanoseconds in the trace clock timebase.
302   static uint64_t GetTimeNs();
303 
304   static TraceTimestamp GetTraceTime();
305 
GetClockId()306   static inline protos::pbzero::BuiltinClock GetClockId() { return clock_; }
SetClockId(protos::pbzero::BuiltinClock clock)307   static inline void SetClockId(protos::pbzero::BuiltinClock clock) {
308     clock_ = clock;
309   }
310 
GetDisallowMergingWithSystemTracks()311   static inline bool GetDisallowMergingWithSystemTracks() {
312     return disallow_merging_with_system_tracks_;
313   }
SetDisallowMergingWithSystemTracks(bool disallow_merging_with_system_tracks)314   static inline void SetDisallowMergingWithSystemTracks(
315       bool disallow_merging_with_system_tracks) {
316     disallow_merging_with_system_tracks_ = disallow_merging_with_system_tracks;
317   }
318 
319   static int GetSessionCount();
320 
321   // Represents the default track for the calling thread.
322   static const Track kDefaultTrack;
323 
324  private:
325   static void ResetIncrementalState(TraceWriterBase* trace_writer,
326                                     TrackEventIncrementalState* incr_state,
327                                     const TrackEventTlsState& tls_state,
328                                     const TraceTimestamp& timestamp);
329 
330   static protozero::MessageHandle<protos::pbzero::TracePacket> NewTracePacket(
331       TraceWriterBase*,
332       TrackEventIncrementalState*,
333       const TrackEventTlsState& tls_state,
334       TraceTimestamp,
335       uint32_t seq_flags =
336           protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
337 
338   static protos::pbzero::DebugAnnotation* AddDebugAnnotation(
339       perfetto::EventContext*,
340       const char* name);
341 
342   static protos::pbzero::DebugAnnotation* AddDebugAnnotation(
343       perfetto::EventContext*,
344       perfetto::DynamicString name);
345 
346   static std::atomic<int> session_count_;
347 
348   static protos::pbzero::BuiltinClock clock_;
349   static bool disallow_merging_with_system_tracks_;
350 };
351 
352 template <typename TraceContext>
TrackEventTlsState(const TraceContext & trace_context)353 TrackEventTlsState::TrackEventTlsState(const TraceContext& trace_context) {
354   auto locked_ds = trace_context.GetDataSourceLocked();
355   bool disable_incremental_timestamps = false;
356   if (locked_ds.valid()) {
357     const auto& config = locked_ds->GetConfig();
358     disable_incremental_timestamps = config.disable_incremental_timestamps();
359     filter_debug_annotations = config.filter_debug_annotations();
360     filter_dynamic_event_names = config.filter_dynamic_event_names();
361     enable_thread_time_sampling = config.enable_thread_time_sampling();
362     if (config.has_timestamp_unit_multiplier()) {
363       timestamp_unit_multiplier = config.timestamp_unit_multiplier();
364     }
365   }
366   if (disable_incremental_timestamps) {
367     if (timestamp_unit_multiplier == 1) {
368       default_clock = static_cast<uint32_t>(TrackEventInternal::GetClockId());
369     } else {
370       default_clock = TrackEventIncrementalState::kClockIdAbsolute;
371     }
372   } else {
373     default_clock = TrackEventIncrementalState::kClockIdIncremental;
374   }
375 }
376 
377 }  // namespace internal
378 }  // namespace perfetto
379 
380 #endif  // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_INTERNAL_H_
381