1 /* 2 * Copyright (C) 2018 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_EXT_TRACING_CORE_SHARED_MEMORY_ARBITER_H_ 18 #define INCLUDE_PERFETTO_EXT_TRACING_CORE_SHARED_MEMORY_ARBITER_H_ 19 20 #include <stddef.h> 21 22 #include <functional> 23 #include <memory> 24 #include <vector> 25 26 #include "perfetto/base/export.h" 27 #include "perfetto/ext/tracing/core/basic_types.h" 28 #include "perfetto/ext/tracing/core/shared_memory_abi.h" 29 #include "perfetto/ext/tracing/core/tracing_service.h" 30 #include "perfetto/tracing/buffer_exhausted_policy.h" 31 32 namespace perfetto { 33 34 namespace base { 35 class TaskRunner; 36 } 37 38 class SharedMemory; 39 class TraceWriter; 40 41 // Used by the Producer-side of the transport layer to vend TraceWriters 42 // from the SharedMemory it receives from the Service-side. 43 class PERFETTO_EXPORT_COMPONENT SharedMemoryArbiter { 44 public: 45 using ShmemMode = SharedMemoryABI::ShmemMode; 46 47 virtual ~SharedMemoryArbiter(); 48 49 // Creates a new TraceWriter and assigns it a new WriterID. The WriterID is 50 // written in each chunk header owned by a given TraceWriter and is used by 51 // the Service to reconstruct TracePackets written by the same TraceWriter. 52 // Returns null impl of TraceWriter if all WriterID slots are exhausted. The 53 // writer will commit to the provided |target_buffer|. If the arbiter was 54 // created via CreateUnbound() or CreateStartupTraceWriter() is later used, 55 // only BufferExhaustedPolicy::kDrop is supported. 56 virtual std::unique_ptr<TraceWriter> CreateTraceWriter( 57 BufferID target_buffer, 58 BufferExhaustedPolicy buffer_exhausted_policy = 59 BufferExhaustedPolicy::kDefault) = 0; 60 61 // Creates a TraceWriter that will commit to the target buffer with the given 62 // reservation ID (creating a new reservation for this ID if none exists yet). 63 // The buffer reservation should be bound to an actual BufferID via 64 // BindStartupTargetBuffer() once the actual BufferID is known. Calling this 65 // method may transition the arbiter into unbound state (see state diagram in 66 // SharedMemoryArbiterImpl's class comment) and requires that all (past and 67 // future) TraceWriters are created with BufferExhaustedPolicy::kDrop. 68 // 69 // While any unbound buffer reservation exists, all commits will be buffered 70 // until all reservations were bound. Thus, until all reservations are bound, 71 // the data written to the SMB will not be consumed by the service - the SMB 72 // size should be chosen with this in mind. Startup writers always use 73 // BufferExhaustedPolicy::kDrop, as we cannot feasibly stall while not 74 // flushing to the service. 75 // 76 // The |target_buffer_reservation_id| should be greater than 0 but can 77 // otherwise be freely chosen by the producer and is only used to translate 78 // packets into the actual buffer id once 79 // BindStartupTargetBuffer(reservation_id) is called. For example, Chrome uses 80 // startup tracing not only for the first, but also subsequent tracing 81 // sessions (to enable tracing in the browser process before it instructs the 82 // tracing service to start tracing asynchronously, minimizing trace data loss 83 // in the meantime), and increments the reservation ID between sessions. 84 // Similarly, if more than a single target buffer per session is required 85 // (e.g. for two different data sources), different reservation IDs should be 86 // chosen for different target buffers. 87 virtual std::unique_ptr<TraceWriter> CreateStartupTraceWriter( 88 uint16_t target_buffer_reservation_id) = 0; 89 90 // Should only be called on unbound SharedMemoryArbiters. Binds the arbiter to 91 // the provided ProducerEndpoint and TaskRunner. Should be called only once 92 // and on the provided |TaskRunner|. Usually called by the producer (i.e., no 93 // specific data source) once it connects to the service. Both the endpoint 94 // and task runner should remain valid for the remainder of the arbiter's 95 // lifetime. 96 virtual void BindToProducerEndpoint(TracingService::ProducerEndpoint*, 97 base::TaskRunner*) = 0; 98 99 // Binds commits from TraceWriters created via CreateStartupTraceWriter() with 100 // the given |target_buffer_reservation_id| to |target_buffer_id|. May only be 101 // called once per |target_buffer_reservation_id|. Should be called on the 102 // arbiter's TaskRunner, and after BindToProducerEndpoint() was called. 103 // Usually, it is called by a specific data source, after it received its 104 // configuration (including the target buffer ID) from the service. 105 virtual void BindStartupTargetBuffer(uint16_t target_buffer_reservation_id, 106 BufferID target_buffer_id) = 0; 107 108 // Treat the reservation as resolved to an invalid buffer. Commits for this 109 // reservation will be flushed to the service ASAP. The service will free 110 // committed chunks but otherwise ignore them. The producer can call this 111 // method, for example, if connection to the tracing service failed or the 112 // session was stopped concurrently before the connection was established. 113 virtual void AbortStartupTracingForReservation( 114 uint16_t target_buffer_reservation_id) = 0; 115 116 // Notifies the service that all data for the given FlushRequestID has been 117 // committed in the shared memory buffer. Should only be called while bound. 118 virtual void NotifyFlushComplete(FlushRequestID) = 0; 119 120 // Sets the duration during which commits are batched. Args: 121 // |batch_commits_duration_ms|: The length of the period, during which commits 122 // by all trace writers are accumulated, before being sent to the service. 123 // When the period ends, all accumulated commits are flushed. On the first 124 // commit after the last flush, another delayed flush is scheduled to run in 125 // |batch_commits_duration_ms|. If an immediate flush occurs (via 126 // FlushPendingCommitDataRequests()) during a batching period, any 127 // accumulated commits up to that point will be sent to the service 128 // immediately. And when the batching period ends, the commits that occurred 129 // after the immediate flush will also be sent to the service. 130 // 131 // If the duration has already been set to a non-zero value before this method 132 // is called, and there is already a scheduled flush with the previously-set 133 // duration, the new duration will take effect after the scheduled flush 134 // occurs. 135 // 136 // If |batch_commits_duration_ms| is non-zero, batched data that hasn't been 137 // sent could be lost at the end of a tracing session. To avoid this, 138 // producers should make sure that FlushPendingCommitDataRequests is called 139 // after the last TraceWriter write and before the service has stopped 140 // listening for commits from the tracing session's data sources (i.e. 141 // data sources should stop asynchronously, see 142 // DataSourceDescriptor.will_notify_on_stop=true). 143 virtual void SetBatchCommitsDuration(uint32_t batch_commits_duration_ms) = 0; 144 145 // Called to enable direct producer-side patching of chunks that have not yet 146 // been committed to the service. The return value indicates whether direct 147 // patching was successfully enabled. It will be true if 148 // SharedMemoryArbiter::SetDirectSMBPatchingSupportedByService has been called 149 // and false otherwise. 150 virtual bool EnableDirectSMBPatching() = 0; 151 152 // When the producer and service live in separate processes, this method 153 // should be called if the producer receives an 154 // InitializeConnectionResponse.direct_smb_patching_supported set to true by 155 // the service (see producer_port.proto) . 156 // 157 // In the in-process case, the service will always support direct SMB patching 158 // and this method should always be called. 159 virtual void SetDirectSMBPatchingSupportedByService() = 0; 160 161 // Forces an immediate commit of the completed packets, without waiting for 162 // the next task or for a batching period to end. Should only be called while 163 // bound. 164 virtual void FlushPendingCommitDataRequests( 165 std::function<void()> callback = {}) = 0; 166 167 // Attempts to shut down this arbiter. This function prevents new trace 168 // writers from being created for this this arbiter, but if there are any 169 // existing trace writers, the shutdown cannot proceed and this funtion 170 // returns false. The caller should not delete the arbiter before all of its 171 // associated trace writers have been destroyed and this function returns 172 // true. 173 virtual bool TryShutdown() = 0; 174 175 // Create a bound arbiter instance. Args: 176 // |SharedMemory|: the shared memory buffer to use. 177 // |page_size|: a multiple of 4KB that defines the granularity of tracing 178 // pages. See tradeoff considerations in shared_memory_abi.h. 179 // |ProducerEndpoint|: The service's producer endpoint used e.g. to commit 180 // chunks and register trace writers. 181 // |TaskRunner|: Task runner for perfetto's main thread, which executes the 182 // OnPagesCompleteCallback and IPC calls to the |ProducerEndpoint|. 183 // 184 // Implemented in src/core/shared_memory_arbiter_impl.cc. 185 static std::unique_ptr<SharedMemoryArbiter> CreateInstance( 186 SharedMemory*, 187 size_t page_size, 188 ShmemMode, 189 TracingService::ProducerEndpoint*, 190 base::TaskRunner*); 191 192 // Create an unbound arbiter instance, which should later be bound to a 193 // ProducerEndpoint and TaskRunner by calling BindToProducerEndpoint(). The 194 // returned arbiter will ONLY support trace writers with 195 // BufferExhaustedPolicy::kDrop. 196 // 197 // An unbound SharedMemoryArbiter can be used to write to a producer-created 198 // SharedMemory buffer before the producer connects to the tracing service. 199 // The producer can then pass this SMB to the service when it connects (see 200 // TracingService::ConnectProducer). 201 // 202 // To trace into the SMB before the service starts the tracing session, trace 203 // writers can be obtained via CreateStartupTraceWriter() and later associated 204 // with a target buffer via BindStartupTargetBuffer(), once the target buffer 205 // is known. 206 // 207 // Implemented in src/core/shared_memory_arbiter_impl.cc. See CreateInstance() 208 // for comments about the arguments. 209 static std::unique_ptr<SharedMemoryArbiter> 210 CreateUnboundInstance(SharedMemory*, size_t page_size, ShmemMode mode); 211 }; 212 213 } // namespace perfetto 214 215 #endif // INCLUDE_PERFETTO_EXT_TRACING_CORE_SHARED_MEMORY_ARBITER_H_ 216