1 /* 2 * Copyright (C) 2017 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_CORE_TRACE_WRITER_IMPL_H_ 18 #define SRC_TRACING_CORE_TRACE_WRITER_IMPL_H_ 19 20 #include "perfetto/base/proc_utils.h" 21 #include "perfetto/ext/tracing/core/basic_types.h" 22 #include "perfetto/ext/tracing/core/shared_memory_abi.h" 23 #include "perfetto/ext/tracing/core/shared_memory_arbiter.h" 24 #include "perfetto/ext/tracing/core/trace_writer.h" 25 #include "perfetto/protozero/message_handle.h" 26 #include "perfetto/protozero/proto_utils.h" 27 #include "perfetto/protozero/root_message.h" 28 #include "perfetto/protozero/scattered_stream_writer.h" 29 #include "perfetto/tracing/buffer_exhausted_policy.h" 30 #include "src/tracing/core/patch_list.h" 31 32 namespace perfetto { 33 34 class SharedMemoryArbiterImpl; 35 36 // See //include/perfetto/ext/tracing/core/trace_writer.h for docs. 37 // 38 // Locking will happen only when a chunk is exhausted and a new one is 39 // acquired from the arbiter. 40 // 41 // TODO: TraceWriter needs to keep the shared memory buffer alive (refcount?). 42 // Otherwise if the shared memory buffer goes away (e.g. the Service crashes) 43 // the TraceWriter will keep writing into unmapped memory. 44 // 45 class TraceWriterImpl : public TraceWriter, 46 public protozero::ScatteredStreamWriter::Delegate { 47 public: 48 // TracePacketHandle is defined in trace_writer.h 49 TraceWriterImpl(SharedMemoryArbiterImpl*, 50 WriterID, 51 MaybeUnboundBufferID buffer_id, 52 BufferExhaustedPolicy); 53 ~TraceWriterImpl() override; 54 55 // TraceWriter implementation. See documentation in trace_writer.h. 56 TracePacketHandle NewTracePacket() override; 57 void FinishTracePacket() override; 58 // Commits the data pending for the current chunk into the shared memory 59 // buffer and sends a CommitDataRequest() to the service. 60 // TODO(primiano): right now the |callback| will be called on the IPC thread. 61 // This is fine in the current single-thread scenario, but long-term 62 // trace_writer_impl.cc should be smarter and post it on the right thread. 63 void Flush(std::function<void()> callback = {}) override; 64 WriterID writer_id() const override; written()65 uint64_t written() const override { 66 return protobuf_stream_writer_.written(); 67 } 68 ResetChunkForTesting()69 void ResetChunkForTesting() { cur_chunk_ = SharedMemoryABI::Chunk(); } drop_packets_for_testing()70 bool drop_packets_for_testing() const { return drop_packets_; } 71 72 private: 73 TraceWriterImpl(const TraceWriterImpl&) = delete; 74 TraceWriterImpl& operator=(const TraceWriterImpl&) = delete; 75 76 // ScatteredStreamWriter::Delegate implementation. 77 protozero::ContiguousMemoryRange GetNewBuffer() override; 78 uint8_t* AnnotatePatch(uint8_t*) override; 79 80 // The per-producer arbiter that coordinates access to the shared memory 81 // buffer from several threads. 82 SharedMemoryArbiterImpl* const shmem_arbiter_; 83 84 // ID of the current writer. 85 const WriterID id_; 86 87 // This is copied into the commit request by SharedMemoryArbiter. See comments 88 // in data_source_config.proto for |target_buffer|. If this is a reservation 89 // for a buffer ID in case of a startup trace writer, SharedMemoryArbiterImpl 90 // will also translate the reservation ID to the actual buffer ID. 91 const MaybeUnboundBufferID target_buffer_; 92 93 // Whether GetNewChunk() should stall or return an invalid chunk if the SMB is 94 // exhausted. 95 const BufferExhaustedPolicy buffer_exhausted_policy_; 96 97 // Monotonic (% wrapping) sequence id of the chunk. Together with the WriterID 98 // this allows the Service to reconstruct the linear sequence of packets. 99 ChunkID next_chunk_id_ = 0; 100 101 // The chunk we are holding onto (if any). 102 SharedMemoryABI::Chunk cur_chunk_; 103 104 // Passed to protozero message to write directly into |cur_chunk_|. It 105 // keeps track of the write pointer. It calls us back (GetNewBuffer()) when 106 // |cur_chunk_| is filled. 107 protozero::ScatteredStreamWriter protobuf_stream_writer_; 108 109 // The packet returned via NewTracePacket(). Its owned by this class, 110 // TracePacketHandle has just a pointer to it. 111 // 112 // The caller of NewTracePacket can use TakeStreamWriter() and use the stream 113 // writer directly: in that case: 114 // * cur_packet_->size() is not up to date. Only the stream writer has the 115 // correct information. 116 // * cur_packet_->nested_message() is always nullptr. 117 // * cur_packet_->size_field() is still used to track the start of the current 118 // fragment. 119 std::unique_ptr<protozero::RootMessage<protos::pbzero::TracePacket>> 120 cur_packet_; 121 122 // The start address of |cur_packet_| within |cur_chunk_|. Used to figure out 123 // fragments sizes when a TracePacket write is interrupted by GetNewBuffer(). 124 uint8_t* cur_fragment_start_ = nullptr; 125 126 // true if we received a call to GetNewBuffer() after NewTracePacket(), 127 // false if GetNewBuffer() happened during NewTracePacket() prologue, while 128 // starting the TracePacket header. 129 bool fragmenting_packet_ = false; 130 131 // Set to |true| when the current chunk contains the maximum number of packets 132 // a chunk can contain. When this is |true|, the next packet requires starting 133 // a new chunk. 134 bool reached_max_packets_per_chunk_ = false; 135 136 // If we fail to acquire a new chunk when the arbiter operates in 137 // SharedMemory::BufferExhaustedPolicy::kDrop mode, the trace writer enters a 138 // mode in which data is written to a local garbage chunk and dropped. 139 bool drop_packets_ = false; 140 141 // Whether the trace writer should try to acquire a new chunk from the SMB 142 // when the next TracePacket is started because it filled the garbage chunk at 143 // least once since the last attempt. 144 bool retry_new_chunk_after_packet_ = false; 145 146 // Points to the size field of the last packet we wrote to the current chunk. 147 // If the chunk was already returned, this is reset to |nullptr|. 148 uint8_t* last_packet_size_field_ = nullptr; 149 150 // When a packet is fragmented across different chunks, the |size_field| of 151 // the outstanding nested protobuf messages is redirected onto Patch entries 152 // in this list at the time the Chunk is returned (because at that point we 153 // have to release the ownership of the current Chunk). This list will be 154 // later sent out-of-band to the tracing service, who will patch the required 155 // chunks, if they are still around. 156 PatchList patch_list_; 157 158 // PID of the process that created the trace writer. Used for a DCHECK that 159 // aims to detect unsupported process forks while tracing. 160 const base::PlatformProcessId process_id_; 161 162 // True for the first packet on sequence. See the comment for 163 // TracePacket.first_packet_on_sequence for more details. 164 bool first_packet_on_sequence_ = true; 165 }; 166 167 } // namespace perfetto 168 169 #endif // SRC_TRACING_CORE_TRACE_WRITER_IMPL_H_ 170