[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:
parent
d56ee2e3df
commit
a03ed62679
@ -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
|
||||
|
15
src/d8/d8.cc
15
src/d8/d8.cc
@ -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;
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user