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_DATA_SOURCE_INTERNAL_H_ 18 #define INCLUDE_PERFETTO_TRACING_INTERNAL_DATA_SOURCE_INTERNAL_H_ 19 20 #include <stddef.h> 21 #include <stdint.h> 22 23 #include <array> 24 #include <atomic> 25 #include <memory> 26 #include <mutex> 27 28 // No perfetto headers (other than tracing/api and protozero) should be here. 29 #include "perfetto/tracing/core/data_source_config.h" 30 #include "perfetto/tracing/internal/basic_types.h" 31 #include "perfetto/tracing/trace_writer_base.h" 32 33 namespace perfetto { 34 35 class DataSourceBase; 36 class InterceptorBase; 37 class TraceWriterBase; 38 39 namespace internal { 40 41 class TracingTLS; 42 43 // This maintains the internal state of a data source instance that is used only 44 // to implement the tracing mechanics and is not exposed to the API client. 45 // There is one of these object per DataSource instance (up to 46 // kMaxDataSourceInstances). 47 struct DataSourceState { 48 // This boolean flag determines whether the DataSource::Trace() method should 49 // do something or be a no-op. This flag doesn't give the full guarantee 50 // that tracing data will be visible in the trace, it just makes it so that 51 // the client attemps writing trace data and interacting with the service. 52 // For instance, when a tracing session ends the service will reject data 53 // commits that arrive too late even if the producer hasn't received the stop 54 // IPC message. 55 // This flag is set right before calling OnStart() and cleared right before 56 // calling OnStop(), unless using HandleStopAsynchronously() (see comments 57 // in data_source.h). 58 // Keep this flag as the first field. This allows the compiler to directly 59 // dereference the DataSourceState* pointer in the trace fast-path without 60 // doing extra pointr arithmetic. 61 std::atomic<bool> trace_lambda_enabled{false}; 62 63 // The overall TracingMuxerImpl instance id, which gets incremented by 64 // ResetForTesting. 65 uint32_t muxer_id_for_testing = 0; 66 67 // The central buffer id that all TraceWriter(s) created by this data source 68 // must target. 69 BufferId buffer_id = 0; 70 71 // The index within TracingMuxerImpl.backends_. Practically it allows to 72 // lookup the Producer object, and hence the IPC channel, for this data 73 // source. 74 TracingBackendId backend_id = 0; 75 76 // Each backend may connect to the tracing service multiple times if a 77 // disconnection occurs. This counter is used to uniquely identify each 78 // connection so that trace writers don't get reused across connections. 79 uint32_t backend_connection_id = 0; 80 81 // The instance id as assigned by the tracing service. Note that because a 82 // process can be connected to >1 services, this ID is not globally unique but 83 // is only unique within the scope of its backend. 84 // Only the tuple (backend_id, data_source_instance_id) is globally unique. 85 uint64_t data_source_instance_id = 0; 86 87 // Set to a non-0 target buffer reservation ID iff startup tracing is 88 // currently enabled for this data source. 89 std::atomic<uint16_t> startup_target_buffer_reservation{0}; 90 91 // If the data source was originally started for startup tracing, this is set 92 // to the startup session's ID. 93 uint64_t startup_session_id = 0; 94 95 // The trace config used by this instance. This is used to de-duplicate 96 // instances for data sources with identical names (e.g., track event). 97 // We store it as a pointer to be able to free memory after the datasource 98 // is stopped. 99 std::unique_ptr<DataSourceConfig> config; 100 101 // If this data source is being intercepted (see Interceptor), this field 102 // contains the non-zero id of a registered interceptor which should receive 103 // trace packets for this session. Note: interceptor id 1 refers to the first 104 // element of TracingMuxerImpl::interceptors_ with successive numbers using 105 // the following slots. 106 uint32_t interceptor_id = 0; 107 108 // This is set to true when the datasource is in the process of async stop. 109 // The flag is checked by the tracing muxer to avoid calling OnStop for the 110 // second time. 111 bool async_stop_in_progress = false; 112 113 // Whether this data source instance should call NotifyDataSourceStopped() 114 // when it's stopped. 115 bool will_notify_on_stop = false; 116 117 // Incremented whenever incremental state should be reset for this instance of 118 // this data source. 119 std::atomic<uint32_t> incremental_state_generation{0}; 120 121 // This lock is not held to implement Trace() and it's used only if the trace 122 // code wants to access its own data source state. 123 // This is to prevent that accessing the data source on an arbitrary embedder 124 // thread races with the internal IPC thread destroying the data source 125 // because of a end-of-tracing notification from the service. 126 // This lock is also used to protect access to a possible interceptor for this 127 // data source session. 128 std::recursive_mutex lock; 129 std::unique_ptr<DataSourceBase> data_source; 130 std::unique_ptr<InterceptorBase> interceptor; 131 }; 132 133 // This is to allow lazy-initialization and avoid static initializers and 134 // at-exit destructors. All the entries are initialized via placement-new when 135 // DataSource::Register() is called, see TracingMuxerImpl::RegisterDataSource(). 136 struct DataSourceStateStorage { 137 alignas(DataSourceState) char storage[sizeof(DataSourceState)]{}; 138 }; 139 140 // Per-DataSource-type global state. 141 struct DataSourceStaticState { 142 // System-wide unique id of the data source. 143 uint64_t id = 0; 144 145 // Unique index of the data source, assigned at registration time. 146 uint32_t index = kMaxDataSources; 147 148 // A bitmap that tells about the validity of each |instances| entry. When the 149 // i-th bit of the bitmap it's set, instances[i] is valid. 150 std::atomic<uint32_t> valid_instances{}; 151 std::array<DataSourceStateStorage, kMaxDataSourceInstances> instances{}; 152 153 // The caller must be sure that `n` was a valid instance at some point (either 154 // through a previous read of `valid_instances` or because the instance lock 155 // is held). GetUnsafeDataSourceStaticState156 DataSourceState* GetUnsafe(size_t n) { 157 return reinterpret_cast<DataSourceState*>(&instances[n]); 158 } 159 160 // Can be used with a cached |valid_instances| bitmap. TryGetCachedDataSourceStaticState161 DataSourceState* TryGetCached(uint32_t cached_bitmap, size_t n) { 162 return cached_bitmap & (1 << n) ? GetUnsafe(n) : nullptr; 163 } 164 TryGetDataSourceStaticState165 DataSourceState* TryGet(size_t n) { 166 return TryGetCached(valid_instances.load(std::memory_order_acquire), n); 167 } 168 CompilerAssertsDataSourceStaticState169 void CompilerAsserts() { 170 static_assert(sizeof(valid_instances.load()) * 8 >= kMaxDataSourceInstances, 171 "kMaxDataSourceInstances too high"); 172 } 173 ResetForTestingDataSourceStaticState174 void ResetForTesting() { 175 id = 0; 176 index = kMaxDataSources; 177 valid_instances.store(0, std::memory_order_release); 178 instances = {}; 179 } 180 }; 181 182 // Per-DataSource-instance thread-local state. 183 struct DataSourceInstanceThreadLocalState { ResetDataSourceInstanceThreadLocalState184 void Reset() { *this = DataSourceInstanceThreadLocalState{}; } 185 186 std::unique_ptr<TraceWriterBase> trace_writer; 187 using ObjectWithDeleter = std::unique_ptr<void, void (*)(void*)>; 188 ObjectWithDeleter incremental_state = {nullptr, [](void*) {}}; 189 ObjectWithDeleter data_source_custom_tls = {nullptr, [](void*) {}}; 190 uint32_t incremental_state_generation = 0; 191 uint32_t muxer_id_for_testing = 0; 192 TracingBackendId backend_id = 0; 193 uint32_t backend_connection_id = 0; 194 BufferId buffer_id = 0; 195 uint64_t data_source_instance_id = 0; 196 bool is_intercepted = false; 197 uint64_t last_empty_packet_position = 0; 198 uint16_t startup_target_buffer_reservation = 0; 199 }; 200 201 // Per-DataSource-type thread-local state. 202 struct DataSourceThreadLocalState { 203 DataSourceStaticState* static_state = nullptr; 204 205 // Pointer to the parent tls object that holds us. Used to retrieve the 206 // generation, which is per-global-TLS and not per data-source. 207 TracingTLS* root_tls = nullptr; 208 209 // One entry per each data source instance. 210 std::array<DataSourceInstanceThreadLocalState, kMaxDataSourceInstances> 211 per_instance{}; 212 }; 213 214 } // namespace internal 215 } // namespace perfetto 216 217 #endif // INCLUDE_PERFETTO_TRACING_INTERNAL_DATA_SOURCE_INTERNAL_H_ 218