1*6dbdd20aSAndroid Build Coastguard Worker /* 2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project 3*6dbdd20aSAndroid Build Coastguard Worker * 4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*6dbdd20aSAndroid Build Coastguard Worker * 8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*6dbdd20aSAndroid Build Coastguard Worker * 10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License. 15*6dbdd20aSAndroid Build Coastguard Worker */ 16*6dbdd20aSAndroid Build Coastguard Worker 17*6dbdd20aSAndroid Build Coastguard Worker #ifndef SRC_TRACING_SERVICE_TRACE_BUFFER_H_ 18*6dbdd20aSAndroid Build Coastguard Worker #define SRC_TRACING_SERVICE_TRACE_BUFFER_H_ 19*6dbdd20aSAndroid Build Coastguard Worker 20*6dbdd20aSAndroid Build Coastguard Worker #include <stdint.h> 21*6dbdd20aSAndroid Build Coastguard Worker #include <string.h> 22*6dbdd20aSAndroid Build Coastguard Worker 23*6dbdd20aSAndroid Build Coastguard Worker #include <array> 24*6dbdd20aSAndroid Build Coastguard Worker #include <limits> 25*6dbdd20aSAndroid Build Coastguard Worker #include <map> 26*6dbdd20aSAndroid Build Coastguard Worker #include <tuple> 27*6dbdd20aSAndroid Build Coastguard Worker 28*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h" 29*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/flat_hash_map.h" 30*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/paged_memory.h" 31*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/thread_annotations.h" 32*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/utils.h" 33*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/tracing/core/basic_types.h" 34*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/tracing/core/client_identity.h" 35*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/tracing/core/slice.h" 36*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/tracing/core/trace_stats.h" 37*6dbdd20aSAndroid Build Coastguard Worker #include "src/tracing/service/histogram.h" 38*6dbdd20aSAndroid Build Coastguard Worker 39*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto { 40*6dbdd20aSAndroid Build Coastguard Worker 41*6dbdd20aSAndroid Build Coastguard Worker class TracePacket; 42*6dbdd20aSAndroid Build Coastguard Worker 43*6dbdd20aSAndroid Build Coastguard Worker // The main buffer, owned by the tracing service, where all the trace data is 44*6dbdd20aSAndroid Build Coastguard Worker // ultimately stored into. The service will own several instances of this class, 45*6dbdd20aSAndroid Build Coastguard Worker // at least one per active consumer (as defined in the |buffers| section of 46*6dbdd20aSAndroid Build Coastguard Worker // trace_config.proto) and will copy chunks from the producer's shared memory 47*6dbdd20aSAndroid Build Coastguard Worker // buffers into here when a CommitData IPC is received. 48*6dbdd20aSAndroid Build Coastguard Worker // 49*6dbdd20aSAndroid Build Coastguard Worker // Writing into the buffer 50*6dbdd20aSAndroid Build Coastguard Worker // ----------------------- 51*6dbdd20aSAndroid Build Coastguard Worker // Data is copied from the SMB(s) using CopyChunkUntrusted(). The buffer will 52*6dbdd20aSAndroid Build Coastguard Worker // hence contain data coming from different producers and different writer 53*6dbdd20aSAndroid Build Coastguard Worker // sequences, more specifically: 54*6dbdd20aSAndroid Build Coastguard Worker // - The service receives data by several producer(s), identified by their ID. 55*6dbdd20aSAndroid Build Coastguard Worker // - Each producer writes several sequences identified by the same WriterID. 56*6dbdd20aSAndroid Build Coastguard Worker // (they correspond to TraceWriter instances in the producer). 57*6dbdd20aSAndroid Build Coastguard Worker // - Each Writer writes, in order, several chunks. 58*6dbdd20aSAndroid Build Coastguard Worker // - Each chunk contains zero, one, or more TracePacket(s), or even just 59*6dbdd20aSAndroid Build Coastguard Worker // fragments of packets (when they span across several chunks). 60*6dbdd20aSAndroid Build Coastguard Worker // 61*6dbdd20aSAndroid Build Coastguard Worker // So at any point in time, the buffer will contain a variable number of logical 62*6dbdd20aSAndroid Build Coastguard Worker // sequences identified by the {ProducerID, WriterID} tuple. Any given chunk 63*6dbdd20aSAndroid Build Coastguard Worker // will only contain packets (or fragments) belonging to the same sequence. 64*6dbdd20aSAndroid Build Coastguard Worker // 65*6dbdd20aSAndroid Build Coastguard Worker // The buffer operates by default as a ring buffer. 66*6dbdd20aSAndroid Build Coastguard Worker // It has two overwrite policies: 67*6dbdd20aSAndroid Build Coastguard Worker // 1. kOverwrite (default): if the write pointer reaches the read pointer, old 68*6dbdd20aSAndroid Build Coastguard Worker // unread chunks will be overwritten by new chunks. 69*6dbdd20aSAndroid Build Coastguard Worker // 2. kDiscard: if the write pointer reaches the read pointer, unread chunks 70*6dbdd20aSAndroid Build Coastguard Worker // are preserved and the new chunks are discarded. Any future write becomes 71*6dbdd20aSAndroid Build Coastguard Worker // a no-op, even if the reader manages to fully catch up. This is because 72*6dbdd20aSAndroid Build Coastguard Worker // once a chunk is discarded, the sequence of packets is broken and trying 73*6dbdd20aSAndroid Build Coastguard Worker // to recover would be too hard (also due to the fact that, at the same 74*6dbdd20aSAndroid Build Coastguard Worker // time, we allow out-of-order commits and chunk re-writes). 75*6dbdd20aSAndroid Build Coastguard Worker // 76*6dbdd20aSAndroid Build Coastguard Worker // Chunks are (over)written in the same order of the CopyChunkUntrusted() calls. 77*6dbdd20aSAndroid Build Coastguard Worker // When overwriting old content, entire chunks are overwritten or clobbered. 78*6dbdd20aSAndroid Build Coastguard Worker // The buffer never leaves a partial chunk around. Chunks' payload is copied 79*6dbdd20aSAndroid Build Coastguard Worker // as-is, but their header is not and is repacked in order to keep the 80*6dbdd20aSAndroid Build Coastguard Worker // ProducerID around. 81*6dbdd20aSAndroid Build Coastguard Worker // 82*6dbdd20aSAndroid Build Coastguard Worker // Chunks are stored in the buffer next to each other. Each chunk is prefixed by 83*6dbdd20aSAndroid Build Coastguard Worker // an inline header (ChunkRecord), which contains most of the fields of the 84*6dbdd20aSAndroid Build Coastguard Worker // SharedMemoryABI ChunkHeader + the ProducerID + the size of the payload. 85*6dbdd20aSAndroid Build Coastguard Worker // It's a conventional binary object stream essentially, where each ChunkRecord 86*6dbdd20aSAndroid Build Coastguard Worker // tells where it ends and hence where to find the next one, like this: 87*6dbdd20aSAndroid Build Coastguard Worker // 88*6dbdd20aSAndroid Build Coastguard Worker // .-------------------------. 16 byte boundary 89*6dbdd20aSAndroid Build Coastguard Worker // | ChunkRecord: 16 bytes | 90*6dbdd20aSAndroid Build Coastguard Worker // | - chunk id: 4 bytes | 91*6dbdd20aSAndroid Build Coastguard Worker // | - producer id: 2 bytes | 92*6dbdd20aSAndroid Build Coastguard Worker // | - writer id: 2 bytes | 93*6dbdd20aSAndroid Build Coastguard Worker // | - #fragments: 2 bytes | 94*6dbdd20aSAndroid Build Coastguard Worker // +-----+ - record size: 2 bytes | 95*6dbdd20aSAndroid Build Coastguard Worker // | | - flags+pad: 4 bytes | 96*6dbdd20aSAndroid Build Coastguard Worker // | +-------------------------+ 97*6dbdd20aSAndroid Build Coastguard Worker // | | | 98*6dbdd20aSAndroid Build Coastguard Worker // | : Chunk payload : 99*6dbdd20aSAndroid Build Coastguard Worker // | | | 100*6dbdd20aSAndroid Build Coastguard Worker // | +-------------------------+ 101*6dbdd20aSAndroid Build Coastguard Worker // | | Optional padding | 102*6dbdd20aSAndroid Build Coastguard Worker // +---> +-------------------------+ 16 byte boundary 103*6dbdd20aSAndroid Build Coastguard Worker // | ChunkRecord | 104*6dbdd20aSAndroid Build Coastguard Worker // : : 105*6dbdd20aSAndroid Build Coastguard Worker // Chunks stored in the buffer are always rounded up to 16 bytes (that is 106*6dbdd20aSAndroid Build Coastguard Worker // sizeof(ChunkRecord)), in order to avoid further inner fragmentation. 107*6dbdd20aSAndroid Build Coastguard Worker // Special "padding" chunks can be put in the buffer, e.g. in the case when we 108*6dbdd20aSAndroid Build Coastguard Worker // try to write a chunk of size N while the write pointer is at the end of the 109*6dbdd20aSAndroid Build Coastguard Worker // buffer, but the write pointer is < N bytes from the end (and hence needs to 110*6dbdd20aSAndroid Build Coastguard Worker // wrap over). 111*6dbdd20aSAndroid Build Coastguard Worker // Because of this, the buffer is self-describing: the contents of the buffer 112*6dbdd20aSAndroid Build Coastguard Worker // can be reconstructed by just looking at the buffer content (this will be 113*6dbdd20aSAndroid Build Coastguard Worker // quite useful in future to recover the buffer from crash reports). 114*6dbdd20aSAndroid Build Coastguard Worker // 115*6dbdd20aSAndroid Build Coastguard Worker // However, in order to keep some operations (patching and reading) fast, a 116*6dbdd20aSAndroid Build Coastguard Worker // lookaside index is maintained (in |index_|), keeping each chunk in the buffer 117*6dbdd20aSAndroid Build Coastguard Worker // indexed by their {ProducerID, WriterID, ChunkID} tuple. 118*6dbdd20aSAndroid Build Coastguard Worker // 119*6dbdd20aSAndroid Build Coastguard Worker // Patching data out-of-band 120*6dbdd20aSAndroid Build Coastguard Worker // ------------------------- 121*6dbdd20aSAndroid Build Coastguard Worker // This buffer also supports patching chunks' payload out-of-band, after they 122*6dbdd20aSAndroid Build Coastguard Worker // have been stored. This is to allow producers to backfill the "size" fields 123*6dbdd20aSAndroid Build Coastguard Worker // of the protos that spawn across several chunks, when the previous chunks are 124*6dbdd20aSAndroid Build Coastguard Worker // returned to the service. The MaybePatchChunkContents() deals with the fact 125*6dbdd20aSAndroid Build Coastguard Worker // that a chunk might have been lost (because of wrapping) by the time the OOB 126*6dbdd20aSAndroid Build Coastguard Worker // IPC comes. 127*6dbdd20aSAndroid Build Coastguard Worker // 128*6dbdd20aSAndroid Build Coastguard Worker // Reading from the buffer 129*6dbdd20aSAndroid Build Coastguard Worker // ----------------------- 130*6dbdd20aSAndroid Build Coastguard Worker // This class supports one reader only (the consumer). Reads are NOT idempotent 131*6dbdd20aSAndroid Build Coastguard Worker // as they move the read cursors around. Reading back the buffer is the most 132*6dbdd20aSAndroid Build Coastguard Worker // conceptually complex part. The ReadNextTracePacket() method operates with 133*6dbdd20aSAndroid Build Coastguard Worker // whole packet granularity. Packets are returned only when all their fragments 134*6dbdd20aSAndroid Build Coastguard Worker // are available. 135*6dbdd20aSAndroid Build Coastguard Worker // This class takes care of: 136*6dbdd20aSAndroid Build Coastguard Worker // - Gluing packets within the same sequence, even if they are not stored 137*6dbdd20aSAndroid Build Coastguard Worker // adjacently in the buffer. 138*6dbdd20aSAndroid Build Coastguard Worker // - Re-ordering chunks within a sequence (using the ChunkID, which wraps). 139*6dbdd20aSAndroid Build Coastguard Worker // - Detecting holes in packet fragments (because of loss of chunks). 140*6dbdd20aSAndroid Build Coastguard Worker // Reads guarantee that packets for the same sequence are read in FIFO order 141*6dbdd20aSAndroid Build Coastguard Worker // (according to their ChunkID), but don't give any guarantee about the read 142*6dbdd20aSAndroid Build Coastguard Worker // order of packets from different sequences, see comments in 143*6dbdd20aSAndroid Build Coastguard Worker // ReadNextTracePacket() below. 144*6dbdd20aSAndroid Build Coastguard Worker class TraceBuffer { 145*6dbdd20aSAndroid Build Coastguard Worker public: 146*6dbdd20aSAndroid Build Coastguard Worker static const size_t InlineChunkHeaderSize; // For test/fake_packet.{cc,h}. 147*6dbdd20aSAndroid Build Coastguard Worker 148*6dbdd20aSAndroid Build Coastguard Worker // See comment in the header above. 149*6dbdd20aSAndroid Build Coastguard Worker enum OverwritePolicy { kOverwrite, kDiscard }; 150*6dbdd20aSAndroid Build Coastguard Worker 151*6dbdd20aSAndroid Build Coastguard Worker // Argument for out-of-band patches applied through TryPatchChunkContents(). 152*6dbdd20aSAndroid Build Coastguard Worker struct Patch { 153*6dbdd20aSAndroid Build Coastguard Worker // From SharedMemoryABI::kPacketHeaderSize. 154*6dbdd20aSAndroid Build Coastguard Worker static constexpr size_t kSize = 4; 155*6dbdd20aSAndroid Build Coastguard Worker 156*6dbdd20aSAndroid Build Coastguard Worker size_t offset_untrusted; 157*6dbdd20aSAndroid Build Coastguard Worker std::array<uint8_t, kSize> data; 158*6dbdd20aSAndroid Build Coastguard Worker }; 159*6dbdd20aSAndroid Build Coastguard Worker 160*6dbdd20aSAndroid Build Coastguard Worker // Identifiers that are constant for a packet sequence. 161*6dbdd20aSAndroid Build Coastguard Worker struct PacketSequenceProperties { 162*6dbdd20aSAndroid Build Coastguard Worker ProducerID producer_id_trusted; 163*6dbdd20aSAndroid Build Coastguard Worker ClientIdentity client_identity_trusted; 164*6dbdd20aSAndroid Build Coastguard Worker WriterID writer_id; 165*6dbdd20aSAndroid Build Coastguard Worker producer_uid_trustedPacketSequenceProperties166*6dbdd20aSAndroid Build Coastguard Worker uid_t producer_uid_trusted() const { return client_identity_trusted.uid(); } producer_pid_trustedPacketSequenceProperties167*6dbdd20aSAndroid Build Coastguard Worker pid_t producer_pid_trusted() const { return client_identity_trusted.pid(); } 168*6dbdd20aSAndroid Build Coastguard Worker }; 169*6dbdd20aSAndroid Build Coastguard Worker 170*6dbdd20aSAndroid Build Coastguard Worker // Holds the "used chunk" stats for each <Producer, Writer> tuple. 171*6dbdd20aSAndroid Build Coastguard Worker struct WriterStats { 172*6dbdd20aSAndroid Build Coastguard Worker Histogram<8, 32, 128, 512, 1024, 2048, 4096, 8192, 12288, 16384> 173*6dbdd20aSAndroid Build Coastguard Worker used_chunk_hist; 174*6dbdd20aSAndroid Build Coastguard Worker }; 175*6dbdd20aSAndroid Build Coastguard Worker 176*6dbdd20aSAndroid Build Coastguard Worker using WriterStatsMap = base::FlatHashMap<ProducerAndWriterID, 177*6dbdd20aSAndroid Build Coastguard Worker WriterStats, 178*6dbdd20aSAndroid Build Coastguard Worker std::hash<ProducerAndWriterID>, 179*6dbdd20aSAndroid Build Coastguard Worker base::QuadraticProbe, 180*6dbdd20aSAndroid Build Coastguard Worker /*AppendOnly=*/true>; 181*6dbdd20aSAndroid Build Coastguard Worker 182*6dbdd20aSAndroid Build Coastguard Worker // Can return nullptr if the memory allocation fails. 183*6dbdd20aSAndroid Build Coastguard Worker static std::unique_ptr<TraceBuffer> Create(size_t size_in_bytes, 184*6dbdd20aSAndroid Build Coastguard Worker OverwritePolicy = kOverwrite); 185*6dbdd20aSAndroid Build Coastguard Worker 186*6dbdd20aSAndroid Build Coastguard Worker ~TraceBuffer(); 187*6dbdd20aSAndroid Build Coastguard Worker 188*6dbdd20aSAndroid Build Coastguard Worker // Copies a Chunk from a producer Shared Memory Buffer into the trace buffer. 189*6dbdd20aSAndroid Build Coastguard Worker // |src| points to the first packet in the SharedMemoryABI's chunk shared with 190*6dbdd20aSAndroid Build Coastguard Worker // an untrusted producer. "untrusted" here means: the producer might be 191*6dbdd20aSAndroid Build Coastguard Worker // malicious and might change |src| concurrently while we read it (internally 192*6dbdd20aSAndroid Build Coastguard Worker // this method memcpy()-s first the chunk before processing it). None of the 193*6dbdd20aSAndroid Build Coastguard Worker // arguments should be trusted, unless otherwise stated. We can trust that 194*6dbdd20aSAndroid Build Coastguard Worker // |src| points to a valid memory area, but not its contents. 195*6dbdd20aSAndroid Build Coastguard Worker // 196*6dbdd20aSAndroid Build Coastguard Worker // This method may be called multiple times for the same chunk. In this case, 197*6dbdd20aSAndroid Build Coastguard Worker // the original chunk's payload will be overridden and its number of fragments 198*6dbdd20aSAndroid Build Coastguard Worker // and flags adjusted to match |num_fragments| and |chunk_flags|. The service 199*6dbdd20aSAndroid Build Coastguard Worker // may use this to insert partial chunks (|chunk_complete = false|) before the 200*6dbdd20aSAndroid Build Coastguard Worker // producer has committed them. 201*6dbdd20aSAndroid Build Coastguard Worker // 202*6dbdd20aSAndroid Build Coastguard Worker // If |chunk_complete| is |false|, the TraceBuffer will only consider the 203*6dbdd20aSAndroid Build Coastguard Worker // first |num_fragments - 1| packets to be complete, since the producer may 204*6dbdd20aSAndroid Build Coastguard Worker // not have finished writing the latest packet. Reading from a sequence will 205*6dbdd20aSAndroid Build Coastguard Worker // also not progress past any incomplete chunks until they were rewritten with 206*6dbdd20aSAndroid Build Coastguard Worker // |chunk_complete = true|, e.g. after a producer's commit. 207*6dbdd20aSAndroid Build Coastguard Worker // 208*6dbdd20aSAndroid Build Coastguard Worker // TODO(eseckler): Pass in a PacketStreamProperties instead of individual IDs. 209*6dbdd20aSAndroid Build Coastguard Worker void CopyChunkUntrusted(ProducerID producer_id_trusted, 210*6dbdd20aSAndroid Build Coastguard Worker const ClientIdentity& client_identity_trusted, 211*6dbdd20aSAndroid Build Coastguard Worker 212*6dbdd20aSAndroid Build Coastguard Worker WriterID writer_id, 213*6dbdd20aSAndroid Build Coastguard Worker ChunkID chunk_id, 214*6dbdd20aSAndroid Build Coastguard Worker uint16_t num_fragments, 215*6dbdd20aSAndroid Build Coastguard Worker uint8_t chunk_flags, 216*6dbdd20aSAndroid Build Coastguard Worker bool chunk_complete, 217*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* src, 218*6dbdd20aSAndroid Build Coastguard Worker size_t size); 219*6dbdd20aSAndroid Build Coastguard Worker 220*6dbdd20aSAndroid Build Coastguard Worker // Applies a batch of |patches| to the given chunk, if the given chunk is 221*6dbdd20aSAndroid Build Coastguard Worker // still in the buffer. Does nothing if the given ChunkID is gone. 222*6dbdd20aSAndroid Build Coastguard Worker // Returns true if the chunk has been found and patched, false otherwise. 223*6dbdd20aSAndroid Build Coastguard Worker // |other_patches_pending| is used to determine whether this is the only 224*6dbdd20aSAndroid Build Coastguard Worker // batch of patches for the chunk or there is more. 225*6dbdd20aSAndroid Build Coastguard Worker // If |other_patches_pending| == false, the chunk is marked as ready to be 226*6dbdd20aSAndroid Build Coastguard Worker // consumed. If true, the state of the chunk is not altered. 227*6dbdd20aSAndroid Build Coastguard Worker // 228*6dbdd20aSAndroid Build Coastguard Worker // Note: If the producer is batching commits (see shared_memory_arbiter.h), it 229*6dbdd20aSAndroid Build Coastguard Worker // will also attempt to do patching locally. Namely, if nested messages are 230*6dbdd20aSAndroid Build Coastguard Worker // completed while the chunk on which they started is being batched (i.e. 231*6dbdd20aSAndroid Build Coastguard Worker // before it has been committed to the service), the producer will apply the 232*6dbdd20aSAndroid Build Coastguard Worker // respective patches to the batched chunk. These patches will not be sent to 233*6dbdd20aSAndroid Build Coastguard Worker // the service - i.e. only the patches that the producer did not manage to 234*6dbdd20aSAndroid Build Coastguard Worker // apply before committing the chunk will be applied here. 235*6dbdd20aSAndroid Build Coastguard Worker bool TryPatchChunkContents(ProducerID, 236*6dbdd20aSAndroid Build Coastguard Worker WriterID, 237*6dbdd20aSAndroid Build Coastguard Worker ChunkID, 238*6dbdd20aSAndroid Build Coastguard Worker const Patch* patches, 239*6dbdd20aSAndroid Build Coastguard Worker size_t patches_size, 240*6dbdd20aSAndroid Build Coastguard Worker bool other_patches_pending); 241*6dbdd20aSAndroid Build Coastguard Worker 242*6dbdd20aSAndroid Build Coastguard Worker // To read the contents of the buffer the caller needs to: 243*6dbdd20aSAndroid Build Coastguard Worker // BeginRead() 244*6dbdd20aSAndroid Build Coastguard Worker // while (ReadNextTracePacket(packet_fragments)) { ... } 245*6dbdd20aSAndroid Build Coastguard Worker // No other calls to any other method should be interleaved between 246*6dbdd20aSAndroid Build Coastguard Worker // BeginRead() and ReadNextTracePacket(). 247*6dbdd20aSAndroid Build Coastguard Worker // Reads in the TraceBuffer are NOT idempotent. 248*6dbdd20aSAndroid Build Coastguard Worker void BeginRead(); 249*6dbdd20aSAndroid Build Coastguard Worker 250*6dbdd20aSAndroid Build Coastguard Worker // Returns the next packet in the buffer, if any, and the producer_id, 251*6dbdd20aSAndroid Build Coastguard Worker // producer_uid, and writer_id of the producer/writer that wrote it (as passed 252*6dbdd20aSAndroid Build Coastguard Worker // in the CopyChunkUntrusted() call). Returns false if no packets can be read 253*6dbdd20aSAndroid Build Coastguard Worker // at this point. If a packet was read successfully, 254*6dbdd20aSAndroid Build Coastguard Worker // |previous_packet_on_sequence_dropped| is set to |true| if the previous 255*6dbdd20aSAndroid Build Coastguard Worker // packet on the sequence was dropped from the buffer before it could be read 256*6dbdd20aSAndroid Build Coastguard Worker // (e.g. because its chunk was overridden due to the ring buffer wrapping or 257*6dbdd20aSAndroid Build Coastguard Worker // due to an ABI violation), and to |false| otherwise. 258*6dbdd20aSAndroid Build Coastguard Worker // 259*6dbdd20aSAndroid Build Coastguard Worker // This function returns only complete packets. Specifically: 260*6dbdd20aSAndroid Build Coastguard Worker // When there is at least one complete packet in the buffer, this function 261*6dbdd20aSAndroid Build Coastguard Worker // returns true and populates the TracePacket argument with the boundaries of 262*6dbdd20aSAndroid Build Coastguard Worker // each fragment for one packet. 263*6dbdd20aSAndroid Build Coastguard Worker // TracePacket will have at least one slice when this function returns true. 264*6dbdd20aSAndroid Build Coastguard Worker // When there are no whole packets eligible to read (e.g. we are still missing 265*6dbdd20aSAndroid Build Coastguard Worker // fragments) this function returns false. 266*6dbdd20aSAndroid Build Coastguard Worker // This function guarantees also that packets for a given 267*6dbdd20aSAndroid Build Coastguard Worker // {ProducerID, WriterID} are read in FIFO order. 268*6dbdd20aSAndroid Build Coastguard Worker // This function does not guarantee any ordering w.r.t. packets belonging to 269*6dbdd20aSAndroid Build Coastguard Worker // different WriterID(s). For instance, given the following packets copied 270*6dbdd20aSAndroid Build Coastguard Worker // into the buffer: 271*6dbdd20aSAndroid Build Coastguard Worker // {ProducerID: 1, WriterID: 1}: P1 P2 P3 272*6dbdd20aSAndroid Build Coastguard Worker // {ProducerID: 1, WriterID: 2}: P4 P5 P6 273*6dbdd20aSAndroid Build Coastguard Worker // {ProducerID: 2, WriterID: 1}: P7 P8 P9 274*6dbdd20aSAndroid Build Coastguard Worker // The following read sequence is possible: 275*6dbdd20aSAndroid Build Coastguard Worker // P1, P4, P7, P2, P3, P5, P8, P9, P6 276*6dbdd20aSAndroid Build Coastguard Worker // But the following is guaranteed to NOT happen: 277*6dbdd20aSAndroid Build Coastguard Worker // P1, P5, P7, P4 (P4 cannot come after P5) 278*6dbdd20aSAndroid Build Coastguard Worker bool ReadNextTracePacket(TracePacket*, 279*6dbdd20aSAndroid Build Coastguard Worker PacketSequenceProperties* sequence_properties, 280*6dbdd20aSAndroid Build Coastguard Worker bool* previous_packet_on_sequence_dropped); 281*6dbdd20aSAndroid Build Coastguard Worker 282*6dbdd20aSAndroid Build Coastguard Worker // Creates a read-only clone of the trace buffer. The read iterators of the 283*6dbdd20aSAndroid Build Coastguard Worker // new buffer will be reset, as if no Read() had been called. Calls to 284*6dbdd20aSAndroid Build Coastguard Worker // CopyChunkUntrusted() and TryPatchChunkContents() on the returned cloned 285*6dbdd20aSAndroid Build Coastguard Worker // TraceBuffer will CHECK(). 286*6dbdd20aSAndroid Build Coastguard Worker std::unique_ptr<TraceBuffer> CloneReadOnly() const; 287*6dbdd20aSAndroid Build Coastguard Worker set_read_only()288*6dbdd20aSAndroid Build Coastguard Worker void set_read_only() { read_only_ = true; } writer_stats()289*6dbdd20aSAndroid Build Coastguard Worker const WriterStatsMap& writer_stats() const { return writer_stats_; } stats()290*6dbdd20aSAndroid Build Coastguard Worker const TraceStats::BufferStats& stats() const { return stats_; } size()291*6dbdd20aSAndroid Build Coastguard Worker size_t size() const { return size_; } used_size()292*6dbdd20aSAndroid Build Coastguard Worker size_t used_size() const { return used_size_; } overwrite_policy()293*6dbdd20aSAndroid Build Coastguard Worker OverwritePolicy overwrite_policy() const { return overwrite_policy_; } has_data()294*6dbdd20aSAndroid Build Coastguard Worker bool has_data() const { return has_data_; } 295*6dbdd20aSAndroid Build Coastguard Worker 296*6dbdd20aSAndroid Build Coastguard Worker private: 297*6dbdd20aSAndroid Build Coastguard Worker friend class TraceBufferTest; 298*6dbdd20aSAndroid Build Coastguard Worker 299*6dbdd20aSAndroid Build Coastguard Worker // ChunkRecord is a Chunk header stored inline in the |data_| buffer, before 300*6dbdd20aSAndroid Build Coastguard Worker // the chunk payload (the packets' data). The |data_| buffer looks like this: 301*6dbdd20aSAndroid Build Coastguard Worker // +---------------+------------------++---------------+-----------------+ 302*6dbdd20aSAndroid Build Coastguard Worker // | ChunkRecord 1 | Chunk payload 1 || ChunkRecord 2 | Chunk payload 2 | ... 303*6dbdd20aSAndroid Build Coastguard Worker // +---------------+------------------++---------------+-----------------+ 304*6dbdd20aSAndroid Build Coastguard Worker // Most of the ChunkRecord fields are copied from SharedMemoryABI::ChunkHeader 305*6dbdd20aSAndroid Build Coastguard Worker // (the chunk header used in the shared memory buffers). 306*6dbdd20aSAndroid Build Coastguard Worker // A ChunkRecord can be a special "padding" record. In this case its payload 307*6dbdd20aSAndroid Build Coastguard Worker // should be ignored and the record should be just skipped. 308*6dbdd20aSAndroid Build Coastguard Worker // 309*6dbdd20aSAndroid Build Coastguard Worker // Full page move optimization: 310*6dbdd20aSAndroid Build Coastguard Worker // This struct has to be exactly (sizeof(PageHeader) + sizeof(ChunkHeader)) 311*6dbdd20aSAndroid Build Coastguard Worker // (from shared_memory_abi.h) to allow full page move optimizations 312*6dbdd20aSAndroid Build Coastguard Worker // (TODO(primiano): not implemented yet). In the special case of moving a full 313*6dbdd20aSAndroid Build Coastguard Worker // 4k page that contains only one chunk, in fact, we can just ask the kernel 314*6dbdd20aSAndroid Build Coastguard Worker // to move the full SHM page (see SPLICE_F_{GIFT,MOVE}) and overlay the 315*6dbdd20aSAndroid Build Coastguard Worker // ChunkRecord on top of the moved SMB's header (page + chunk header). 316*6dbdd20aSAndroid Build Coastguard Worker // This special requirement is covered by static_assert(s) in the .cc file. 317*6dbdd20aSAndroid Build Coastguard Worker struct ChunkRecord { ChunkRecordChunkRecord318*6dbdd20aSAndroid Build Coastguard Worker explicit ChunkRecord(size_t sz) : flags{0}, is_padding{0} { 319*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(sz >= sizeof(ChunkRecord) && 320*6dbdd20aSAndroid Build Coastguard Worker sz % sizeof(ChunkRecord) == 0 && sz <= kMaxSize); 321*6dbdd20aSAndroid Build Coastguard Worker size = static_cast<decltype(size)>(sz); 322*6dbdd20aSAndroid Build Coastguard Worker } 323*6dbdd20aSAndroid Build Coastguard Worker is_validChunkRecord324*6dbdd20aSAndroid Build Coastguard Worker bool is_valid() const { return size != 0; } 325*6dbdd20aSAndroid Build Coastguard Worker 326*6dbdd20aSAndroid Build Coastguard Worker // Keep this structure packed and exactly 16 bytes (128 bits) big. 327*6dbdd20aSAndroid Build Coastguard Worker 328*6dbdd20aSAndroid Build Coastguard Worker // [32 bits] Monotonic counter within the same writer_id. 329*6dbdd20aSAndroid Build Coastguard Worker ChunkID chunk_id = 0; 330*6dbdd20aSAndroid Build Coastguard Worker 331*6dbdd20aSAndroid Build Coastguard Worker // [16 bits] ID of the Producer from which the Chunk was copied from. 332*6dbdd20aSAndroid Build Coastguard Worker ProducerID producer_id = 0; 333*6dbdd20aSAndroid Build Coastguard Worker 334*6dbdd20aSAndroid Build Coastguard Worker // [16 bits] Unique per Producer (but not within the service). 335*6dbdd20aSAndroid Build Coastguard Worker // If writer_id == kWriterIdPadding the record should just be skipped. 336*6dbdd20aSAndroid Build Coastguard Worker WriterID writer_id = 0; 337*6dbdd20aSAndroid Build Coastguard Worker 338*6dbdd20aSAndroid Build Coastguard Worker // Number of fragments contained in the chunk. 339*6dbdd20aSAndroid Build Coastguard Worker uint16_t num_fragments = 0; 340*6dbdd20aSAndroid Build Coastguard Worker 341*6dbdd20aSAndroid Build Coastguard Worker // Size in bytes, including sizeof(ChunkRecord) itself. 342*6dbdd20aSAndroid Build Coastguard Worker uint16_t size; 343*6dbdd20aSAndroid Build Coastguard Worker 344*6dbdd20aSAndroid Build Coastguard Worker uint8_t flags : 6; // See SharedMemoryABI::ChunkHeader::flags. 345*6dbdd20aSAndroid Build Coastguard Worker static constexpr size_t kFlagsBitMask = (1 << 6) - 1; 346*6dbdd20aSAndroid Build Coastguard Worker 347*6dbdd20aSAndroid Build Coastguard Worker uint8_t is_padding : 1; 348*6dbdd20aSAndroid Build Coastguard Worker uint8_t unused_flag : 1; 349*6dbdd20aSAndroid Build Coastguard Worker 350*6dbdd20aSAndroid Build Coastguard Worker // Not strictly needed, can be reused for more fields in the future. But 351*6dbdd20aSAndroid Build Coastguard Worker // right now helps to spot chunks in hex dumps. 352*6dbdd20aSAndroid Build Coastguard Worker char unused[3] = {'C', 'H', 'U'}; 353*6dbdd20aSAndroid Build Coastguard Worker 354*6dbdd20aSAndroid Build Coastguard Worker static constexpr size_t kMaxSize = 355*6dbdd20aSAndroid Build Coastguard Worker std::numeric_limits<decltype(size)>::max(); 356*6dbdd20aSAndroid Build Coastguard Worker }; 357*6dbdd20aSAndroid Build Coastguard Worker 358*6dbdd20aSAndroid Build Coastguard Worker // Lookaside index entry. This serves two purposes: 359*6dbdd20aSAndroid Build Coastguard Worker // 1) Allow a fast lookup of ChunkRecord by their ID (the tuple 360*6dbdd20aSAndroid Build Coastguard Worker // {ProducerID, WriterID, ChunkID}). This is used when applying out-of-band 361*6dbdd20aSAndroid Build Coastguard Worker // patches to the contents of the chunks after they have been copied into 362*6dbdd20aSAndroid Build Coastguard Worker // the TraceBuffer. 363*6dbdd20aSAndroid Build Coastguard Worker // 2) keep the chunks ordered by their ID. This is used when reading back. 364*6dbdd20aSAndroid Build Coastguard Worker // 3) Keep metadata about the status of the chunk, e.g. whether the contents 365*6dbdd20aSAndroid Build Coastguard Worker // have been read already and should be skipped in a future read pass. 366*6dbdd20aSAndroid Build Coastguard Worker // This struct should not have any field that is essential for reconstructing 367*6dbdd20aSAndroid Build Coastguard Worker // the contents of the buffer from a crash dump. 368*6dbdd20aSAndroid Build Coastguard Worker struct ChunkMeta { 369*6dbdd20aSAndroid Build Coastguard Worker // Key used for sorting in the map. 370*6dbdd20aSAndroid Build Coastguard Worker struct Key { KeyChunkMeta::Key371*6dbdd20aSAndroid Build Coastguard Worker Key(ProducerID p, WriterID w, ChunkID c) 372*6dbdd20aSAndroid Build Coastguard Worker : producer_id{p}, writer_id{w}, chunk_id{c} {} 373*6dbdd20aSAndroid Build Coastguard Worker 374*6dbdd20aSAndroid Build Coastguard Worker Key(const Key&) noexcept = default; 375*6dbdd20aSAndroid Build Coastguard Worker Key& operator=(const Key&) = default; 376*6dbdd20aSAndroid Build Coastguard Worker KeyChunkMeta::Key377*6dbdd20aSAndroid Build Coastguard Worker explicit Key(const ChunkRecord& cr) 378*6dbdd20aSAndroid Build Coastguard Worker : Key(cr.producer_id, cr.writer_id, cr.chunk_id) {} 379*6dbdd20aSAndroid Build Coastguard Worker 380*6dbdd20aSAndroid Build Coastguard Worker // Note that this sorting doesn't keep into account the fact that ChunkID 381*6dbdd20aSAndroid Build Coastguard Worker // will wrap over at some point. The extra logic in SequenceIterator deals 382*6dbdd20aSAndroid Build Coastguard Worker // with that. 383*6dbdd20aSAndroid Build Coastguard Worker bool operator<(const Key& other) const { 384*6dbdd20aSAndroid Build Coastguard Worker return std::tie(producer_id, writer_id, chunk_id) < 385*6dbdd20aSAndroid Build Coastguard Worker std::tie(other.producer_id, other.writer_id, other.chunk_id); 386*6dbdd20aSAndroid Build Coastguard Worker } 387*6dbdd20aSAndroid Build Coastguard Worker 388*6dbdd20aSAndroid Build Coastguard Worker bool operator==(const Key& other) const { 389*6dbdd20aSAndroid Build Coastguard Worker return std::tie(producer_id, writer_id, chunk_id) == 390*6dbdd20aSAndroid Build Coastguard Worker std::tie(other.producer_id, other.writer_id, other.chunk_id); 391*6dbdd20aSAndroid Build Coastguard Worker } 392*6dbdd20aSAndroid Build Coastguard Worker 393*6dbdd20aSAndroid Build Coastguard Worker bool operator!=(const Key& other) const { return !(*this == other); } 394*6dbdd20aSAndroid Build Coastguard Worker 395*6dbdd20aSAndroid Build Coastguard Worker // These fields should match at all times the corresponding fields in 396*6dbdd20aSAndroid Build Coastguard Worker // the |chunk_record|. They are copied here purely for efficiency to avoid 397*6dbdd20aSAndroid Build Coastguard Worker // dereferencing the buffer all the time. 398*6dbdd20aSAndroid Build Coastguard Worker ProducerID producer_id; 399*6dbdd20aSAndroid Build Coastguard Worker WriterID writer_id; 400*6dbdd20aSAndroid Build Coastguard Worker ChunkID chunk_id; 401*6dbdd20aSAndroid Build Coastguard Worker }; 402*6dbdd20aSAndroid Build Coastguard Worker 403*6dbdd20aSAndroid Build Coastguard Worker enum IndexFlags : uint8_t { 404*6dbdd20aSAndroid Build Coastguard Worker // If set, the chunk state was kChunkComplete at the time it was copied. 405*6dbdd20aSAndroid Build Coastguard Worker // If unset, the chunk was still kChunkBeingWritten while copied. When 406*6dbdd20aSAndroid Build Coastguard Worker // reading from the chunk's sequence, the sequence will not advance past 407*6dbdd20aSAndroid Build Coastguard Worker // this chunk until this flag is set. 408*6dbdd20aSAndroid Build Coastguard Worker kComplete = 1 << 0, 409*6dbdd20aSAndroid Build Coastguard Worker 410*6dbdd20aSAndroid Build Coastguard Worker // If set, we skipped the last packet that we read from this chunk e.g. 411*6dbdd20aSAndroid Build Coastguard Worker // because we it was a continuation from a previous chunk that was dropped 412*6dbdd20aSAndroid Build Coastguard Worker // or due to an ABI violation. 413*6dbdd20aSAndroid Build Coastguard Worker kLastReadPacketSkipped = 1 << 1 414*6dbdd20aSAndroid Build Coastguard Worker }; 415*6dbdd20aSAndroid Build Coastguard Worker ChunkMetaChunkMeta416*6dbdd20aSAndroid Build Coastguard Worker ChunkMeta(uint32_t _record_off, 417*6dbdd20aSAndroid Build Coastguard Worker uint16_t _num_fragments, 418*6dbdd20aSAndroid Build Coastguard Worker bool complete, 419*6dbdd20aSAndroid Build Coastguard Worker uint8_t _flags, 420*6dbdd20aSAndroid Build Coastguard Worker const ClientIdentity& client_identity) 421*6dbdd20aSAndroid Build Coastguard Worker : record_off{_record_off}, 422*6dbdd20aSAndroid Build Coastguard Worker client_identity_trusted(client_identity), 423*6dbdd20aSAndroid Build Coastguard Worker flags{_flags}, 424*6dbdd20aSAndroid Build Coastguard Worker num_fragments{_num_fragments} { 425*6dbdd20aSAndroid Build Coastguard Worker if (complete) 426*6dbdd20aSAndroid Build Coastguard Worker index_flags = kComplete; 427*6dbdd20aSAndroid Build Coastguard Worker } 428*6dbdd20aSAndroid Build Coastguard Worker 429*6dbdd20aSAndroid Build Coastguard Worker ChunkMeta(const ChunkMeta&) noexcept = default; 430*6dbdd20aSAndroid Build Coastguard Worker is_completeChunkMeta431*6dbdd20aSAndroid Build Coastguard Worker bool is_complete() const { return index_flags & kComplete; } 432*6dbdd20aSAndroid Build Coastguard Worker set_completeChunkMeta433*6dbdd20aSAndroid Build Coastguard Worker void set_complete(bool complete) { 434*6dbdd20aSAndroid Build Coastguard Worker if (complete) { 435*6dbdd20aSAndroid Build Coastguard Worker index_flags |= kComplete; 436*6dbdd20aSAndroid Build Coastguard Worker } else { 437*6dbdd20aSAndroid Build Coastguard Worker index_flags &= ~kComplete; 438*6dbdd20aSAndroid Build Coastguard Worker } 439*6dbdd20aSAndroid Build Coastguard Worker } 440*6dbdd20aSAndroid Build Coastguard Worker last_read_packet_skippedChunkMeta441*6dbdd20aSAndroid Build Coastguard Worker bool last_read_packet_skipped() const { 442*6dbdd20aSAndroid Build Coastguard Worker return index_flags & kLastReadPacketSkipped; 443*6dbdd20aSAndroid Build Coastguard Worker } 444*6dbdd20aSAndroid Build Coastguard Worker set_last_read_packet_skippedChunkMeta445*6dbdd20aSAndroid Build Coastguard Worker void set_last_read_packet_skipped(bool skipped) { 446*6dbdd20aSAndroid Build Coastguard Worker if (skipped) { 447*6dbdd20aSAndroid Build Coastguard Worker index_flags |= kLastReadPacketSkipped; 448*6dbdd20aSAndroid Build Coastguard Worker } else { 449*6dbdd20aSAndroid Build Coastguard Worker index_flags &= ~kLastReadPacketSkipped; 450*6dbdd20aSAndroid Build Coastguard Worker } 451*6dbdd20aSAndroid Build Coastguard Worker } 452*6dbdd20aSAndroid Build Coastguard Worker 453*6dbdd20aSAndroid Build Coastguard Worker const uint32_t record_off; // Offset of ChunkRecord within |data_|. 454*6dbdd20aSAndroid Build Coastguard Worker const ClientIdentity client_identity_trusted; 455*6dbdd20aSAndroid Build Coastguard Worker // Flags set by TraceBuffer to track the state of the chunk in the index. 456*6dbdd20aSAndroid Build Coastguard Worker uint8_t index_flags = 0; 457*6dbdd20aSAndroid Build Coastguard Worker 458*6dbdd20aSAndroid Build Coastguard Worker // Correspond to |chunk_record->flags| and |chunk_record->num_fragments|. 459*6dbdd20aSAndroid Build Coastguard Worker // Copied here for performance reasons (avoids having to dereference 460*6dbdd20aSAndroid Build Coastguard Worker // |chunk_record| while iterating over ChunkMeta) and to aid debugging in 461*6dbdd20aSAndroid Build Coastguard Worker // case the buffer gets corrupted. 462*6dbdd20aSAndroid Build Coastguard Worker uint8_t flags = 0; // See SharedMemoryABI::ChunkHeader::flags. 463*6dbdd20aSAndroid Build Coastguard Worker uint16_t num_fragments = 0; // Total number of packet fragments. 464*6dbdd20aSAndroid Build Coastguard Worker 465*6dbdd20aSAndroid Build Coastguard Worker uint16_t num_fragments_read = 0; // Number of fragments already read. 466*6dbdd20aSAndroid Build Coastguard Worker 467*6dbdd20aSAndroid Build Coastguard Worker // The start offset of the next fragment (the |num_fragments_read|-th) to be 468*6dbdd20aSAndroid Build Coastguard Worker // read. This is the offset in bytes from the beginning of the ChunkRecord's 469*6dbdd20aSAndroid Build Coastguard Worker // payload (the 1st fragment starts at |chunk_record| + 470*6dbdd20aSAndroid Build Coastguard Worker // sizeof(ChunkRecord)). 471*6dbdd20aSAndroid Build Coastguard Worker uint16_t cur_fragment_offset = 0; 472*6dbdd20aSAndroid Build Coastguard Worker }; 473*6dbdd20aSAndroid Build Coastguard Worker 474*6dbdd20aSAndroid Build Coastguard Worker using ChunkMap = std::map<ChunkMeta::Key, ChunkMeta>; 475*6dbdd20aSAndroid Build Coastguard Worker 476*6dbdd20aSAndroid Build Coastguard Worker // Allows to iterate over a sub-sequence of |index_| for all keys belonging to 477*6dbdd20aSAndroid Build Coastguard Worker // the same {ProducerID,WriterID}. Furthermore takes into account the wrapping 478*6dbdd20aSAndroid Build Coastguard Worker // of ChunkID. Instances are valid only as long as the |index_| is not altered 479*6dbdd20aSAndroid Build Coastguard Worker // (can be used safely only between adjacent ReadNextTracePacket() calls). 480*6dbdd20aSAndroid Build Coastguard Worker // The order of the iteration will proceed in the following order: 481*6dbdd20aSAndroid Build Coastguard Worker // |wrapping_id| + 1 -> |seq_end|, |seq_begin| -> |wrapping_id|. 482*6dbdd20aSAndroid Build Coastguard Worker // Practical example: 483*6dbdd20aSAndroid Build Coastguard Worker // - Assume that kMaxChunkID == 7 484*6dbdd20aSAndroid Build Coastguard Worker // - Assume that we have all 8 chunks in the range (0..7). 485*6dbdd20aSAndroid Build Coastguard Worker // - Hence, |seq_begin| == c0, |seq_end| == c7 486*6dbdd20aSAndroid Build Coastguard Worker // - Assume |wrapping_id| = 4 (c4 is the last chunk copied over 487*6dbdd20aSAndroid Build Coastguard Worker // through a CopyChunkUntrusted()). 488*6dbdd20aSAndroid Build Coastguard Worker // The resulting iteration order will be: c5, c6, c7, c0, c1, c2, c3, c4. 489*6dbdd20aSAndroid Build Coastguard Worker struct SequenceIterator { 490*6dbdd20aSAndroid Build Coastguard Worker // Points to the 1st key (the one with the numerically min ChunkID). 491*6dbdd20aSAndroid Build Coastguard Worker ChunkMap::iterator seq_begin; 492*6dbdd20aSAndroid Build Coastguard Worker 493*6dbdd20aSAndroid Build Coastguard Worker // Points one past the last key (the one with the numerically max ChunkID). 494*6dbdd20aSAndroid Build Coastguard Worker ChunkMap::iterator seq_end; 495*6dbdd20aSAndroid Build Coastguard Worker 496*6dbdd20aSAndroid Build Coastguard Worker // Current iterator, always >= seq_begin && <= seq_end. 497*6dbdd20aSAndroid Build Coastguard Worker ChunkMap::iterator cur; 498*6dbdd20aSAndroid Build Coastguard Worker 499*6dbdd20aSAndroid Build Coastguard Worker // The latest ChunkID written. Determines the start/end of the sequence. 500*6dbdd20aSAndroid Build Coastguard Worker ChunkID wrapping_id; 501*6dbdd20aSAndroid Build Coastguard Worker is_validSequenceIterator502*6dbdd20aSAndroid Build Coastguard Worker bool is_valid() const { return cur != seq_end; } 503*6dbdd20aSAndroid Build Coastguard Worker producer_idSequenceIterator504*6dbdd20aSAndroid Build Coastguard Worker ProducerID producer_id() const { 505*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(is_valid()); 506*6dbdd20aSAndroid Build Coastguard Worker return cur->first.producer_id; 507*6dbdd20aSAndroid Build Coastguard Worker } 508*6dbdd20aSAndroid Build Coastguard Worker writer_idSequenceIterator509*6dbdd20aSAndroid Build Coastguard Worker WriterID writer_id() const { 510*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(is_valid()); 511*6dbdd20aSAndroid Build Coastguard Worker return cur->first.writer_id; 512*6dbdd20aSAndroid Build Coastguard Worker } 513*6dbdd20aSAndroid Build Coastguard Worker chunk_idSequenceIterator514*6dbdd20aSAndroid Build Coastguard Worker ChunkID chunk_id() const { 515*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(is_valid()); 516*6dbdd20aSAndroid Build Coastguard Worker return cur->first.chunk_id; 517*6dbdd20aSAndroid Build Coastguard Worker } 518*6dbdd20aSAndroid Build Coastguard Worker 519*6dbdd20aSAndroid Build Coastguard Worker ChunkMeta& operator*() { 520*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(is_valid()); 521*6dbdd20aSAndroid Build Coastguard Worker return cur->second; 522*6dbdd20aSAndroid Build Coastguard Worker } 523*6dbdd20aSAndroid Build Coastguard Worker 524*6dbdd20aSAndroid Build Coastguard Worker // Moves |cur| to the next chunk in the index. 525*6dbdd20aSAndroid Build Coastguard Worker // is_valid() will become false after calling this, if this was the last 526*6dbdd20aSAndroid Build Coastguard Worker // entry of the sequence. 527*6dbdd20aSAndroid Build Coastguard Worker void MoveNext(); 528*6dbdd20aSAndroid Build Coastguard Worker MoveToEndSequenceIterator529*6dbdd20aSAndroid Build Coastguard Worker void MoveToEnd() { cur = seq_end; } 530*6dbdd20aSAndroid Build Coastguard Worker }; 531*6dbdd20aSAndroid Build Coastguard Worker 532*6dbdd20aSAndroid Build Coastguard Worker enum class ReadAheadResult { 533*6dbdd20aSAndroid Build Coastguard Worker kSucceededReturnSlices, 534*6dbdd20aSAndroid Build Coastguard Worker kFailedMoveToNextSequence, 535*6dbdd20aSAndroid Build Coastguard Worker kFailedStayOnSameSequence, 536*6dbdd20aSAndroid Build Coastguard Worker }; 537*6dbdd20aSAndroid Build Coastguard Worker 538*6dbdd20aSAndroid Build Coastguard Worker enum class ReadPacketResult { 539*6dbdd20aSAndroid Build Coastguard Worker kSucceeded, 540*6dbdd20aSAndroid Build Coastguard Worker kFailedInvalidPacket, 541*6dbdd20aSAndroid Build Coastguard Worker kFailedEmptyPacket, 542*6dbdd20aSAndroid Build Coastguard Worker }; 543*6dbdd20aSAndroid Build Coastguard Worker 544*6dbdd20aSAndroid Build Coastguard Worker explicit TraceBuffer(OverwritePolicy); 545*6dbdd20aSAndroid Build Coastguard Worker TraceBuffer(const TraceBuffer&) = delete; 546*6dbdd20aSAndroid Build Coastguard Worker TraceBuffer& operator=(const TraceBuffer&) = delete; 547*6dbdd20aSAndroid Build Coastguard Worker 548*6dbdd20aSAndroid Build Coastguard Worker // Not using the implicit copy ctor to avoid unintended copies. 549*6dbdd20aSAndroid Build Coastguard Worker // This tagged ctor should be used only for Clone(). 550*6dbdd20aSAndroid Build Coastguard Worker struct CloneCtor {}; 551*6dbdd20aSAndroid Build Coastguard Worker TraceBuffer(CloneCtor, const TraceBuffer&); 552*6dbdd20aSAndroid Build Coastguard Worker 553*6dbdd20aSAndroid Build Coastguard Worker bool Initialize(size_t size); 554*6dbdd20aSAndroid Build Coastguard Worker 555*6dbdd20aSAndroid Build Coastguard Worker // Returns an object that allows to iterate over chunks in the |index_| that 556*6dbdd20aSAndroid Build Coastguard Worker // have the same {ProducerID, WriterID} of 557*6dbdd20aSAndroid Build Coastguard Worker // |seq_begin.first.{producer,writer}_id|. |seq_begin| must be an iterator to 558*6dbdd20aSAndroid Build Coastguard Worker // the first entry in the |index_| that has a different {ProducerID, WriterID} 559*6dbdd20aSAndroid Build Coastguard Worker // from the previous one. It is valid for |seq_begin| to be == index_.end() 560*6dbdd20aSAndroid Build Coastguard Worker // (i.e. if the index is empty). The iteration takes care of ChunkID wrapping, 561*6dbdd20aSAndroid Build Coastguard Worker // by using |last_chunk_id_|. 562*6dbdd20aSAndroid Build Coastguard Worker SequenceIterator GetReadIterForSequence(ChunkMap::iterator seq_begin); 563*6dbdd20aSAndroid Build Coastguard Worker 564*6dbdd20aSAndroid Build Coastguard Worker // Used as a last resort when a buffer corruption is detected. 565*6dbdd20aSAndroid Build Coastguard Worker void ClearContentsAndResetRWCursors(); 566*6dbdd20aSAndroid Build Coastguard Worker 567*6dbdd20aSAndroid Build Coastguard Worker // Adds a padding record of the given size (must be a multiple of 568*6dbdd20aSAndroid Build Coastguard Worker // sizeof(ChunkRecord)). 569*6dbdd20aSAndroid Build Coastguard Worker void AddPaddingRecord(size_t); 570*6dbdd20aSAndroid Build Coastguard Worker 571*6dbdd20aSAndroid Build Coastguard Worker // Look for contiguous fragment of the same packet starting from |read_iter_|. 572*6dbdd20aSAndroid Build Coastguard Worker // If a contiguous packet is found, all the fragments are pushed into 573*6dbdd20aSAndroid Build Coastguard Worker // TracePacket and the function returns kSucceededReturnSlices. If not, the 574*6dbdd20aSAndroid Build Coastguard Worker // function returns either kFailedMoveToNextSequence or 575*6dbdd20aSAndroid Build Coastguard Worker // kFailedStayOnSameSequence, telling the caller to continue looking for 576*6dbdd20aSAndroid Build Coastguard Worker // packets. 577*6dbdd20aSAndroid Build Coastguard Worker ReadAheadResult ReadAhead(TracePacket*); 578*6dbdd20aSAndroid Build Coastguard Worker 579*6dbdd20aSAndroid Build Coastguard Worker // Deletes (by marking the record invalid and removing form the index) all 580*6dbdd20aSAndroid Build Coastguard Worker // chunks from |wptr_| to |wptr_| + |bytes_to_clear|. 581*6dbdd20aSAndroid Build Coastguard Worker // Returns: 582*6dbdd20aSAndroid Build Coastguard Worker // * The size of the gap left between the next valid Chunk and the end of 583*6dbdd20aSAndroid Build Coastguard Worker // the deletion range. 584*6dbdd20aSAndroid Build Coastguard Worker // * 0 if no next valid chunk exists (if the buffer is still zeroed). 585*6dbdd20aSAndroid Build Coastguard Worker // * -1 if the buffer |overwrite_policy_| == kDiscard and the deletion would 586*6dbdd20aSAndroid Build Coastguard Worker // cause unread chunks to be overwritten. In this case the buffer is left 587*6dbdd20aSAndroid Build Coastguard Worker // untouched. 588*6dbdd20aSAndroid Build Coastguard Worker // Graphically, assume the initial situation is the following (|wptr_| = 10). 589*6dbdd20aSAndroid Build Coastguard Worker // |0 |10 (wptr_) |30 |40 |60 590*6dbdd20aSAndroid Build Coastguard Worker // +---------+-----------------+---------+-------------------+---------+ 591*6dbdd20aSAndroid Build Coastguard Worker // | Chunk 1 | Chunk 2 | Chunk 3 | Chunk 4 | Chunk 5 | 592*6dbdd20aSAndroid Build Coastguard Worker // +---------+-----------------+---------+-------------------+---------+ 593*6dbdd20aSAndroid Build Coastguard Worker // |_________Deletion range_______|~~return value~~| 594*6dbdd20aSAndroid Build Coastguard Worker // 595*6dbdd20aSAndroid Build Coastguard Worker // A call to DeleteNextChunksFor(32) will remove chunks 2,3,4 and return 18 596*6dbdd20aSAndroid Build Coastguard Worker // (60 - 42), the distance between chunk 5 and the end of the deletion range. 597*6dbdd20aSAndroid Build Coastguard Worker ssize_t DeleteNextChunksFor(size_t bytes_to_clear); 598*6dbdd20aSAndroid Build Coastguard Worker 599*6dbdd20aSAndroid Build Coastguard Worker // Decodes the boundaries of the next packet (or a fragment) pointed by 600*6dbdd20aSAndroid Build Coastguard Worker // ChunkMeta and pushes that into |TracePacket|. It also increments the 601*6dbdd20aSAndroid Build Coastguard Worker // |num_fragments_read| counter. 602*6dbdd20aSAndroid Build Coastguard Worker // TracePacket can be nullptr, in which case the read state is still advanced. 603*6dbdd20aSAndroid Build Coastguard Worker // When TracePacket is not nullptr, ProducerID must also be not null and will 604*6dbdd20aSAndroid Build Coastguard Worker // be updated with the ProducerID that originally wrote the chunk. 605*6dbdd20aSAndroid Build Coastguard Worker ReadPacketResult ReadNextPacketInChunk(ProducerAndWriterID, 606*6dbdd20aSAndroid Build Coastguard Worker ChunkMeta*, 607*6dbdd20aSAndroid Build Coastguard Worker TracePacket*); 608*6dbdd20aSAndroid Build Coastguard Worker DcheckIsAlignedAndWithinBounds(const uint8_t * ptr)609*6dbdd20aSAndroid Build Coastguard Worker void DcheckIsAlignedAndWithinBounds(const uint8_t* ptr) const { 610*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(ptr >= begin() && ptr <= end() - sizeof(ChunkRecord)); 611*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK( 612*6dbdd20aSAndroid Build Coastguard Worker (reinterpret_cast<uintptr_t>(ptr) & (alignof(ChunkRecord) - 1)) == 0); 613*6dbdd20aSAndroid Build Coastguard Worker } 614*6dbdd20aSAndroid Build Coastguard Worker GetChunkRecordAt(uint8_t * ptr)615*6dbdd20aSAndroid Build Coastguard Worker ChunkRecord* GetChunkRecordAt(uint8_t* ptr) { 616*6dbdd20aSAndroid Build Coastguard Worker DcheckIsAlignedAndWithinBounds(ptr); 617*6dbdd20aSAndroid Build Coastguard Worker // We may be accessing a new (empty) record. 618*6dbdd20aSAndroid Build Coastguard Worker EnsureCommitted(static_cast<size_t>(ptr + sizeof(ChunkRecord) - begin())); 619*6dbdd20aSAndroid Build Coastguard Worker return reinterpret_cast<ChunkRecord*>(ptr); 620*6dbdd20aSAndroid Build Coastguard Worker } 621*6dbdd20aSAndroid Build Coastguard Worker EnsureCommitted(size_t size)622*6dbdd20aSAndroid Build Coastguard Worker void EnsureCommitted(size_t size) { 623*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(size <= size_); 624*6dbdd20aSAndroid Build Coastguard Worker data_.EnsureCommitted(size); 625*6dbdd20aSAndroid Build Coastguard Worker used_size_ = std::max(used_size_, size); 626*6dbdd20aSAndroid Build Coastguard Worker } 627*6dbdd20aSAndroid Build Coastguard Worker 628*6dbdd20aSAndroid Build Coastguard Worker void DiscardWrite(); 629*6dbdd20aSAndroid Build Coastguard Worker 630*6dbdd20aSAndroid Build Coastguard Worker // |src| can be nullptr (in which case |size| must be == 631*6dbdd20aSAndroid Build Coastguard Worker // record.size - sizeof(ChunkRecord)), for the case of writing a padding 632*6dbdd20aSAndroid Build Coastguard Worker // record. |wptr_| is NOT advanced by this function, the caller must do that. WriteChunkRecord(uint8_t * wptr,const ChunkRecord & record,const uint8_t * src,size_t size)633*6dbdd20aSAndroid Build Coastguard Worker void WriteChunkRecord(uint8_t* wptr, 634*6dbdd20aSAndroid Build Coastguard Worker const ChunkRecord& record, 635*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* src, 636*6dbdd20aSAndroid Build Coastguard Worker size_t size) { 637*6dbdd20aSAndroid Build Coastguard Worker // Note: |record.size| will be slightly bigger than |size| because of the 638*6dbdd20aSAndroid Build Coastguard Worker // ChunkRecord header and rounding, to ensure that all ChunkRecord(s) are 639*6dbdd20aSAndroid Build Coastguard Worker // multiple of sizeof(ChunkRecord). The invariant is: 640*6dbdd20aSAndroid Build Coastguard Worker // record.size >= |size| + sizeof(ChunkRecord) (== if no rounding). 641*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(size <= ChunkRecord::kMaxSize); 642*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(record.size >= sizeof(record)); 643*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(record.size % sizeof(record) == 0); 644*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(record.size >= size + sizeof(record)); 645*6dbdd20aSAndroid Build Coastguard Worker DcheckIsAlignedAndWithinBounds(wptr); 646*6dbdd20aSAndroid Build Coastguard Worker 647*6dbdd20aSAndroid Build Coastguard Worker // We may be writing to this area for the first time. 648*6dbdd20aSAndroid Build Coastguard Worker EnsureCommitted(static_cast<size_t>(wptr + record.size - begin())); 649*6dbdd20aSAndroid Build Coastguard Worker 650*6dbdd20aSAndroid Build Coastguard Worker // Deliberately not a *D*CHECK. 651*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(wptr + sizeof(record) + size <= end()); 652*6dbdd20aSAndroid Build Coastguard Worker memcpy(wptr, &record, sizeof(record)); 653*6dbdd20aSAndroid Build Coastguard Worker if (PERFETTO_LIKELY(src)) { 654*6dbdd20aSAndroid Build Coastguard Worker // If the producer modifies the data in the shared memory buffer while we 655*6dbdd20aSAndroid Build Coastguard Worker // are copying it to the central buffer, TSAN will (rightfully) flag that 656*6dbdd20aSAndroid Build Coastguard Worker // as a race. However the entire purpose of copying the data into the 657*6dbdd20aSAndroid Build Coastguard Worker // central buffer is that we can validate it without worrying that the 658*6dbdd20aSAndroid Build Coastguard Worker // producer changes it from under our feet, so this race is benign. The 659*6dbdd20aSAndroid Build Coastguard Worker // alternative would be to try computing which part of the buffer is safe 660*6dbdd20aSAndroid Build Coastguard Worker // to read (assuming a well-behaving client), but the risk of introducing 661*6dbdd20aSAndroid Build Coastguard Worker // a bug that way outweighs the benefit. 662*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ANNOTATE_BENIGN_RACE_SIZED( 663*6dbdd20aSAndroid Build Coastguard Worker src, size, "Benign race when copying chunk from shared memory.") 664*6dbdd20aSAndroid Build Coastguard Worker memcpy(wptr + sizeof(record), src, size); 665*6dbdd20aSAndroid Build Coastguard Worker } else { 666*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(size == record.size - sizeof(record)); 667*6dbdd20aSAndroid Build Coastguard Worker } 668*6dbdd20aSAndroid Build Coastguard Worker const size_t rounding_size = record.size - sizeof(record) - size; 669*6dbdd20aSAndroid Build Coastguard Worker memset(wptr + sizeof(record) + size, 0, rounding_size); 670*6dbdd20aSAndroid Build Coastguard Worker } 671*6dbdd20aSAndroid Build Coastguard Worker GetOffset(const void * _addr)672*6dbdd20aSAndroid Build Coastguard Worker uint32_t GetOffset(const void* _addr) { 673*6dbdd20aSAndroid Build Coastguard Worker const uintptr_t addr = reinterpret_cast<uintptr_t>(_addr); 674*6dbdd20aSAndroid Build Coastguard Worker const uintptr_t buf_start = reinterpret_cast<uintptr_t>(begin()); 675*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(addr >= buf_start && addr < buf_start + size_); 676*6dbdd20aSAndroid Build Coastguard Worker return static_cast<uint32_t>(addr - buf_start); 677*6dbdd20aSAndroid Build Coastguard Worker } 678*6dbdd20aSAndroid Build Coastguard Worker begin()679*6dbdd20aSAndroid Build Coastguard Worker uint8_t* begin() const { return reinterpret_cast<uint8_t*>(data_.Get()); } end()680*6dbdd20aSAndroid Build Coastguard Worker uint8_t* end() const { return begin() + size_; } size_to_end()681*6dbdd20aSAndroid Build Coastguard Worker size_t size_to_end() const { return static_cast<size_t>(end() - wptr_); } 682*6dbdd20aSAndroid Build Coastguard Worker 683*6dbdd20aSAndroid Build Coastguard Worker base::PagedMemory data_; 684*6dbdd20aSAndroid Build Coastguard Worker size_t size_ = 0; // Size in bytes of |data_|. 685*6dbdd20aSAndroid Build Coastguard Worker 686*6dbdd20aSAndroid Build Coastguard Worker // High watermark. The number of bytes (<= |size_|) written into the buffer 687*6dbdd20aSAndroid Build Coastguard Worker // before the first wraparound. This increases as data is written into the 688*6dbdd20aSAndroid Build Coastguard Worker // buffer and then saturates at |size_|. Used for CloneReadOnly(). 689*6dbdd20aSAndroid Build Coastguard Worker size_t used_size_ = 0; 690*6dbdd20aSAndroid Build Coastguard Worker 691*6dbdd20aSAndroid Build Coastguard Worker size_t max_chunk_size_ = 0; // Max size in bytes allowed for a chunk. 692*6dbdd20aSAndroid Build Coastguard Worker uint8_t* wptr_ = nullptr; // Write pointer. 693*6dbdd20aSAndroid Build Coastguard Worker 694*6dbdd20aSAndroid Build Coastguard Worker // An index that keeps track of the positions and metadata of each 695*6dbdd20aSAndroid Build Coastguard Worker // ChunkRecord. 696*6dbdd20aSAndroid Build Coastguard Worker ChunkMap index_; 697*6dbdd20aSAndroid Build Coastguard Worker 698*6dbdd20aSAndroid Build Coastguard Worker // Read iterator used for ReadNext(). It is reset by calling BeginRead(). 699*6dbdd20aSAndroid Build Coastguard Worker // It becomes invalid after any call to methods that alters the |index_|. 700*6dbdd20aSAndroid Build Coastguard Worker SequenceIterator read_iter_; 701*6dbdd20aSAndroid Build Coastguard Worker 702*6dbdd20aSAndroid Build Coastguard Worker // See comments at the top of the file. 703*6dbdd20aSAndroid Build Coastguard Worker OverwritePolicy overwrite_policy_ = kOverwrite; 704*6dbdd20aSAndroid Build Coastguard Worker 705*6dbdd20aSAndroid Build Coastguard Worker // This buffer is a read-only snapshot obtained via Clone(). If this is true 706*6dbdd20aSAndroid Build Coastguard Worker // calls to CopyChunkUntrusted() and TryPatchChunkContents() will CHECK(). 707*6dbdd20aSAndroid Build Coastguard Worker bool read_only_ = false; 708*6dbdd20aSAndroid Build Coastguard Worker 709*6dbdd20aSAndroid Build Coastguard Worker // Only used when |overwrite_policy_ == kDiscard|. This is set the first time 710*6dbdd20aSAndroid Build Coastguard Worker // a write fails because it would overwrite unread chunks. 711*6dbdd20aSAndroid Build Coastguard Worker bool discard_writes_ = false; 712*6dbdd20aSAndroid Build Coastguard Worker 713*6dbdd20aSAndroid Build Coastguard Worker // Keeps track of the highest ChunkID written for a given sequence, taking 714*6dbdd20aSAndroid Build Coastguard Worker // into account a potential overflow of ChunkIDs. In the case of overflow, 715*6dbdd20aSAndroid Build Coastguard Worker // stores the highest ChunkID written since the overflow. 716*6dbdd20aSAndroid Build Coastguard Worker // 717*6dbdd20aSAndroid Build Coastguard Worker // TODO(primiano): should clean up keys from this map. Right now it grows 718*6dbdd20aSAndroid Build Coastguard Worker // without bounds (although realistically is not a problem unless we have too 719*6dbdd20aSAndroid Build Coastguard Worker // many producers/writers within the same trace session). 720*6dbdd20aSAndroid Build Coastguard Worker std::map<std::pair<ProducerID, WriterID>, ChunkID> last_chunk_id_written_; 721*6dbdd20aSAndroid Build Coastguard Worker 722*6dbdd20aSAndroid Build Coastguard Worker // Statistics about buffer usage. 723*6dbdd20aSAndroid Build Coastguard Worker TraceStats::BufferStats stats_; 724*6dbdd20aSAndroid Build Coastguard Worker 725*6dbdd20aSAndroid Build Coastguard Worker // Per-{Producer, Writer} statistics. 726*6dbdd20aSAndroid Build Coastguard Worker WriterStatsMap writer_stats_; 727*6dbdd20aSAndroid Build Coastguard Worker 728*6dbdd20aSAndroid Build Coastguard Worker // Set to true upon the very first call to CopyChunkUntrusted() and never 729*6dbdd20aSAndroid Build Coastguard Worker // cleared. This is used to tell if the buffer has never been used since its 730*6dbdd20aSAndroid Build Coastguard Worker // creation (which in turn is used to optimize `clear_before_clone`). 731*6dbdd20aSAndroid Build Coastguard Worker bool has_data_ = false; 732*6dbdd20aSAndroid Build Coastguard Worker 733*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_DCHECK_IS_ON() 734*6dbdd20aSAndroid Build Coastguard Worker bool changed_since_last_read_ = false; 735*6dbdd20aSAndroid Build Coastguard Worker #endif 736*6dbdd20aSAndroid Build Coastguard Worker 737*6dbdd20aSAndroid Build Coastguard Worker // When true disable some DCHECKs that have been put in place to detect 738*6dbdd20aSAndroid Build Coastguard Worker // bugs in the producers. This is for tests that feed malicious inputs and 739*6dbdd20aSAndroid Build Coastguard Worker // hence mimic a buggy producer. 740*6dbdd20aSAndroid Build Coastguard Worker bool suppress_client_dchecks_for_testing_ = false; 741*6dbdd20aSAndroid Build Coastguard Worker }; 742*6dbdd20aSAndroid Build Coastguard Worker 743*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto 744*6dbdd20aSAndroid Build Coastguard Worker 745*6dbdd20aSAndroid Build Coastguard Worker #endif // SRC_TRACING_SERVICE_TRACE_BUFFER_H_ 746