Commit a03ed626 authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

[tracing] Add a configurable output stream for perfetto tracing

Add the ability to provide perfetto with an output stream for the JSON
consumer rather than hardcode it. D8 will use this interface exclusively
once the old trace controller is removed.

Also add a test for scope-managed trace events and their duration - this
was leftover from a previous CL.

Cq-Include-Trybots: luci.v8.try:v8_linux64_perfetto_dbg_ng
Bug: v8:8339
Change-Id: I1c45e17e528b549a4cfdaecabd33c7ac4ab4af77
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1611801Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61753}
parent d56ee2e3
...@@ -240,6 +240,11 @@ class V8_PLATFORM_EXPORT TracingController ...@@ -240,6 +240,11 @@ class V8_PLATFORM_EXPORT TracingController
TracingController(); TracingController();
~TracingController() override; ~TracingController() override;
void Initialize(TraceBuffer* trace_buffer); void Initialize(TraceBuffer* trace_buffer);
#ifdef V8_USE_PERFETTO
// Must be called before StartTracing() if V8_USE_PERFETTO is true. Provides
// the output stream for the JSON trace data.
void InitializeForPerfetto(std::ostream* output_stream);
#endif
// v8::TracingController implementation. // v8::TracingController implementation.
const uint8_t* GetCategoryGroupEnabled(const char* category_group) override; const uint8_t* GetCategoryGroupEnabled(const char* category_group) override;
...@@ -285,6 +290,7 @@ class V8_PLATFORM_EXPORT TracingController ...@@ -285,6 +290,7 @@ class V8_PLATFORM_EXPORT TracingController
#ifdef V8_USE_PERFETTO #ifdef V8_USE_PERFETTO
std::atomic_bool perfetto_recording_{false}; std::atomic_bool perfetto_recording_{false};
std::unique_ptr<PerfettoTracingController> perfetto_tracing_controller_; std::unique_ptr<PerfettoTracingController> perfetto_tracing_controller_;
std::ostream* output_stream_ = nullptr;
#endif #endif
// Disallow copy and assign // Disallow copy and assign
......
...@@ -3323,7 +3323,6 @@ void Shell::CleanupWorkers() { ...@@ -3323,7 +3323,6 @@ void Shell::CleanupWorkers() {
} }
int Shell::Main(int argc, char* argv[]) { int Shell::Main(int argc, char* argv[]) {
std::ofstream trace_file;
v8::base::EnsureConsoleOutput(); v8::base::EnsureConsoleOutput();
if (!SetOptions(argc, argv)) return 1; if (!SetOptions(argc, argv)) return 1;
v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file); v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file);
...@@ -3334,15 +3333,26 @@ int Shell::Main(int argc, char* argv[]) { ...@@ -3334,15 +3333,26 @@ int Shell::Main(int argc, char* argv[]) {
: v8::platform::InProcessStackDumping::kEnabled; : v8::platform::InProcessStackDumping::kEnabled;
std::unique_ptr<platform::tracing::TracingController> tracing; std::unique_ptr<platform::tracing::TracingController> tracing;
std::ofstream trace_file;
#ifdef V8_USE_PERFETTO
std::ofstream perfetto_trace_file;
#endif // V8_USE_PERFETTO
if (options.trace_enabled && !i::FLAG_verify_predictable) { if (options.trace_enabled && !i::FLAG_verify_predictable) {
tracing = base::make_unique<platform::tracing::TracingController>(); tracing = base::make_unique<platform::tracing::TracingController>();
trace_file.open(options.trace_path ? options.trace_path : "v8_trace.json"); trace_file.open(options.trace_path ? options.trace_path : "v8_trace.json");
DCHECK(trace_file.good());
platform::tracing::TraceBuffer* trace_buffer = platform::tracing::TraceBuffer* trace_buffer =
platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer( platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer(
platform::tracing::TraceBuffer::kRingBufferChunks, platform::tracing::TraceBuffer::kRingBufferChunks,
platform::tracing::TraceWriter::CreateJSONTraceWriter(trace_file)); platform::tracing::TraceWriter::CreateJSONTraceWriter(trace_file));
tracing->Initialize(trace_buffer); tracing->Initialize(trace_buffer);
#ifdef V8_USE_PERFETTO
perfetto_trace_file.open("v8_perfetto_trace.json");
DCHECK(trace_file.good());
tracing->InitializeForPerfetto(&perfetto_trace_file);
#endif // V8_USE_PERFETTO
} }
platform::tracing::TracingController* tracing_controller = tracing.get(); platform::tracing::TracingController* tracing_controller = tracing.get();
...@@ -3529,6 +3539,9 @@ int Shell::Main(int argc, char* argv[]) { ...@@ -3529,6 +3539,9 @@ int Shell::Main(int argc, char* argv[]) {
// Delete the platform explicitly here to write the tracing output to the // Delete the platform explicitly here to write the tracing output to the
// tracing file. // tracing file.
if (options.trace_enabled) {
tracing_controller->StopTracing();
}
g_platform.reset(); g_platform.reset();
return result; return result;
} }
......
...@@ -22,16 +22,15 @@ PerfettoTracingController::PerfettoTracingController() ...@@ -22,16 +22,15 @@ PerfettoTracingController::PerfettoTracingController()
consumer_finished_semaphore_(0) {} consumer_finished_semaphore_(0) {}
void PerfettoTracingController::StartTracing( void PerfettoTracingController::StartTracing(
const ::perfetto::TraceConfig& trace_config) { const ::perfetto::TraceConfig& trace_config, std::ostream* output_stream) {
DCHECK(!trace_file_.is_open()); DCHECK_NOT_NULL(output_stream);
trace_file_.open("v8_perfetto_trace.json"); DCHECK(output_stream->good());
CHECK(trace_file_.good());
DCHECK(!task_runner_); DCHECK(!task_runner_);
task_runner_ = base::make_unique<PerfettoTaskRunner>(); task_runner_ = base::make_unique<PerfettoTaskRunner>();
// The Perfetto service expects calls on the task runner thread which is why // The Perfetto service expects calls on the task runner thread which is why
// the setup below occurs in posted tasks. // the setup below occurs in posted tasks.
task_runner_->PostTask([&trace_config, this] { task_runner_->PostTask([&trace_config, output_stream, this] {
std::unique_ptr<::perfetto::SharedMemory::Factory> shmem_factory = std::unique_ptr<::perfetto::SharedMemory::Factory> shmem_factory =
base::make_unique<PerfettoSharedMemoryFactory>(); base::make_unique<PerfettoSharedMemoryFactory>();
...@@ -46,7 +45,7 @@ void PerfettoTracingController::StartTracing( ...@@ -46,7 +45,7 @@ void PerfettoTracingController::StartTracing(
service_->SetSMBScrapingEnabled(true); service_->SetSMBScrapingEnabled(true);
producer_ = base::make_unique<PerfettoProducer>(this); producer_ = base::make_unique<PerfettoProducer>(this);
consumer_ = base::make_unique<PerfettoJSONConsumer>( consumer_ = base::make_unique<PerfettoJSONConsumer>(
&trace_file_, &consumer_finished_semaphore_); output_stream, &consumer_finished_semaphore_);
producer_->set_service_endpoint(service_->ConnectProducer( producer_->set_service_endpoint(service_->ConnectProducer(
producer_.get(), 0, "v8.perfetto-producer", 0, true)); producer_.get(), 0, "v8.perfetto-producer", 0, true));
...@@ -90,9 +89,6 @@ void PerfettoTracingController::StopTracing() { ...@@ -90,9 +89,6 @@ void PerfettoTracingController::StopTracing() {
// Finish the above task, and any callbacks that were triggered. // Finish the above task, and any callbacks that were triggered.
task_runner_->FinishImmediateTasks(); task_runner_->FinishImmediateTasks();
task_runner_.reset(); task_runner_.reset();
DCHECK(trace_file_.is_open());
trace_file_.close();
} }
PerfettoTracingController::~PerfettoTracingController() { PerfettoTracingController::~PerfettoTracingController() {
......
...@@ -37,8 +37,10 @@ class PerfettoTracingController { ...@@ -37,8 +37,10 @@ class PerfettoTracingController {
// Blocks and sets up all required data structures for tracing. It is safe to // Blocks and sets up all required data structures for tracing. It is safe to
// call GetOrCreateThreadLocalWriter() to obtain thread-local TraceWriters for // call GetOrCreateThreadLocalWriter() to obtain thread-local TraceWriters for
// writing trace events once this call returns. // writing trace events once this call returns. Tracing output will be sent in
void StartTracing(const ::perfetto::TraceConfig& trace_config); // JSON format to |output_stream|.
void StartTracing(const ::perfetto::TraceConfig& trace_config,
std::ostream* output_stream);
// Blocks and finishes all existing AddTraceEvent tasks. Stops the tracing // Blocks and finishes all existing AddTraceEvent tasks. Stops the tracing
// thread. // thread.
...@@ -68,9 +70,6 @@ class PerfettoTracingController { ...@@ -68,9 +70,6 @@ class PerfettoTracingController {
base::Semaphore producer_ready_semaphore_; base::Semaphore producer_ready_semaphore_;
base::Semaphore consumer_finished_semaphore_; base::Semaphore consumer_finished_semaphore_;
// TODO(petermarshall): pass this in instead.
std::ofstream trace_file_;
DISALLOW_COPY_AND_ASSIGN(PerfettoTracingController); DISALLOW_COPY_AND_ASSIGN(PerfettoTracingController);
}; };
......
...@@ -73,6 +73,14 @@ void TracingController::Initialize(TraceBuffer* trace_buffer) { ...@@ -73,6 +73,14 @@ void TracingController::Initialize(TraceBuffer* trace_buffer) {
mutex_.reset(new base::Mutex()); mutex_.reset(new base::Mutex());
} }
#ifdef V8_USE_PERFETTO
void TracingController::InitializeForPerfetto(std::ostream* output_stream) {
output_stream_ = output_stream;
DCHECK_NOT_NULL(output_stream);
DCHECK(output_stream->good());
}
#endif
int64_t TracingController::CurrentTimestampMicroseconds() { int64_t TracingController::CurrentTimestampMicroseconds() {
return base::TimeTicks::HighResolutionNow().ToInternalValue(); return base::TimeTicks::HighResolutionNow().ToInternalValue();
} }
...@@ -271,8 +279,12 @@ void TracingController::StartTracing(TraceConfig* trace_config) { ...@@ -271,8 +279,12 @@ void TracingController::StartTracing(TraceConfig* trace_config) {
auto* ds_config = perfetto_trace_config.add_data_sources()->mutable_config(); auto* ds_config = perfetto_trace_config.add_data_sources()->mutable_config();
ds_config->set_name("v8.trace_events"); ds_config->set_name("v8.trace_events");
DCHECK_NOT_NULL(output_stream_);
DCHECK(output_stream_->good());
// TODO(petermarshall): Set all the params from |perfetto_trace_config|. // TODO(petermarshall): Set all the params from |perfetto_trace_config|.
perfetto_tracing_controller_->StartTracing(perfetto_trace_config); perfetto_tracing_controller_->StartTracing(perfetto_trace_config,
output_stream_);
perfetto_recording_.store(true); perfetto_recording_.store(true);
#endif // V8_USE_PERFETTO #endif // V8_USE_PERFETTO
......
...@@ -81,6 +81,20 @@ class MockTraceWriter : public TraceWriter { ...@@ -81,6 +81,20 @@ class MockTraceWriter : public TraceWriter {
std::vector<std::string> events_; std::vector<std::string> events_;
}; };
class MockTraceWriterFullTraceObject : public TraceWriter {
public:
void AppendTraceEvent(TraceObject* trace_event) override {
events_.push_back(trace_event);
}
void Flush() override {}
const std::vector<TraceObject*>& events() const { return events_; }
private:
std::vector<TraceObject*> events_;
};
TEST(TestTraceBufferRingBuffer) { TEST(TestTraceBufferRingBuffer) {
// We should be able to add kChunkSize * 2 + 1 trace events. // We should be able to add kChunkSize * 2 + 1 trace events.
const int HANDLES_COUNT = TraceBufferChunk::kChunkSize * 2 + 1; const int HANDLES_COUNT = TraceBufferChunk::kChunkSize * 2 + 1;
...@@ -144,6 +158,10 @@ void PopulateJSONWriter(TraceWriter* writer) { ...@@ -144,6 +158,10 @@ void PopulateJSONWriter(TraceWriter* writer) {
TraceBuffer* ring_buffer = TraceBuffer* ring_buffer =
TraceBuffer::CreateTraceBufferRingBuffer(1, writer); TraceBuffer::CreateTraceBufferRingBuffer(1, writer);
tracing_controller->Initialize(ring_buffer); tracing_controller->Initialize(ring_buffer);
#ifdef V8_USE_PERFETTO
std::ostringstream sstream;
tracing_controller->InitializeForPerfetto(&sstream);
#endif
TraceConfig* trace_config = new TraceConfig(); TraceConfig* trace_config = new TraceConfig();
trace_config->AddIncludedCategory("v8-cat"); trace_config->AddIncludedCategory("v8-cat");
tracing_controller->StartTracing(trace_config); tracing_controller->StartTracing(trace_config);
...@@ -211,6 +229,10 @@ TEST(TestTracingController) { ...@@ -211,6 +229,10 @@ TEST(TestTracingController) {
TraceBuffer* ring_buffer = TraceBuffer* ring_buffer =
TraceBuffer::CreateTraceBufferRingBuffer(1, writer); TraceBuffer::CreateTraceBufferRingBuffer(1, writer);
tracing_controller->Initialize(ring_buffer); tracing_controller->Initialize(ring_buffer);
#ifdef V8_USE_PERFETTO
std::ostringstream sstream;
tracing_controller->InitializeForPerfetto(&sstream);
#endif
TraceConfig* trace_config = new TraceConfig(); TraceConfig* trace_config = new TraceConfig();
trace_config->AddIncludedCategory("v8"); trace_config->AddIncludedCategory("v8");
tracing_controller->StartTracing(trace_config); tracing_controller->StartTracing(trace_config);
...@@ -243,7 +265,7 @@ void GetJSONStrings(std::vector<std::string>& ret, std::string str, ...@@ -243,7 +265,7 @@ void GetJSONStrings(std::vector<std::string>& ret, std::string str,
} }
TEST(TestTracingControllerMultipleArgsAndCopy) { TEST(TestTracingControllerMultipleArgsAndCopy) {
std::ostringstream stream; std::ostringstream stream, perfetto_stream;
uint64_t aa = 11; uint64_t aa = 11;
unsigned int bb = 22; unsigned int bb = 22;
uint16_t cc = 33; uint16_t cc = 33;
...@@ -282,6 +304,9 @@ TEST(TestTracingControllerMultipleArgsAndCopy) { ...@@ -282,6 +304,9 @@ TEST(TestTracingControllerMultipleArgsAndCopy) {
TraceBuffer* ring_buffer = TraceBuffer* ring_buffer =
TraceBuffer::CreateTraceBufferRingBuffer(1, writer); TraceBuffer::CreateTraceBufferRingBuffer(1, writer);
tracing_controller->Initialize(ring_buffer); tracing_controller->Initialize(ring_buffer);
#ifdef V8_USE_PERFETTO
tracing_controller->InitializeForPerfetto(&perfetto_stream);
#endif
TraceConfig* trace_config = new TraceConfig(); TraceConfig* trace_config = new TraceConfig();
trace_config->AddIncludedCategory("v8"); trace_config->AddIncludedCategory("v8");
tracing_controller->StartTracing(trace_config); tracing_controller->StartTracing(trace_config);
...@@ -399,6 +424,10 @@ TEST(TracingObservers) { ...@@ -399,6 +424,10 @@ TEST(TracingObservers) {
v8::platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer(1, v8::platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer(1,
writer); writer);
tracing_controller->Initialize(ring_buffer); tracing_controller->Initialize(ring_buffer);
#ifdef V8_USE_PERFETTO
std::ostringstream sstream;
tracing_controller->InitializeForPerfetto(&sstream);
#endif
v8::platform::tracing::TraceConfig* trace_config = v8::platform::tracing::TraceConfig* trace_config =
new v8::platform::tracing::TraceConfig(); new v8::platform::tracing::TraceConfig();
trace_config->AddIncludedCategory("v8"); trace_config->AddIncludedCategory("v8");
...@@ -488,6 +517,10 @@ TEST(AddTraceEventMultiThreaded) { ...@@ -488,6 +517,10 @@ TEST(AddTraceEventMultiThreaded) {
TraceBuffer* ring_buffer = TraceBuffer* ring_buffer =
TraceBuffer::CreateTraceBufferRingBuffer(1, writer); TraceBuffer::CreateTraceBufferRingBuffer(1, writer);
tracing_controller->Initialize(ring_buffer); tracing_controller->Initialize(ring_buffer);
#ifdef V8_USE_PERFETTO
std::ostringstream sstream;
tracing_controller->InitializeForPerfetto(&sstream);
#endif
TraceConfig* trace_config = new TraceConfig(); TraceConfig* trace_config = new TraceConfig();
trace_config->AddIncludedCategory("v8"); trace_config->AddIncludedCategory("v8");
tracing_controller->StartTracing(trace_config); tracing_controller->StartTracing(trace_config);
...@@ -506,6 +539,43 @@ TEST(AddTraceEventMultiThreaded) { ...@@ -506,6 +539,43 @@ TEST(AddTraceEventMultiThreaded) {
i::V8::SetPlatformForTesting(old_platform); i::V8::SetPlatformForTesting(old_platform);
} }
TEST(ScopedEventDuration) {
v8::Platform* old_platform = i::V8::GetCurrentPlatform();
std::unique_ptr<v8::Platform> default_platform(
v8::platform::NewDefaultPlatform());
i::V8::SetPlatformForTesting(default_platform.get());
auto tracing = base::make_unique<v8::platform::tracing::TracingController>();
v8::platform::tracing::TracingController* tracing_controller = tracing.get();
static_cast<v8::platform::DefaultPlatform*>(default_platform.get())
->SetTracingController(std::move(tracing));
MockTraceWriterFullTraceObject* writer = new MockTraceWriterFullTraceObject();
TraceBuffer* ring_buffer =
TraceBuffer::CreateTraceBufferRingBuffer(1, writer);
tracing_controller->Initialize(ring_buffer);
#ifdef V8_USE_PERFETTO
std::ostringstream sstream;
tracing_controller->InitializeForPerfetto(&sstream);
#endif
TraceConfig* trace_config = new TraceConfig();
trace_config->AddIncludedCategory("v8");
tracing_controller->StartTracing(trace_config);
{
TRACE_EVENT0("v8", "v8.Test.Scoped");
base::OS::Sleep(base::TimeDelta::FromMilliseconds(10));
}
tracing_controller->StopTracing();
CHECK_EQ(1u, writer->events().size());
CHECK_EQ(std::string("v8.Test.Scoped"), writer->events()[0]->name());
CHECK_GT(writer->events()[0]->duration(), 9000);
i::V8::SetPlatformForTesting(old_platform);
}
} // namespace tracing } // namespace tracing
} // namespace platform } // namespace platform
} // namespace v8 } // namespace v8
...@@ -2665,6 +2665,11 @@ TEST(TracingCpuProfiler) { ...@@ -2665,6 +2665,11 @@ TEST(TracingCpuProfiler) {
i::V8::GetCurrentPlatform()->GetTracingController()); i::V8::GetCurrentPlatform()->GetTracingController());
tracing_controller->Initialize(ring_buffer); tracing_controller->Initialize(ring_buffer);
#ifdef V8_USE_PERFETTO
std::ostringstream perfetto_output;
tracing_controller->InitializeForPerfetto(&perfetto_output);
#endif
bool result = false; bool result = false;
for (int run_duration = 50; !result; run_duration += 50) { for (int run_duration = 50; !result; run_duration += 50) {
TraceConfig* trace_config = new TraceConfig(); TraceConfig* trace_config = new TraceConfig();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment