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