• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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