Home | History | Annotate | Download | only in tracing
      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