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 7 namespace v8 { 8 namespace platform { 9 namespace tracing { 10 11 TraceBufferRingBuffer::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 18 TraceBufferRingBuffer::~TraceBufferRingBuffer() {} 19 20 TraceObject* TraceBufferRingBuffer::AddTraceEvent(uint64_t* handle) { 21 base::LockGuard<base::Mutex> guard(&mutex_); 22 if (is_empty_ || chunks_[chunk_index_]->IsFull()) { 23 chunk_index_ = is_empty_ ? 0 : NextChunkIndex(chunk_index_); 24 is_empty_ = false; 25 auto& chunk = chunks_[chunk_index_]; 26 if (chunk) { 27 chunk->Reset(current_chunk_seq_++); 28 } else { 29 chunk.reset(new TraceBufferChunk(current_chunk_seq_++)); 30 } 31 } 32 auto& chunk = chunks_[chunk_index_]; 33 size_t event_index; 34 TraceObject* trace_object = chunk->AddTraceEvent(&event_index); 35 *handle = MakeHandle(chunk_index_, chunk->seq(), event_index); 36 return trace_object; 37 } 38 39 TraceObject* TraceBufferRingBuffer::GetEventByHandle(uint64_t handle) { 40 base::LockGuard<base::Mutex> guard(&mutex_); 41 size_t chunk_index, event_index; 42 uint32_t chunk_seq; 43 ExtractHandle(handle, &chunk_index, &chunk_seq, &event_index); 44 if (chunk_index >= chunks_.size()) return NULL; 45 auto& chunk = chunks_[chunk_index]; 46 if (!chunk || chunk->seq() != chunk_seq) return NULL; 47 return chunk->GetEventAt(event_index); 48 } 49 50 bool TraceBufferRingBuffer::Flush() { 51 base::LockGuard<base::Mutex> guard(&mutex_); 52 // This flushes all the traces stored in the buffer. 53 if (!is_empty_) { 54 for (size_t i = NextChunkIndex(chunk_index_);; i = NextChunkIndex(i)) { 55 if (auto& chunk = chunks_[i]) { 56 for (size_t j = 0; j < chunk->size(); ++j) { 57 trace_writer_->AppendTraceEvent(chunk->GetEventAt(j)); 58 } 59 } 60 if (i == chunk_index_) break; 61 } 62 } 63 trace_writer_->Flush(); 64 // This resets the trace buffer. 65 is_empty_ = true; 66 return true; 67 } 68 69 uint64_t TraceBufferRingBuffer::MakeHandle(size_t chunk_index, 70 uint32_t chunk_seq, 71 size_t event_index) const { 72 return static_cast<uint64_t>(chunk_seq) * Capacity() + 73 chunk_index * TraceBufferChunk::kChunkSize + event_index; 74 } 75 76 void TraceBufferRingBuffer::ExtractHandle(uint64_t handle, size_t* chunk_index, 77 uint32_t* chunk_seq, 78 size_t* event_index) const { 79 *chunk_seq = static_cast<uint32_t>(handle / Capacity()); 80 size_t indices = handle % Capacity(); 81 *chunk_index = indices / TraceBufferChunk::kChunkSize; 82 *event_index = indices % TraceBufferChunk::kChunkSize; 83 } 84 85 size_t TraceBufferRingBuffer::NextChunkIndex(size_t index) const { 86 if (++index >= max_chunks_) index = 0; 87 return index; 88 } 89 90 TraceBufferChunk::TraceBufferChunk(uint32_t seq) : seq_(seq) {} 91 92 void TraceBufferChunk::Reset(uint32_t new_seq) { 93 next_free_ = 0; 94 seq_ = new_seq; 95 } 96 97 TraceObject* TraceBufferChunk::AddTraceEvent(size_t* event_index) { 98 *event_index = next_free_++; 99 return &chunk_[*event_index]; 100 } 101 102 TraceBuffer* TraceBuffer::CreateTraceBufferRingBuffer( 103 size_t max_chunks, TraceWriter* trace_writer) { 104 return new TraceBufferRingBuffer(max_chunks, trace_writer); 105 } 106 107 } // namespace tracing 108 } // namespace platform 109 } // namespace v8 110