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