| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef SRC_TRACING_SERVICE_TRACE_BUFFER_H_ |
| #define SRC_TRACING_SERVICE_TRACE_BUFFER_H_ |
| |
| #include <stdint.h> |
| #include <array> |
| #include <memory> |
| |
| #include "perfetto/ext/base/flat_hash_map.h" |
| #include "perfetto/ext/tracing/core/basic_types.h" |
| #include "perfetto/ext/tracing/core/client_identity.h" |
| #include "perfetto/ext/tracing/core/trace_stats.h" |
| #include "src/tracing/service/histogram.h" |
| |
| namespace perfetto { |
| |
| class TracePacket; |
| class TraceBuffer_WriterStats; |
| |
| // Virtual interface for trace buffers to enable multiple implementations. |
| // This interface defines the minimal surface used by the tracing service. |
| class TraceBuffer { |
| public: |
| using WriterStats = TraceBuffer_WriterStats; |
| |
| // See comment in the header above. |
| enum OverwritePolicy { kOverwrite, kDiscard }; |
| |
| // Type of trace buffer implementation. |
| // TODO(primiano): remove this once TraceBufferV2 proves itself. |
| // kV2 is experimental. |
| enum BufType { |
| kV1, |
| kV2, |
| }; |
| |
| // Argument for out-of-band patches applied through TryPatchChunkContents(). |
| struct Patch { |
| // From SharedMemoryABI::kPacketHeaderSize. |
| static constexpr size_t kSize = 4; |
| |
| size_t offset_untrusted; |
| std::array<uint8_t, kSize> data; |
| }; |
| |
| // Identifiers that are constant for a packet sequence. |
| struct PacketSequenceProperties { |
| ProducerID producer_id_trusted; |
| ClientIdentity client_identity_trusted; |
| WriterID writer_id; |
| |
| uid_t producer_uid_trusted() const { return client_identity_trusted.uid(); } |
| pid_t producer_pid_trusted() const { return client_identity_trusted.pid(); } |
| }; |
| |
| virtual ~TraceBuffer(); |
| |
| // Copies a Chunk from a producer Shared Memory Buffer into the trace buffer. |
| virtual void CopyChunkUntrusted(ProducerID producer_id_trusted, |
| const ClientIdentity& client_identity_trusted, |
| WriterID writer_id, |
| ChunkID chunk_id, |
| uint16_t num_fragments, |
| uint8_t chunk_flags, |
| bool chunk_complete, |
| const uint8_t* src, |
| size_t size) = 0; |
| |
| // Applies a batch of |patches| to the given chunk, if the given chunk is |
| // still in the buffer. Does nothing if the given ChunkID is gone. |
| // Returns true if the chunk has been found and patched, false otherwise. |
| virtual bool TryPatchChunkContents(ProducerID, |
| WriterID, |
| ChunkID, |
| const Patch* patches, |
| size_t patches_size, |
| bool other_patches_pending) = 0; |
| |
| // To read the contents of the buffer the caller needs to: |
| // BeginRead() |
| // while (ReadNextTracePacket(packet_fragments)) { ... } |
| // No other calls to any other method should be interleaved between |
| // BeginRead() and ReadNextTracePacket(). |
| // Reads in the TraceBuffer are NOT idempotent. |
| virtual void BeginRead() = 0; |
| |
| // Returns the next packet in the buffer, if any, and the producer_id, |
| // producer_uid, and writer_id of the producer/writer that wrote it. |
| // Returns false if no packets can be read at this point. |
| // |previous_packet_on_sequence_dropped| is a bitmask: 0 if no data was lost |
| // on the sequence before this packet, otherwise nonzero. TraceBufferV2 sets |
| // the DataLossReason cause bits; TraceBufferV1 just sets 1. The value is |
| // forwarded into TracePacket.previous_packet_dropped. |
| virtual bool ReadNextTracePacket( |
| TracePacket*, |
| PacketSequenceProperties* sequence_properties, |
| uint32_t* previous_packet_on_sequence_dropped) = 0; |
| |
| // Creates a read-only clone of the trace buffer. The read iterators of the |
| // new buffer will be reset, as if no Read() had been called. |
| virtual std::unique_ptr<TraceBuffer> CloneReadOnly() const = 0; |
| |
| virtual void set_read_only() = 0; |
| virtual const TraceStats::BufferStats& stats() const = 0; |
| virtual const WriterStats& writer_stats() const = 0; |
| virtual size_t size() const = 0; |
| virtual size_t used_size() const = 0; |
| virtual size_t GetMemoryUsageBytes() const = 0; |
| virtual OverwritePolicy overwrite_policy() const = 0; |
| virtual bool has_data() const = 0; |
| virtual BufType buf_type() const = 0; |
| |
| // Exposed for test/fake_packet.{cc,h}. |
| static inline constexpr size_t InlineChunkHeaderSize = 16; |
| }; |
| |
| class TraceBuffer_WriterStats { |
| public: |
| using WriterBuckets = |
| Histogram<8, 32, 128, 512, 1024, 2048, 4096, 8192, 12288, 16384>; |
| using WriterStatsMap = base::FlatHashMap<ProducerAndWriterID, |
| WriterBuckets, |
| std::hash<ProducerAndWriterID>, |
| base::QuadraticProbe, |
| /*AppendOnly=*/true>; |
| |
| void Insert(ProducerAndWriterID key, HistValue val) { |
| map_.Insert(key, {}).first->Add(val); |
| } |
| |
| WriterStatsMap::Iterator GetIterator() const { return map_.GetIterator(); } |
| |
| private: |
| WriterStatsMap map_; |
| }; |
| |
| } // namespace perfetto |
| |
| #endif // SRC_TRACING_SERVICE_TRACE_BUFFER_H_ |