1// Copyright 2016 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/libplatform/tracing/trace-buffer.h" 6 7namespace v8 { 8namespace platform { 9namespace tracing { 10 11TraceBufferRingBuffer::TraceBufferRingBuffer(size_t max_chunks, 12 TraceWriter* trace_writer) 13 : max_chunks_(max_chunks) { 14 trace_writer_.reset(trace_writer); 15 chunks_.resize(max_chunks); 16} 17 18TraceObject* TraceBufferRingBuffer::AddTraceEvent(uint64_t* handle) { 19 base::MutexGuard guard(&mutex_); 20 if (is_empty_ || chunks_[chunk_index_]->IsFull()) { 21 chunk_index_ = is_empty_ ? 0 : NextChunkIndex(chunk_index_); 22 is_empty_ = false; 23 auto& chunk = chunks_[chunk_index_]; 24 if (chunk) { 25 chunk->Reset(current_chunk_seq_++); 26 } else { 27 chunk.reset(new TraceBufferChunk(current_chunk_seq_++)); 28 } 29 } 30 auto& chunk = chunks_[chunk_index_]; 31 size_t event_index; 32 TraceObject* trace_object = chunk->AddTraceEvent(&event_index); 33 *handle = MakeHandle(chunk_index_, chunk->seq(), event_index); 34 return trace_object; 35} 36 37TraceObject* TraceBufferRingBuffer::GetEventByHandle(uint64_t handle) { 38 base::MutexGuard guard(&mutex_); 39 size_t chunk_index, event_index; 40 uint32_t chunk_seq; 41 ExtractHandle(handle, &chunk_index, &chunk_seq, &event_index); 42 if (chunk_index >= chunks_.size()) return nullptr; 43 auto& chunk = chunks_[chunk_index]; 44 if (!chunk || chunk->seq() != chunk_seq) return nullptr; 45 return chunk->GetEventAt(event_index); 46} 47 48bool TraceBufferRingBuffer::Flush() { 49 base::MutexGuard guard(&mutex_); 50 // This flushes all the traces stored in the buffer. 51 if (!is_empty_) { 52 for (size_t i = NextChunkIndex(chunk_index_);; i = NextChunkIndex(i)) { 53 if (auto& chunk = chunks_[i]) { 54 for (size_t j = 0; j < chunk->size(); ++j) { 55 trace_writer_->AppendTraceEvent(chunk->GetEventAt(j)); 56 } 57 } 58 if (i == chunk_index_) break; 59 } 60 } 61 trace_writer_->Flush(); 62 // This resets the trace buffer. 63 is_empty_ = true; 64 return true; 65} 66 67uint64_t TraceBufferRingBuffer::MakeHandle(size_t chunk_index, 68 uint32_t chunk_seq, 69 size_t event_index) const { 70 return static_cast<uint64_t>(chunk_seq) * Capacity() + 71 chunk_index * TraceBufferChunk::kChunkSize + event_index; 72} 73 74void TraceBufferRingBuffer::ExtractHandle(uint64_t handle, size_t* chunk_index, 75 uint32_t* chunk_seq, 76 size_t* event_index) const { 77 *chunk_seq = static_cast<uint32_t>(handle / Capacity()); 78 size_t indices = handle % Capacity(); 79 *chunk_index = indices / TraceBufferChunk::kChunkSize; 80 *event_index = indices % TraceBufferChunk::kChunkSize; 81} 82 83size_t TraceBufferRingBuffer::NextChunkIndex(size_t index) const { 84 if (++index >= max_chunks_) index = 0; 85 return index; 86} 87 88TraceBufferChunk::TraceBufferChunk(uint32_t seq) : seq_(seq) {} 89 90void TraceBufferChunk::Reset(uint32_t new_seq) { 91 next_free_ = 0; 92 seq_ = new_seq; 93} 94 95TraceObject* TraceBufferChunk::AddTraceEvent(size_t* event_index) { 96 *event_index = next_free_++; 97 return &chunk_[*event_index]; 98} 99 100TraceBuffer* TraceBuffer::CreateTraceBufferRingBuffer( 101 size_t max_chunks, TraceWriter* trace_writer) { 102 return new TraceBufferRingBuffer(max_chunks, trace_writer); 103} 104 105} // namespace tracing 106} // namespace platform 107} // namespace v8 108