summaryrefslogtreecommitdiff
path: root/chromium/v8/src/libplatform/tracing/perfetto-tracing-controller.cc
blob: 9b62c2ae78cd2b7204151617ce63eea2dcab4a42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2019 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/perfetto-tracing-controller.h"

#include "perfetto/tracing/core/trace_config.h"
#include "perfetto/tracing/core/trace_writer.h"
#include "perfetto/tracing/core/tracing_service.h"
#include "src/libplatform/tracing/perfetto-consumer.h"
#include "src/libplatform/tracing/perfetto-producer.h"
#include "src/libplatform/tracing/perfetto-shared-memory.h"
#include "src/libplatform/tracing/perfetto-tasks.h"
#include "src/libplatform/tracing/trace-event-listener.h"

namespace v8 {
namespace platform {
namespace tracing {

PerfettoTracingController::PerfettoTracingController()
    : writer_key_(base::Thread::CreateThreadLocalKey()),
      producer_ready_semaphore_(0),
      consumer_finished_semaphore_(0) {}

void PerfettoTracingController::StartTracing(
    const ::perfetto::TraceConfig& trace_config) {
  DCHECK(!task_runner_);
  task_runner_ = base::make_unique<PerfettoTaskRunner>();
  // The Perfetto service expects calls on the task runner thread which is why
  // the setup below occurs in posted tasks.
  task_runner_->PostTask([&trace_config, this] {
    std::unique_ptr<::perfetto::SharedMemory::Factory> shmem_factory =
        base::make_unique<PerfettoSharedMemoryFactory>();

    service_ = ::perfetto::TracingService::CreateInstance(
        std::move(shmem_factory), task_runner_.get());
    // This allows Perfetto to recover trace events that were written by
    // TraceWriters which have not yet been deleted. This allows us to keep
    // TraceWriters alive past the end of tracing, rather than having to delete
    // them all when tracing stops which would require synchronization on every
    // trace event. Eventually we will delete TraceWriters when threads die, but
    // for now we just leak all TraceWriters.
    service_->SetSMBScrapingEnabled(true);
    producer_ = base::make_unique<PerfettoProducer>(this);
    consumer_ =
        base::make_unique<PerfettoConsumer>(&consumer_finished_semaphore_);

    for (TraceEventListener* listener : listeners_) {
      consumer_->AddTraceEventListener(listener);
    }

    producer_->set_service_endpoint(service_->ConnectProducer(
        producer_.get(), 0, "v8.perfetto-producer", 0, true));

    consumer_->set_service_endpoint(
        service_->ConnectConsumer(consumer_.get(), 0));

    // We need to wait for the OnConnected() callbacks of the producer and
    // consumer to be called.
    consumer_->service_endpoint()->EnableTracing(trace_config);
  });

  producer_ready_semaphore_.Wait();
}

void PerfettoTracingController::StopTracing() {
  // Finish all of the tasks such as existing AddTraceEvent calls. These
  // require the data structures below to work properly, so keep them alive
  // until the tasks are done.
  task_runner_->FinishImmediateTasks();

  task_runner_->PostTask([this] {
    // Trigger shared memory buffer scraping which will get all pending trace
    // events that have been written by still-living TraceWriters.
    consumer_->service_endpoint()->DisableTracing();
    // Trigger the consumer to finish. This can trigger multiple calls to
    // PerfettoConsumer::OnTraceData(), with the final call passing has_more
    // as false.
    consumer_->service_endpoint()->ReadBuffers();
  });

  // Wait until the final OnTraceData() call with has_more=false has completed.
  consumer_finished_semaphore_.Wait();

  task_runner_->PostTask([this] {
    consumer_.reset();
    producer_.reset();
    service_.reset();
  });

  // Finish the above task, and any callbacks that were triggered.
  task_runner_->FinishImmediateTasks();
  task_runner_.reset();
}

void PerfettoTracingController::AddTraceEventListener(
    TraceEventListener* listener) {
  listeners_.push_back(listener);
}

PerfettoTracingController::~PerfettoTracingController() {
  base::Thread::DeleteThreadLocalKey(writer_key_);
}

::perfetto::TraceWriter*
PerfettoTracingController::GetOrCreateThreadLocalWriter() {
  // TODO(petermarshall): Use some form of thread-local destructor so that
  // repeatedly created threads don't cause excessive leaking of TraceWriters.
  if (base::Thread::HasThreadLocal(writer_key_)) {
    return static_cast<::perfetto::TraceWriter*>(
        base::Thread::GetExistingThreadLocal(writer_key_));
  }

  // We leak the TraceWriter objects created for each thread. Perfetto has a
  // way of getting events from leaked TraceWriters and we can avoid needing a
  // lock on every trace event this way.
  std::unique_ptr<::perfetto::TraceWriter> tw = producer_->CreateTraceWriter();
  ::perfetto::TraceWriter* writer = tw.release();

  base::Thread::SetThreadLocal(writer_key_, writer);
  return writer;
}

void PerfettoTracingController::OnProducerReady() {
  producer_ready_semaphore_.Signal();
}

}  // namespace tracing
}  // namespace platform
}  // namespace v8