blob: 1a4f1595929ed6585a69d3b6c9e2ef438ddf90b6 [file] [log] [blame]
// 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-json-consumer.h"
#include "src/libplatform/tracing/perfetto-producer.h"
#include "src/libplatform/tracing/perfetto-shared-memory.h"
#include "src/libplatform/tracing/perfetto-tasks.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, std::ostream* output_stream) {
DCHECK_NOT_NULL(output_stream);
DCHECK(output_stream->good());
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, output_stream, 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<PerfettoJSONConsumer>(
output_stream, &consumer_finished_semaphore_);
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
// PerfettoJSONConsumer::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();
}
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