• 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 namespace internal {
87 class TrackEventCategoryRegistry;
88 
89 class PERFETTO_EXPORT_COMPONENT BaseTrackEventInternedDataIndex {
90  public:
91   virtual ~BaseTrackEventInternedDataIndex();
92 
93 #if PERFETTO_DCHECK_IS_ON()
94   const char* type_id_ = nullptr;
95   const void* add_function_ptr_ = nullptr;
96 #endif  // PERFETTO_DCHECK_IS_ON()
97 };
98 
99 struct TrackEventTlsState {
100   template <typename TraceContext>
101   explicit TrackEventTlsState(const TraceContext& trace_context);
102   bool enable_thread_time_sampling = false;
103   bool filter_debug_annotations = false;
104   bool filter_dynamic_event_names = false;
105   uint64_t timestamp_unit_multiplier = 1;
106   uint32_t default_clock;
107 };
108 
109 struct TrackEventIncrementalState {
110   static constexpr size_t kMaxInternedDataFields = 32;
111 
112   // Packet-sequence-scoped clock that encodes nanosecond timestamps in the
113   // domain of the clock returned by GetClockId() as delta values - see
114   // Clock::is_incremental in perfetto/trace/clock_snapshot.proto.
115   // Default unit: nanoseconds.
116   static constexpr uint32_t kClockIdIncremental = 64;
117 
118   // Packet-sequence-scoped clock that encodes timestamps in the domain of the
119   // clock returned by GetClockId() with custom unit_multiplier.
120   // Default unit: nanoseconds.
121   static constexpr uint32_t kClockIdAbsolute = 65;
122 
123   bool was_cleared = true;
124 
125   // A heap-allocated message for storing newly seen interned data while we are
126   // in the middle of writing a track event. When a track event wants to write
127   // new interned data into the trace, it is first serialized into this message
128   // and then flushed to the real trace in EventContext when the packet ends.
129   // The message is cached here as a part of incremental state so that we can
130   // reuse the underlying buffer allocation for subsequently written interned
131   // data.
132   protozero::HeapBuffered<protos::pbzero::InternedData>
133       serialized_interned_data;
134 
135   // In-memory indices for looking up interned data ids.
136   // For each intern-able field (up to a max of 32) we keep a dictionary of
137   // field-value -> interning-key. Depending on the type we either keep the full
138   // value or a hash of it (See track_event_interned_data_index.h)
139   using InternedDataIndex =
140       std::pair</* interned_data.proto field number */ size_t,
141                 std::unique_ptr<BaseTrackEventInternedDataIndex>>;
142   std::array<InternedDataIndex, kMaxInternedDataFields> interned_data_indices =
143       {};
144 
145   // Track uuids for which we have written descriptors into the trace. If a
146   // trace event uses a track which is not in this set, we'll write out a
147   // descriptor for it.
148   base::FlatSet<uint64_t> seen_tracks;
149 
150   // Dynamically registered category names that have been encountered during
151   // this tracing session. The value in the map indicates whether the category
152   // is enabled or disabled.
153   std::unordered_map<std::string, bool> dynamic_categories;
154 
155   // The latest reference timestamp that was used in a TracePacket or in a
156   // ClockSnapshot. The increment between this timestamp and the current trace
157   // time (GetTimeNs) is a value in kClockIdIncremental's domain.
158   uint64_t last_timestamp_ns = 0;
159 
160   // The latest known counter values that was used in a TracePacket for each
161   // counter track. The key (uint64_t) is the uuid of counter track.
162   // The value is used for delta encoding of counter values.
163   std::unordered_map<uint64_t, int64_t> last_counter_value_per_track;
164   int64_t last_thread_time_ns = 0;
165 };
166 
167 // The backend portion of the track event trace point implemention. Outlined to
168 // a separate .cc file so it can be shared by different track event category
169 // namespaces.
170 class PERFETTO_EXPORT_COMPONENT TrackEventInternal {
171  public:
172   static bool Initialize(
173       const TrackEventCategoryRegistry&,
174       bool (*register_data_source)(const DataSourceDescriptor&));
175 
176   static bool AddSessionObserver(const TrackEventCategoryRegistry&,
177                                  TrackEventSessionObserver*);
178   static void RemoveSessionObserver(const TrackEventCategoryRegistry&,
179                                     TrackEventSessionObserver*);
180 
181   static void EnableTracing(const TrackEventCategoryRegistry& registry,
182                             const protos::gen::TrackEventConfig& config,
183                             const DataSourceBase::SetupArgs&);
184   static void OnStart(const TrackEventCategoryRegistry&,
185                       const DataSourceBase::StartArgs&);
186   static void OnStop(const TrackEventCategoryRegistry&,
187                      const DataSourceBase::StopArgs&);
188   static void DisableTracing(const TrackEventCategoryRegistry& registry,
189                              uint32_t internal_instance_index);
190   static void WillClearIncrementalState(
191       const TrackEventCategoryRegistry&,
192       const DataSourceBase::ClearIncrementalStateArgs&);
193 
194   static bool IsCategoryEnabled(const TrackEventCategoryRegistry& registry,
195                                 const protos::gen::TrackEventConfig& config,
196                                 const Category& category);
197 
198   static void WriteEventName(perfetto::DynamicString event_name,
199                              perfetto::EventContext& event_ctx,
200                              const TrackEventTlsState&);
201 
202   static void WriteEventName(perfetto::StaticString event_name,
203                              perfetto::EventContext& event_ctx,
204                              const TrackEventTlsState&);
205 
206   static perfetto::EventContext WriteEvent(
207       TraceWriterBase*,
208       TrackEventIncrementalState*,
209       const TrackEventTlsState& tls_state,
210       const Category* category,
211       perfetto::protos::pbzero::TrackEvent::Type,
212       const TraceTimestamp& timestamp,
213       bool on_current_thread_track);
214 
ResetIncrementalStateIfRequired(TraceWriterBase * trace_writer,TrackEventIncrementalState * incr_state,const TrackEventTlsState & tls_state,const TraceTimestamp & timestamp)215   static void ResetIncrementalStateIfRequired(
216       TraceWriterBase* trace_writer,
217       TrackEventIncrementalState* incr_state,
218       const TrackEventTlsState& tls_state,
219       const TraceTimestamp& timestamp) {
220     if (incr_state->was_cleared) {
221       incr_state->was_cleared = false;
222       ResetIncrementalState(trace_writer, incr_state, tls_state, timestamp);
223     }
224   }
225 
226   // TODO(altimin): Remove this method once Chrome uses
227   // EventContext::AddDebugAnnotation directly.
228   template <typename NameType, typename ValueType>
AddDebugAnnotation(perfetto::EventContext * event_ctx,NameType && name,ValueType && value)229   static void AddDebugAnnotation(perfetto::EventContext* event_ctx,
230                                  NameType&& name,
231                                  ValueType&& value) {
232     auto annotation =
233         AddDebugAnnotation(event_ctx, std::forward<NameType>(name));
234     WriteIntoTracedValue(
235         internal::CreateTracedValueFromProto(annotation, event_ctx),
236         std::forward<ValueType>(value));
237   }
238 
239   // If the given track hasn't been seen by the trace writer yet, write a
240   // descriptor for it into the trace. Doesn't take a lock unless the track
241   // descriptor is new.
242   template <typename TrackType>
WriteTrackDescriptorIfNeeded(const TrackType & track,TraceWriterBase * trace_writer,TrackEventIncrementalState * incr_state,const TrackEventTlsState & tls_state,const TraceTimestamp & timestamp)243   static void WriteTrackDescriptorIfNeeded(
244       const TrackType& track,
245       TraceWriterBase* trace_writer,
246       TrackEventIncrementalState* incr_state,
247       const TrackEventTlsState& tls_state,
248       const TraceTimestamp& timestamp) {
249     auto it_and_inserted = incr_state->seen_tracks.insert(track.uuid);
250     if (PERFETTO_LIKELY(!it_and_inserted.second))
251       return;
252     WriteTrackDescriptor(track, trace_writer, incr_state, tls_state, timestamp);
253   }
254 
255   // Unconditionally write a track descriptor into the trace.
256   template <typename TrackType>
WriteTrackDescriptor(const TrackType & track,TraceWriterBase * trace_writer,TrackEventIncrementalState * incr_state,const TrackEventTlsState & tls_state,const TraceTimestamp & timestamp)257   static void WriteTrackDescriptor(const TrackType& track,
258                                    TraceWriterBase* trace_writer,
259                                    TrackEventIncrementalState* incr_state,
260                                    const TrackEventTlsState& tls_state,
261                                    const TraceTimestamp& timestamp) {
262     ResetIncrementalStateIfRequired(trace_writer, incr_state, tls_state,
263                                     timestamp);
264     TrackRegistry::Get()->SerializeTrack(
265         track, NewTracePacket(trace_writer, incr_state, tls_state, timestamp));
266   }
267 
268   // Get the current time in nanoseconds in the trace clock timebase.
269   static uint64_t GetTimeNs();
270 
271   static TraceTimestamp GetTraceTime();
272 
GetClockId()273   static inline protos::pbzero::BuiltinClock GetClockId() { return clock_; }
SetClockId(protos::pbzero::BuiltinClock clock)274   static inline void SetClockId(protos::pbzero::BuiltinClock clock) {
275     clock_ = clock;
276   }
277 
GetDisallowMergingWithSystemTracks()278   static inline bool GetDisallowMergingWithSystemTracks() {
279     return disallow_merging_with_system_tracks_;
280   }
SetDisallowMergingWithSystemTracks(bool disallow_merging_with_system_tracks)281   static inline void SetDisallowMergingWithSystemTracks(
282       bool disallow_merging_with_system_tracks) {
283     disallow_merging_with_system_tracks_ = disallow_merging_with_system_tracks;
284   }
285 
286   static int GetSessionCount();
287 
288   // Represents the default track for the calling thread.
289   static const Track kDefaultTrack;
290 
291  private:
292   static void ResetIncrementalState(TraceWriterBase* trace_writer,
293                                     TrackEventIncrementalState* incr_state,
294                                     const TrackEventTlsState& tls_state,
295                                     const TraceTimestamp& timestamp);
296 
297   static protozero::MessageHandle<protos::pbzero::TracePacket> NewTracePacket(
298       TraceWriterBase*,
299       TrackEventIncrementalState*,
300       const TrackEventTlsState& tls_state,
301       TraceTimestamp,
302       uint32_t seq_flags =
303           protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
304 
305   static protos::pbzero::DebugAnnotation* AddDebugAnnotation(
306       perfetto::EventContext*,
307       const char* name);
308 
309   static protos::pbzero::DebugAnnotation* AddDebugAnnotation(
310       perfetto::EventContext*,
311       perfetto::DynamicString name);
312 
313   static std::atomic<int> session_count_;
314 
315   static protos::pbzero::BuiltinClock clock_;
316   static bool disallow_merging_with_system_tracks_;
317 };
318 
319 template <typename TraceContext>
TrackEventTlsState(const TraceContext & trace_context)320 TrackEventTlsState::TrackEventTlsState(const TraceContext& trace_context) {
321   auto locked_ds = trace_context.GetDataSourceLocked();
322   bool disable_incremental_timestamps = false;
323   if (locked_ds.valid()) {
324     const auto& config = locked_ds->GetConfig();
325     disable_incremental_timestamps = config.disable_incremental_timestamps();
326     filter_debug_annotations = config.filter_debug_annotations();
327     filter_dynamic_event_names = config.filter_dynamic_event_names();
328     enable_thread_time_sampling = config.enable_thread_time_sampling();
329     if (config.has_timestamp_unit_multiplier()) {
330       timestamp_unit_multiplier = config.timestamp_unit_multiplier();
331     }
332   }
333   if (disable_incremental_timestamps) {
334     if (timestamp_unit_multiplier == 1) {
335       default_clock = static_cast<uint32_t>(TrackEventInternal::GetClockId());
336     } else {
337       default_clock = TrackEventIncrementalState::kClockIdAbsolute;
338     }
339   } else {
340     default_clock = TrackEventIncrementalState::kClockIdIncremental;
341   }
342 }
343 
344 }  // namespace internal
345 }  // namespace perfetto
346 
347 #endif  // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_INTERNAL_H_
348