blob: 230255fe411951c9d06b8095d43b1246385be034 [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) {
DCHECK(!trace_file_.is_open());
trace_file_.open("v8_perfetto_trace.json");
CHECK(trace_file_.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, this] {
std::unique_ptr<::perfetto::SharedMemory::Factory> shmem_factory =
base::make_unique<PerfettoSharedMemoryFactory>();
service_ = ::perfetto::TracingService::CreateInstance(
std::move(shmem_factory), task_runner_.get());
producer_ = base::make_unique<PerfettoProducer>(this);
consumer_ = base::make_unique<PerfettoJSONConsumer>(
&trace_file_, &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] {
// Causes each thread-local writer to be deleted which will trigger a
// final Flush() on each writer as well.
// TODO(petermarshall): There as a race here where the writer is still being
// used by a thread writing trace events (the thread read the value of
// perfetto_recording_ before it was changed). We either need to synchronize
// all tracing threads here or use TLS destructors like Chrome.
writers_to_finalize_.clear();
// 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();
DCHECK(trace_file_.is_open());
trace_file_.close();
}
PerfettoTracingController::~PerfettoTracingController() {
base::Thread::DeleteThreadLocalKey(writer_key_);
}
::perfetto::TraceWriter*
PerfettoTracingController::GetOrCreateThreadLocalWriter() {
if (base::Thread::HasThreadLocal(writer_key_)) {
return static_cast<::perfetto::TraceWriter*>(
base::Thread::GetExistingThreadLocal(writer_key_));
}
std::unique_ptr<::perfetto::TraceWriter> tw = producer_->CreateTraceWriter();
::perfetto::TraceWriter* writer = tw.get();
// We don't have thread-local storage destructors but we need to delete each
// thread local TraceWriter, so that they can release the trace buffer chunks
// they are holding on to. To do this, we keep a vector of all writers that we
// create so they can be deleted when tracing is stopped.
{
base::MutexGuard guard(&writers_mutex_);
writers_to_finalize_.push_back(std::move(tw));
}
base::Thread::SetThreadLocal(writer_key_, writer);
return writer;
}
void PerfettoTracingController::OnProducerReady() {
producer_ready_semaphore_.Signal();
}
} // namespace tracing
} // namespace platform
} // namespace v8