[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/+/1611801
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61753}
This commit is contained in:
Peter Marshall 2019-05-21 13:24:16 +02:00 committed by Commit Bot
parent d56ee2e3df
commit a03ed62679
7 changed files with 118 additions and 17 deletions

View File

@ -240,6 +240,11 @@ class V8_PLATFORM_EXPORT TracingController
TracingController();
~TracingController() override;
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.
const uint8_t* GetCategoryGroupEnabled(const char* category_group) override;
@ -285,6 +290,7 @@ class V8_PLATFORM_EXPORT TracingController
#ifdef V8_USE_PERFETTO
std::atomic_bool perfetto_recording_{false};
std::unique_ptr<PerfettoTracingController> perfetto_tracing_controller_;
std::ostream* output_stream_ = nullptr;
#endif
// Disallow copy and assign

View File

@ -3323,7 +3323,6 @@ void Shell::CleanupWorkers() {
}
int Shell::Main(int argc, char* argv[]) {
std::ofstream trace_file;
v8::base::EnsureConsoleOutput();
if (!SetOptions(argc, argv)) return 1;
v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file);
@ -3334,15 +3333,26 @@ int Shell::Main(int argc, char* argv[]) {
: v8::platform::InProcessStackDumping::kEnabled;
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) {
tracing = base::make_unique<platform::tracing::TracingController>();
trace_file.open(options.trace_path ? options.trace_path : "v8_trace.json");
DCHECK(trace_file.good());
platform::tracing::TraceBuffer* trace_buffer =
platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer(
platform::tracing::TraceBuffer::kRingBufferChunks,
platform::tracing::TraceWriter::CreateJSONTraceWriter(trace_file));
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();
@ -3529,6 +3539,9 @@ int Shell::Main(int argc, char* argv[]) {
// Delete the platform explicitly here to write the tracing output to the
// tracing file.
if (options.trace_enabled) {
tracing_controller->StopTracing();
}
g_platform.reset();
return result;
}

View File

@ -22,16 +22,15 @@ PerfettoTracingController::PerfettoTracingController()
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());
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, this] {
task_runner_->PostTask([&trace_config, output_stream, this] {
std::unique_ptr<::perfetto::SharedMemory::Factory> shmem_factory =
base::make_unique<PerfettoSharedMemoryFactory>();
@ -46,7 +45,7 @@ void PerfettoTracingController::StartTracing(
service_->SetSMBScrapingEnabled(true);
producer_ = base::make_unique<PerfettoProducer>(this);
consumer_ = base::make_unique<PerfettoJSONConsumer>(
&trace_file_, &consumer_finished_semaphore_);
output_stream, &consumer_finished_semaphore_);
producer_->set_service_endpoint(service_->ConnectProducer(
producer_.get(), 0, "v8.perfetto-producer", 0, true));
@ -90,9 +89,6 @@ void PerfettoTracingController::StopTracing() {
// 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() {

View File

@ -37,8 +37,10 @@ class PerfettoTracingController {
// Blocks and sets up all required data structures for tracing. It is safe to
// call GetOrCreateThreadLocalWriter() to obtain thread-local TraceWriters for
// writing trace events once this call returns.
void StartTracing(const ::perfetto::TraceConfig& trace_config);
// writing trace events once this call returns. Tracing output will be sent in
// 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
// thread.
@ -68,9 +70,6 @@ class PerfettoTracingController {
base::Semaphore producer_ready_semaphore_;
base::Semaphore consumer_finished_semaphore_;
// TODO(petermarshall): pass this in instead.
std::ofstream trace_file_;
DISALLOW_COPY_AND_ASSIGN(PerfettoTracingController);
};

View File

@ -73,6 +73,14 @@ void TracingController::Initialize(TraceBuffer* trace_buffer) {
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() {
return base::TimeTicks::HighResolutionNow().ToInternalValue();
}
@ -271,8 +279,12 @@ void TracingController::StartTracing(TraceConfig* trace_config) {
auto* ds_config = perfetto_trace_config.add_data_sources()->mutable_config();
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|.
perfetto_tracing_controller_->StartTracing(perfetto_trace_config);
perfetto_tracing_controller_->StartTracing(perfetto_trace_config,
output_stream_);
perfetto_recording_.store(true);
#endif // V8_USE_PERFETTO

View File

@ -81,6 +81,20 @@ class MockTraceWriter : public TraceWriter {
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) {
// We should be able to add kChunkSize * 2 + 1 trace events.
const int HANDLES_COUNT = TraceBufferChunk::kChunkSize * 2 + 1;
@ -144,6 +158,10 @@ void PopulateJSONWriter(TraceWriter* writer) {
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-cat");
tracing_controller->StartTracing(trace_config);
@ -211,6 +229,10 @@ TEST(TestTracingController) {
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);
@ -243,7 +265,7 @@ void GetJSONStrings(std::vector<std::string>& ret, std::string str,
}
TEST(TestTracingControllerMultipleArgsAndCopy) {
std::ostringstream stream;
std::ostringstream stream, perfetto_stream;
uint64_t aa = 11;
unsigned int bb = 22;
uint16_t cc = 33;
@ -282,6 +304,9 @@ TEST(TestTracingControllerMultipleArgsAndCopy) {
TraceBuffer* ring_buffer =
TraceBuffer::CreateTraceBufferRingBuffer(1, writer);
tracing_controller->Initialize(ring_buffer);
#ifdef V8_USE_PERFETTO
tracing_controller->InitializeForPerfetto(&perfetto_stream);
#endif
TraceConfig* trace_config = new TraceConfig();
trace_config->AddIncludedCategory("v8");
tracing_controller->StartTracing(trace_config);
@ -399,6 +424,10 @@ TEST(TracingObservers) {
v8::platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer(1,
writer);
tracing_controller->Initialize(ring_buffer);
#ifdef V8_USE_PERFETTO
std::ostringstream sstream;
tracing_controller->InitializeForPerfetto(&sstream);
#endif
v8::platform::tracing::TraceConfig* trace_config =
new v8::platform::tracing::TraceConfig();
trace_config->AddIncludedCategory("v8");
@ -488,6 +517,10 @@ TEST(AddTraceEventMultiThreaded) {
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);
@ -506,6 +539,43 @@ TEST(AddTraceEventMultiThreaded) {
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 platform
} // namespace v8

View File

@ -2665,6 +2665,11 @@ TEST(TracingCpuProfiler) {
i::V8::GetCurrentPlatform()->GetTracingController());
tracing_controller->Initialize(ring_buffer);
#ifdef V8_USE_PERFETTO
std::ostringstream perfetto_output;
tracing_controller->InitializeForPerfetto(&perfetto_output);
#endif
bool result = false;
for (int run_duration = 50; !result; run_duration += 50) {
TraceConfig* trace_config = new TraceConfig();