123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- // Copyright 2015 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/trace_event/trace_buffer.h"
- #include <memory>
- #include <utility>
- #include <vector>
- #include "base/bind.h"
- #include "base/trace_event/heap_profiler.h"
- #include "base/trace_event/trace_event_impl.h"
- namespace base {
- namespace trace_event {
- namespace {
- class TraceBufferRingBuffer : public TraceBuffer {
- public:
- TraceBufferRingBuffer(size_t max_chunks)
- : max_chunks_(max_chunks),
- recyclable_chunks_queue_(new size_t[queue_capacity()]),
- queue_head_(0),
- queue_tail_(max_chunks),
- current_iteration_index_(0),
- current_chunk_seq_(1) {
- chunks_.reserve(max_chunks);
- for (size_t i = 0; i < max_chunks; ++i)
- recyclable_chunks_queue_[i] = i;
- }
- TraceBufferRingBuffer(const TraceBufferRingBuffer&) = delete;
- TraceBufferRingBuffer& operator=(const TraceBufferRingBuffer&) = delete;
- std::unique_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
- HEAP_PROFILER_SCOPED_IGNORE;
- // Because the number of threads is much less than the number of chunks,
- // the queue should never be empty.
- DCHECK(!QueueIsEmpty());
- *index = recyclable_chunks_queue_[queue_head_];
- queue_head_ = NextQueueIndex(queue_head_);
- current_iteration_index_ = queue_head_;
- if (*index >= chunks_.size())
- chunks_.resize(*index + 1);
- TraceBufferChunk* chunk = chunks_[*index].release();
- chunks_[*index] = nullptr; // Put nullptr in the slot of a in-flight chunk.
- if (chunk)
- chunk->Reset(current_chunk_seq_++);
- else
- chunk = new TraceBufferChunk(current_chunk_seq_++);
- return std::unique_ptr<TraceBufferChunk>(chunk);
- }
- void ReturnChunk(size_t index,
- std::unique_ptr<TraceBufferChunk> chunk) override {
- // When this method is called, the queue should not be full because it
- // can contain all chunks including the one to be returned.
- DCHECK(!QueueIsFull());
- DCHECK(chunk);
- DCHECK_LT(index, chunks_.size());
- DCHECK(!chunks_[index]);
- chunks_[index] = std::move(chunk);
- recyclable_chunks_queue_[queue_tail_] = index;
- queue_tail_ = NextQueueIndex(queue_tail_);
- }
- bool IsFull() const override { return false; }
- size_t Size() const override {
- // This is approximate because not all of the chunks are full.
- return chunks_.size() * TraceBufferChunk::kTraceBufferChunkSize;
- }
- size_t Capacity() const override {
- return max_chunks_ * TraceBufferChunk::kTraceBufferChunkSize;
- }
- TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
- if (handle.chunk_index >= chunks_.size())
- return nullptr;
- TraceBufferChunk* chunk = chunks_[handle.chunk_index].get();
- if (!chunk || chunk->seq() != handle.chunk_seq)
- return nullptr;
- return chunk->GetEventAt(handle.event_index);
- }
- const TraceBufferChunk* NextChunk() override {
- if (chunks_.empty())
- return nullptr;
- while (current_iteration_index_ != queue_tail_) {
- size_t chunk_index = recyclable_chunks_queue_[current_iteration_index_];
- current_iteration_index_ = NextQueueIndex(current_iteration_index_);
- if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
- continue;
- DCHECK(chunks_[chunk_index]);
- return chunks_[chunk_index].get();
- }
- return nullptr;
- }
- void EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) override {
- overhead->Add(TraceEventMemoryOverhead::kTraceBuffer, sizeof(*this));
- for (size_t queue_index = queue_head_; queue_index != queue_tail_;
- queue_index = NextQueueIndex(queue_index)) {
- size_t chunk_index = recyclable_chunks_queue_[queue_index];
- if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
- continue;
- chunks_[chunk_index]->EstimateTraceMemoryOverhead(overhead);
- }
- }
- private:
- bool QueueIsEmpty() const { return queue_head_ == queue_tail_; }
- size_t QueueSize() const {
- return queue_tail_ > queue_head_
- ? queue_tail_ - queue_head_
- : queue_tail_ + queue_capacity() - queue_head_;
- }
- bool QueueIsFull() const { return QueueSize() == queue_capacity() - 1; }
- size_t queue_capacity() const {
- // One extra space to help distinguish full state and empty state.
- return max_chunks_ + 1;
- }
- size_t NextQueueIndex(size_t index) const {
- index++;
- if (index >= queue_capacity())
- index = 0;
- return index;
- }
- size_t max_chunks_;
- std::vector<std::unique_ptr<TraceBufferChunk>> chunks_;
- std::unique_ptr<size_t[]> recyclable_chunks_queue_;
- size_t queue_head_;
- size_t queue_tail_;
- size_t current_iteration_index_;
- uint32_t current_chunk_seq_;
- };
- class TraceBufferVector : public TraceBuffer {
- public:
- TraceBufferVector(size_t max_chunks)
- : in_flight_chunk_count_(0),
- current_iteration_index_(0),
- max_chunks_(max_chunks) {
- chunks_.reserve(max_chunks_);
- }
- TraceBufferVector(const TraceBufferVector&) = delete;
- TraceBufferVector& operator=(const TraceBufferVector&) = delete;
- std::unique_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
- HEAP_PROFILER_SCOPED_IGNORE;
- // This function may be called when adding normal events or indirectly from
- // AddMetadataEventsWhileLocked(). We can not DECHECK(!IsFull()) because we
- // have to add the metadata events and flush thread-local buffers even if
- // the buffer is full.
- *index = chunks_.size();
- // Put nullptr in the slot of a in-flight chunk.
- chunks_.push_back(nullptr);
- ++in_flight_chunk_count_;
- // + 1 because zero chunk_seq is not allowed.
- return std::make_unique<TraceBufferChunk>(static_cast<uint32_t>(*index) +
- 1);
- }
- void ReturnChunk(size_t index,
- std::unique_ptr<TraceBufferChunk> chunk) override {
- DCHECK_GT(in_flight_chunk_count_, 0u);
- DCHECK_LT(index, chunks_.size());
- DCHECK(!chunks_[index]);
- --in_flight_chunk_count_;
- chunks_[index] = std::move(chunk);
- }
- bool IsFull() const override { return chunks_.size() >= max_chunks_; }
- size_t Size() const override {
- // This is approximate because not all of the chunks are full.
- return chunks_.size() * TraceBufferChunk::kTraceBufferChunkSize;
- }
- size_t Capacity() const override {
- return max_chunks_ * TraceBufferChunk::kTraceBufferChunkSize;
- }
- TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
- if (handle.chunk_index >= chunks_.size())
- return nullptr;
- TraceBufferChunk* chunk = chunks_[handle.chunk_index].get();
- if (!chunk || chunk->seq() != handle.chunk_seq)
- return nullptr;
- return chunk->GetEventAt(handle.event_index);
- }
- const TraceBufferChunk* NextChunk() override {
- while (current_iteration_index_ < chunks_.size()) {
- // Skip in-flight chunks.
- const TraceBufferChunk* chunk = chunks_[current_iteration_index_++].get();
- if (chunk)
- return chunk;
- }
- return nullptr;
- }
- void EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) override {
- const size_t chunks_ptr_vector_allocated_size =
- sizeof(*this) + max_chunks_ * sizeof(decltype(chunks_)::value_type);
- const size_t chunks_ptr_vector_resident_size =
- sizeof(*this) + chunks_.size() * sizeof(decltype(chunks_)::value_type);
- overhead->Add(TraceEventMemoryOverhead::kTraceBuffer,
- chunks_ptr_vector_allocated_size,
- chunks_ptr_vector_resident_size);
- for (size_t i = 0; i < chunks_.size(); ++i) {
- TraceBufferChunk* chunk = chunks_[i].get();
- // Skip the in-flight (nullptr) chunks. They will be accounted by the
- // per-thread-local dumpers, see ThreadLocalEventBuffer::OnMemoryDump.
- if (chunk)
- chunk->EstimateTraceMemoryOverhead(overhead);
- }
- }
- private:
- size_t in_flight_chunk_count_;
- size_t current_iteration_index_;
- size_t max_chunks_;
- std::vector<std::unique_ptr<TraceBufferChunk>> chunks_;
- };
- } // namespace
- TraceBufferChunk::TraceBufferChunk(uint32_t seq) : next_free_(0), seq_(seq) {}
- TraceBufferChunk::~TraceBufferChunk() = default;
- void TraceBufferChunk::Reset(uint32_t new_seq) {
- for (size_t i = 0; i < next_free_; ++i)
- chunk_[i].Reset();
- next_free_ = 0;
- seq_ = new_seq;
- cached_overhead_estimate_.reset();
- }
- TraceEvent* TraceBufferChunk::AddTraceEvent(size_t* event_index) {
- DCHECK(!IsFull());
- *event_index = next_free_++;
- return &chunk_[*event_index];
- }
- void TraceBufferChunk::EstimateTraceMemoryOverhead(
- TraceEventMemoryOverhead* overhead) {
- if (!cached_overhead_estimate_) {
- cached_overhead_estimate_ = std::make_unique<TraceEventMemoryOverhead>();
- // When estimating the size of TraceBufferChunk, exclude the array of trace
- // events, as they are computed individually below.
- cached_overhead_estimate_->Add(TraceEventMemoryOverhead::kTraceBufferChunk,
- sizeof(*this) - sizeof(chunk_));
- }
- const size_t num_cached_estimated_events =
- cached_overhead_estimate_->GetCount(
- TraceEventMemoryOverhead::kTraceEvent);
- DCHECK_LE(num_cached_estimated_events, size());
- if (IsFull() && num_cached_estimated_events == size()) {
- overhead->Update(*cached_overhead_estimate_);
- return;
- }
- for (size_t i = num_cached_estimated_events; i < size(); ++i)
- chunk_[i].EstimateTraceMemoryOverhead(cached_overhead_estimate_.get());
- if (IsFull()) {
- cached_overhead_estimate_->AddSelf();
- } else {
- // The unused TraceEvents in |chunks_| are not cached. They will keep
- // changing as new TraceEvents are added to this chunk, so they are
- // computed on the fly.
- const size_t num_unused_trace_events = capacity() - size();
- overhead->Add(TraceEventMemoryOverhead::kUnusedTraceEvent,
- num_unused_trace_events * sizeof(TraceEvent));
- }
- overhead->Update(*cached_overhead_estimate_);
- }
- TraceResultBuffer::OutputCallback
- TraceResultBuffer::SimpleOutput::GetCallback() {
- return BindRepeating(&SimpleOutput::Append, Unretained(this));
- }
- void TraceResultBuffer::SimpleOutput::Append(
- const std::string& json_trace_output) {
- json_output += json_trace_output;
- }
- TraceResultBuffer::TraceResultBuffer() : append_comma_(false) {}
- TraceResultBuffer::~TraceResultBuffer() = default;
- void TraceResultBuffer::SetOutputCallback(OutputCallback json_chunk_callback) {
- output_callback_ = std::move(json_chunk_callback);
- }
- void TraceResultBuffer::Start() {
- append_comma_ = false;
- output_callback_.Run("[");
- }
- void TraceResultBuffer::AddFragment(const std::string& trace_fragment) {
- if (append_comma_)
- output_callback_.Run(",");
- append_comma_ = true;
- output_callback_.Run(trace_fragment);
- }
- void TraceResultBuffer::Finish() {
- output_callback_.Run("]");
- }
- TraceBuffer* TraceBuffer::CreateTraceBufferRingBuffer(size_t max_chunks) {
- return new TraceBufferRingBuffer(max_chunks);
- }
- TraceBuffer* TraceBuffer::CreateTraceBufferVectorOfSize(size_t max_chunks) {
- return new TraceBufferVector(max_chunks);
- }
- } // namespace trace_event
- } // namespace base
|