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