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