// Copyright 2016 the V8 project 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 "src/libplatform/tracing/trace-buffer.h" namespace v8 { namespace platform { namespace tracing { TraceBufferRingBuffer::TraceBufferRingBuffer(size_t max_chunks, TraceWriter* trace_writer) : max_chunks_(max_chunks) { trace_writer_.reset(trace_writer); chunks_.resize(max_chunks); } TraceBufferRingBuffer::~TraceBufferRingBuffer() {} TraceObject* TraceBufferRingBuffer::AddTraceEvent(uint64_t* handle) { base::LockGuard<base::Mutex> guard(&mutex_); if (is_empty_ || chunks_[chunk_index_]->IsFull()) { chunk_index_ = is_empty_ ? 0 : NextChunkIndex(chunk_index_); is_empty_ = false; auto& chunk = chunks_[chunk_index_]; if (chunk) { chunk->Reset(current_chunk_seq_++); } else { chunk.reset(new TraceBufferChunk(current_chunk_seq_++)); } } auto& chunk = chunks_[chunk_index_]; size_t event_index; TraceObject* trace_object = chunk->AddTraceEvent(&event_index); *handle = MakeHandle(chunk_index_, chunk->seq(), event_index); return trace_object; } TraceObject* TraceBufferRingBuffer::GetEventByHandle(uint64_t handle) { base::LockGuard<base::Mutex> guard(&mutex_); size_t chunk_index, event_index; uint32_t chunk_seq; ExtractHandle(handle, &chunk_index, &chunk_seq, &event_index); if (chunk_index >= chunks_.size()) return NULL; auto& chunk = chunks_[chunk_index]; if (!chunk || chunk->seq() != chunk_seq) return NULL; return chunk->GetEventAt(event_index); } bool TraceBufferRingBuffer::Flush() { base::LockGuard<base::Mutex> guard(&mutex_); // This flushes all the traces stored in the buffer. if (!is_empty_) { for (size_t i = NextChunkIndex(chunk_index_);; i = NextChunkIndex(i)) { if (auto& chunk = chunks_[i]) { for (size_t j = 0; j < chunk->size(); ++j) { trace_writer_->AppendTraceEvent(chunk->GetEventAt(j)); } } if (i == chunk_index_) break; } } trace_writer_->Flush(); // This resets the trace buffer. is_empty_ = true; return true; } uint64_t TraceBufferRingBuffer::MakeHandle(size_t chunk_index, uint32_t chunk_seq, size_t event_index) const { return static_cast<uint64_t>(chunk_seq) * Capacity() + chunk_index * TraceBufferChunk::kChunkSize + event_index; } void TraceBufferRingBuffer::ExtractHandle(uint64_t handle, size_t* chunk_index, uint32_t* chunk_seq, size_t* event_index) const { *chunk_seq = static_cast<uint32_t>(handle / Capacity()); size_t indices = handle % Capacity(); *chunk_index = indices / TraceBufferChunk::kChunkSize; *event_index = indices % TraceBufferChunk::kChunkSize; } size_t TraceBufferRingBuffer::NextChunkIndex(size_t index) const { if (++index >= max_chunks_) index = 0; return index; } TraceBufferChunk::TraceBufferChunk(uint32_t seq) : seq_(seq) {} void TraceBufferChunk::Reset(uint32_t new_seq) { next_free_ = 0; seq_ = new_seq; } TraceObject* TraceBufferChunk::AddTraceEvent(size_t* event_index) { *event_index = next_free_++; return &chunk_[*event_index]; } TraceBuffer* TraceBuffer::CreateTraceBufferRingBuffer( size_t max_chunks, TraceWriter* trace_writer) { return new TraceBufferRingBuffer(max_chunks, trace_writer); } } // namespace tracing } // namespace platform } // namespace v8