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 class EventContext;
36 class TrackEventSessionObserver;
37 struct Category;
38 namespace protos {
39 namespace gen {
40 class TrackEventConfig;
41 }  // namespace gen
42 namespace pbzero {
43 class DebugAnnotation;
44 }  // namespace pbzero
45 }  // namespace protos
46 
47 // A callback interface for observing track event tracing sessions starting and
48 // stopping. See TrackEvent::{Add,Remove}SessionObserver. Note that all methods
49 // will be called on an internal Perfetto thread.
50 class PERFETTO_EXPORT TrackEventSessionObserver {
51  public:
52   virtual ~TrackEventSessionObserver();
53   // Called when a track event tracing session is configured. Note tracing isn't
54   // active yet, so track events emitted here won't be recorded. See
55   // DataSourceBase::OnSetup.
56   virtual void OnSetup(const DataSourceBase::SetupArgs&);
57   // Called when a track event tracing session is started. It is possible to
58   // emit track events from this callback.
59   virtual void OnStart(const DataSourceBase::StartArgs&);
60   // Called when a track event tracing session is stopped. It is still possible
61   // to emit track events from this callback.
62   virtual void OnStop(const DataSourceBase::StopArgs&);
63 };
64 
65 namespace internal {
66 class TrackEventCategoryRegistry;
67 
68 class PERFETTO_EXPORT BaseTrackEventInternedDataIndex {
69  public:
70   virtual ~BaseTrackEventInternedDataIndex();
71 
72 #if PERFETTO_DCHECK_IS_ON()
73   const char* type_id_ = nullptr;
74   const void* add_function_ptr_ = nullptr;
75 #endif  // PERFETTO_DCHECK_IS_ON()
76 };
77 
78 struct TrackEventIncrementalState {
79   static constexpr size_t kMaxInternedDataFields = 32;
80 
81   bool was_cleared = true;
82 
83   // A heap-allocated message for storing newly seen interned data while we are
84   // in the middle of writing a track event. When a track event wants to write
85   // new interned data into the trace, it is first serialized into this message
86   // and then flushed to the real trace in EventContext when the packet ends.
87   // The message is cached here as a part of incremental state so that we can
88   // reuse the underlying buffer allocation for subsequently written interned
89   // data.
90   protozero::HeapBuffered<protos::pbzero::InternedData>
91       serialized_interned_data;
92 
93   // In-memory indices for looking up interned data ids.
94   // For each intern-able field (up to a max of 32) we keep a dictionary of
95   // field-value -> interning-key. Depending on the type we either keep the full
96   // value or a hash of it (See track_event_interned_data_index.h)
97   using InternedDataIndex =
98       std::pair</* interned_data.proto field number */ size_t,
99                 std::unique_ptr<BaseTrackEventInternedDataIndex>>;
100   std::array<InternedDataIndex, kMaxInternedDataFields> interned_data_indices =
101       {};
102 
103   // Track uuids for which we have written descriptors into the trace. If a
104   // trace event uses a track which is not in this set, we'll write out a
105   // descriptor for it.
106   base::FlatSet<uint64_t> seen_tracks;
107 
108   // Dynamically registered category names that have been encountered during
109   // this tracing session. The value in the map indicates whether the category
110   // is enabled or disabled.
111   std::unordered_map<std::string, bool> dynamic_categories;
112 };
113 
114 // The backend portion of the track event trace point implemention. Outlined to
115 // a separate .cc file so it can be shared by different track event category
116 // namespaces.
117 class PERFETTO_EXPORT TrackEventInternal {
118  public:
119   static bool Initialize(
120       const TrackEventCategoryRegistry&,
121       bool (*register_data_source)(const DataSourceDescriptor&));
122 
123   static bool AddSessionObserver(TrackEventSessionObserver*);
124   static void RemoveSessionObserver(TrackEventSessionObserver*);
125 
126   static void EnableTracing(const TrackEventCategoryRegistry& registry,
127                             const protos::gen::TrackEventConfig& config,
128                             const DataSourceBase::SetupArgs&);
129   static void OnStart(const DataSourceBase::StartArgs&);
130   static void DisableTracing(const TrackEventCategoryRegistry& registry,
131                              const DataSourceBase::StopArgs&);
132   static bool IsCategoryEnabled(const TrackEventCategoryRegistry& registry,
133                                 const protos::gen::TrackEventConfig& config,
134                                 const Category& category);
135 
136   static perfetto::EventContext WriteEvent(
137       TraceWriterBase*,
138       TrackEventIncrementalState*,
139       const Category* category,
140       const char* name,
141       perfetto::protos::pbzero::TrackEvent::Type,
142       uint64_t timestamp = GetTimeNs());
143 
144   static void ResetIncrementalState(TraceWriterBase*, uint64_t timestamp);
145 
146   template <typename T>
AddDebugAnnotation(perfetto::EventContext * event_ctx,const char * name,T && value)147   static void AddDebugAnnotation(perfetto::EventContext* event_ctx,
148                                  const char* name,
149                                  T&& value) {
150     auto annotation = AddDebugAnnotation(event_ctx, name);
151     WriteIntoTracedValue(internal::CreateTracedValueFromProto(annotation),
152                          std::forward<T>(value));
153   }
154 
155   // If the given track hasn't been seen by the trace writer yet, write a
156   // descriptor for it into the trace. Doesn't take a lock unless the track
157   // descriptor is new.
158   template <typename TrackType>
WriteTrackDescriptorIfNeeded(const TrackType & track,TraceWriterBase * trace_writer,TrackEventIncrementalState * incr_state)159   static void WriteTrackDescriptorIfNeeded(
160       const TrackType& track,
161       TraceWriterBase* trace_writer,
162       TrackEventIncrementalState* incr_state) {
163     auto it_and_inserted = incr_state->seen_tracks.insert(track.uuid);
164     if (PERFETTO_LIKELY(!it_and_inserted.second))
165       return;
166     WriteTrackDescriptor(track, trace_writer);
167   }
168 
169   // Unconditionally write a track descriptor into the trace.
170   template <typename TrackType>
WriteTrackDescriptor(const TrackType & track,TraceWriterBase * trace_writer)171   static void WriteTrackDescriptor(const TrackType& track,
172                                    TraceWriterBase* trace_writer) {
173     TrackRegistry::Get()->SerializeTrack(
174         track, NewTracePacket(trace_writer, GetTimeNs()));
175   }
176 
177   // Get the current time in nanoseconds in the trace clock timebase.
178   static uint64_t GetTimeNs();
179 
180   // Get the clock used by GetTimeNs().
GetClockId()181   static constexpr protos::pbzero::BuiltinClock GetClockId() {
182 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \
183     !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
184     return protos::pbzero::BUILTIN_CLOCK_BOOTTIME;
185 #else
186     return protos::pbzero::BUILTIN_CLOCK_MONOTONIC;
187 #endif
188   }
189 
190   static int GetSessionCount();
191 
192   // Represents the default track for the calling thread.
193   static const Track kDefaultTrack;
194 
195  private:
196   static protozero::MessageHandle<protos::pbzero::TracePacket> NewTracePacket(
197       TraceWriterBase*,
198       uint64_t timestamp,
199       uint32_t seq_flags =
200           protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
201   static protos::pbzero::DebugAnnotation* AddDebugAnnotation(
202       perfetto::EventContext*,
203       const char* name);
204 
205   static std::atomic<int> session_count_;
206 };
207 
208 }  // namespace internal
209 }  // namespace perfetto
210 
211 #endif  // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_INTERNAL_H_
212