From edd383fbcd3511cfc4c6abc20e90df7e986180f2 Mon Sep 17 00:00:00 2001 From: Peter Marshall Date: Mon, 8 Jul 2019 10:29:54 +0200 Subject: [PATCH] [tracing] Use the new perfetto client API The client API provides a much simpler interface so that we don't have to deal with producers, consumers etc. directly. This CL removes all the code that dealt with the more complex API used previously. The architecture used here requires that the embedder call into Tracing::Initialize() to set up the tracing backend. The tracing controller then connects to this backend when calling DataSource::Register() and Tracing::NewTrace(). This will ultimately avoid the need for a virtual call (or two) for every trace event that need to be dispatched over the API - chrome can provide a backend and V8 will connect to it opaquely with the same code when tracing is enabled. Cq-Include-Trybots: luci.v8.try:v8_linux64_perfetto_dbg_ng Bug: v8:8339 Change-Id: I6b74fbb49ffcc89638caeb59ed3d5cc81238f3e8 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1634916 Reviewed-by: Yang Guo Reviewed-by: Jakob Gruber Commit-Queue: Peter Marshall Cr-Commit-Position: refs/heads/master@{#62568} --- BUILD.gn | 20 ++- DEPS | 2 +- include/libplatform/v8-tracing.h | 11 +- src/DEPS | 1 + src/d8/d8.cc | 8 ++ .../tracing/json-trace-event-listener.cc | 4 +- .../tracing/json-trace-event-listener.h | 5 +- src/libplatform/tracing/perfetto-consumer.cc | 44 ------ src/libplatform/tracing/perfetto-consumer.h | 80 ----------- src/libplatform/tracing/perfetto-producer.cc | 45 ------ src/libplatform/tracing/perfetto-producer.h | 70 ---------- .../tracing/perfetto-shared-memory.cc | 28 ---- .../tracing/perfetto-shared-memory.h | 45 ------ src/libplatform/tracing/perfetto-tasks.cc | 52 ------- src/libplatform/tracing/perfetto-tasks.h | 55 -------- .../tracing/perfetto-tracing-controller.cc | 130 ------------------ .../tracing/perfetto-tracing-controller.h | 86 ------------ .../tracing/trace-event-listener.cc | 27 ++++ .../tracing/trace-event-listener.h | 9 +- src/libplatform/tracing/tracing-controller.cc | 129 +++++++++-------- test/cctest/BUILD.gn | 10 +- test/cctest/DEPS | 3 +- test/cctest/cctest.cc | 11 +- test/cctest/libplatform/test-tracing.cc | 72 +++++++++- 24 files changed, 223 insertions(+), 724 deletions(-) delete mode 100644 src/libplatform/tracing/perfetto-consumer.cc delete mode 100644 src/libplatform/tracing/perfetto-consumer.h delete mode 100644 src/libplatform/tracing/perfetto-producer.cc delete mode 100644 src/libplatform/tracing/perfetto-producer.h delete mode 100644 src/libplatform/tracing/perfetto-shared-memory.cc delete mode 100644 src/libplatform/tracing/perfetto-shared-memory.h delete mode 100644 src/libplatform/tracing/perfetto-tasks.cc delete mode 100644 src/libplatform/tracing/perfetto-tasks.h delete mode 100644 src/libplatform/tracing/perfetto-tracing-controller.cc delete mode 100644 src/libplatform/tracing/perfetto-tracing-controller.h create mode 100644 src/libplatform/tracing/trace-event-listener.cc diff --git a/BUILD.gn b/BUILD.gn index 43b93c4a92..6c0ea2c6ec 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -3682,21 +3682,15 @@ v8_component("v8_libplatform") { sources += [ "src/libplatform/tracing/json-trace-event-listener.cc", "src/libplatform/tracing/json-trace-event-listener.h", - "src/libplatform/tracing/perfetto-consumer.cc", - "src/libplatform/tracing/perfetto-consumer.h", - "src/libplatform/tracing/perfetto-producer.cc", - "src/libplatform/tracing/perfetto-producer.h", - "src/libplatform/tracing/perfetto-shared-memory.cc", - "src/libplatform/tracing/perfetto-shared-memory.h", - "src/libplatform/tracing/perfetto-tasks.cc", - "src/libplatform/tracing/perfetto-tasks.h", - "src/libplatform/tracing/perfetto-tracing-controller.cc", - "src/libplatform/tracing/perfetto-tracing-controller.h", + "src/libplatform/tracing/trace-event-listener.cc", "src/libplatform/tracing/trace-event-listener.h", ] deps += [ - "//third_party/perfetto:libperfetto", + "//third_party/perfetto/protos/perfetto/trace:lite", "//third_party/perfetto/protos/perfetto/trace/chrome:minimal_complete_lite", + "//third_party/perfetto/protos/perfetto/trace/chrome:zero", + "//third_party/perfetto/src/tracing:client_api", + "//third_party/perfetto/src/tracing:platform_posix", ] } } @@ -4164,6 +4158,10 @@ v8_executable("d8") { if (v8_enable_vtunejit) { deps += [ "src/third_party/vtune:v8_vtune" ] } + + if (v8_use_perfetto) { + deps += [ "//third_party/perfetto/include/perfetto/tracing" ] + } } v8_executable("v8_hello_world") { diff --git a/DEPS b/DEPS index 950c9146df..3a6bf2dd75 100644 --- a/DEPS +++ b/DEPS @@ -233,7 +233,7 @@ deps = { 'v8/test/wasm-js/data': Var('chromium_url') + '/external/github.com/WebAssembly/spec.git' + '@' + '666dc4cb8d4a81d386a7a716000bb85fbbbd06a2', 'v8/third_party/perfetto': - Var('android_url') + '/platform/external/perfetto.git' + '@' + '10c98fe0cfae669f71610d97e9da94260a6da173', + Var('android_url') + '/platform/external/perfetto.git' + '@' + '0e8281399fd854de13461f2c1c9f2fb0b8e9c3ae', 'v8/third_party/protobuf': Var('chromium_url') + '/external/github.com/google/protobuf'+ '@' + 'b68a347f56137b4b1a746e8c7438495a6ac1bd91', } diff --git a/include/libplatform/v8-tracing.h b/include/libplatform/v8-tracing.h index ccdca0a8c5..e7cd8bfcdb 100644 --- a/include/libplatform/v8-tracing.h +++ b/include/libplatform/v8-tracing.h @@ -14,6 +14,10 @@ #include "libplatform/libplatform-export.h" #include "v8-platform.h" // NOLINT(build/include) +namespace perfetto { +class TracingSession; +} + namespace v8 { namespace base { @@ -23,8 +27,8 @@ class Mutex; namespace platform { namespace tracing { -class PerfettoTracingController; class TraceEventListener; +class JSONTraceEventListener; const int kTraceMaxNumArgs = 2; @@ -292,11 +296,10 @@ class V8_PLATFORM_EXPORT TracingController std::unordered_set observers_; std::atomic_bool recording_{false}; #ifdef V8_USE_PERFETTO - std::atomic_bool perfetto_recording_{false}; - std::unique_ptr perfetto_tracing_controller_; std::ostream* output_stream_ = nullptr; - std::unique_ptr json_listener_; + std::unique_ptr json_listener_; TraceEventListener* listener_for_testing_ = nullptr; + std::unique_ptr tracing_session_; #endif // Disallow copy and assign diff --git a/src/DEPS b/src/DEPS index c8379e1e17..1ae6a569e7 100644 --- a/src/DEPS +++ b/src/DEPS @@ -49,5 +49,6 @@ specific_include_rules = { "d8\.cc": [ "+include/libplatform/libplatform.h", "+include/libplatform/v8-tracing.h", + "+perfetto/tracing.h" ], } diff --git a/src/d8/d8.cc b/src/d8/d8.cc index c0168d4498..094bf40eb9 100644 --- a/src/d8/d8.cc +++ b/src/d8/d8.cc @@ -48,6 +48,10 @@ #include "src/utils/utils.h" #include "src/wasm/wasm-engine.h" +#ifdef V8_USE_PERFETTO +#include "perfetto/tracing.h" +#endif // V8_USE_PERFETTO + #ifdef V8_INTL_SUPPORT #include "unicode/locid.h" #endif // V8_INTL_SUPPORT @@ -3366,6 +3370,10 @@ int Shell::Main(int argc, char* argv[]) { tracing->Initialize(trace_buffer); #ifdef V8_USE_PERFETTO + perfetto::TracingInitArgs init_args; + init_args.backends = perfetto::BackendType::kInProcessBackend; + perfetto::Tracing::Initialize(init_args); + perfetto_trace_file.open("v8_perfetto_trace.json"); DCHECK(trace_file.good()); tracing->InitializeForPerfetto(&perfetto_trace_file); diff --git a/src/libplatform/tracing/json-trace-event-listener.cc b/src/libplatform/tracing/json-trace-event-listener.cc index 99db86a7d1..94b74ef255 100644 --- a/src/libplatform/tracing/json-trace-event-listener.cc +++ b/src/libplatform/tracing/json-trace-event-listener.cc @@ -8,6 +8,8 @@ #include "base/trace_event/common/trace_event_common.h" #include "perfetto/trace/chrome/chrome_trace_packet.pb.h" +#include "perfetto/trace/trace.pb.h" +#include "perfetto/tracing.h" #include "src/base/logging.h" #include "src/base/macros.h" @@ -111,7 +113,7 @@ void JSONTraceEventListener::AppendArgValue( } void JSONTraceEventListener::ProcessPacket( - const ::perfetto::protos::ChromeTracePacket& packet) { + const ::perfetto::protos::TracePacket& packet) { for (const ::perfetto::protos::ChromeTraceEvent& event : packet.chrome_events().trace_events()) { if (append_comma_) *stream_ << ","; diff --git a/src/libplatform/tracing/json-trace-event-listener.h b/src/libplatform/tracing/json-trace-event-listener.h index fc4979f14c..d13332871f 100644 --- a/src/libplatform/tracing/json-trace-event-listener.h +++ b/src/libplatform/tracing/json-trace-event-listener.h @@ -26,10 +26,9 @@ class JSONTraceEventListener final : public TraceEventListener { explicit JSONTraceEventListener(std::ostream* stream); ~JSONTraceEventListener() override; - private: - void ProcessPacket( - const ::perfetto::protos::ChromeTracePacket& packet) override; + void ProcessPacket(const ::perfetto::protos::TracePacket& packet) override; + private: // Internal implementation void AppendJSONString(const char* str); void AppendArgValue(const ::perfetto::protos::ChromeTraceEvent_Arg& arg); diff --git a/src/libplatform/tracing/perfetto-consumer.cc b/src/libplatform/tracing/perfetto-consumer.cc deleted file mode 100644 index 8071fe52d5..0000000000 --- a/src/libplatform/tracing/perfetto-consumer.cc +++ /dev/null @@ -1,44 +0,0 @@ -// 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-consumer.h" - -#include "perfetto/trace/chrome/chrome_trace_packet.pb.h" -#include "perfetto/tracing/core/trace_packet.h" -#include "src/base/macros.h" -#include "src/base/platform/semaphore.h" -#include "src/libplatform/tracing/trace-event-listener.h" - -namespace v8 { -namespace platform { -namespace tracing { - -PerfettoConsumer::PerfettoConsumer(base::Semaphore* finished) - : finished_semaphore_(finished) {} - -void PerfettoConsumer::OnTraceData(std::vector<::perfetto::TracePacket> packets, - bool has_more) { - for (const ::perfetto::TracePacket& packet : packets) { - perfetto::protos::ChromeTracePacket proto_packet; - bool success = packet.Decode(&proto_packet); - USE(success); - DCHECK(success); - - for (TraceEventListener* listener : listeners_) { - listener->ProcessPacket(proto_packet); - } - } - // PerfettoTracingController::StopTracing() waits on this sempahore. This is - // so that we can ensure that this consumer has finished consuming all of the - // trace events from the buffer before the buffer is destroyed. - if (!has_more) finished_semaphore_->Signal(); -} - -void PerfettoConsumer::AddTraceEventListener(TraceEventListener* listener) { - listeners_.push_back(listener); -} - -} // namespace tracing -} // namespace platform -} // namespace v8 diff --git a/src/libplatform/tracing/perfetto-consumer.h b/src/libplatform/tracing/perfetto-consumer.h deleted file mode 100644 index 83d0c48c1b..0000000000 --- a/src/libplatform/tracing/perfetto-consumer.h +++ /dev/null @@ -1,80 +0,0 @@ -// 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. - -#ifndef V8_LIBPLATFORM_TRACING_PERFETTO_CONSUMER_H_ -#define V8_LIBPLATFORM_TRACING_PERFETTO_CONSUMER_H_ - -#include - -#include "perfetto/tracing/core/consumer.h" -#include "perfetto/tracing/core/tracing_service.h" -#include "src/base/logging.h" - -namespace perfetto { -namespace protos { -class ChromeTracePacket; -} // namespace protos -} // namespace perfetto - -namespace v8 { - -namespace base { -class Semaphore; -} - -namespace platform { -namespace tracing { - -class TraceEventListener; - -// A Perfetto Consumer gets streamed trace events from the Service via -// OnTraceData(). A Consumer can be configured (via -// service_endpoint()->EnableTracing()) to listen to various different types of -// trace events. The Consumer is responsible for producing whatever tracing -// output the system should have. - -// Implements the V8-specific logic for interacting with the tracing controller -// and directs trace events to the added TraceEventListeners. -class PerfettoConsumer final : public ::perfetto::Consumer { - public: - explicit PerfettoConsumer(base::Semaphore* finished); - - using ServiceEndpoint = ::perfetto::TracingService::ConsumerEndpoint; - - // Register a trace event listener that will receive trace events from this - // consumer. This can be called multiple times to register multiple listeners, - // but must be called before starting tracing. - void AddTraceEventListener(TraceEventListener* listener); - - ServiceEndpoint* service_endpoint() const { return service_endpoint_.get(); } - void set_service_endpoint(std::unique_ptr endpoint) { - service_endpoint_ = std::move(endpoint); - } - - private: - // ::perfetto::Consumer implementation - void OnConnect() override {} - void OnDisconnect() override {} - void OnTracingDisabled() override {} - void OnTraceData(std::vector<::perfetto::TracePacket> packets, - bool has_more) override; - void OnDetach(bool success) override {} - void OnAttach(bool success, const ::perfetto::TraceConfig&) override {} - void OnTraceStats(bool success, const ::perfetto::TraceStats&) override { - UNREACHABLE(); - } - void OnObservableEvents(const ::perfetto::ObservableEvents&) override { - UNREACHABLE(); - } - - std::unique_ptr service_endpoint_; - base::Semaphore* finished_semaphore_; - std::vector listeners_; -}; - -} // namespace tracing -} // namespace platform -} // namespace v8 - -#endif // V8_LIBPLATFORM_TRACING_PERFETTO_CONSUMER_H_ diff --git a/src/libplatform/tracing/perfetto-producer.cc b/src/libplatform/tracing/perfetto-producer.cc deleted file mode 100644 index 814dca6b59..0000000000 --- a/src/libplatform/tracing/perfetto-producer.cc +++ /dev/null @@ -1,45 +0,0 @@ -// 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-producer.h" - -#include "perfetto/tracing/core/data_source_config.h" -#include "perfetto/tracing/core/data_source_descriptor.h" -#include "perfetto/tracing/core/trace_writer.h" -#include "src/libplatform/tracing/perfetto-tasks.h" -#include "src/libplatform/tracing/perfetto-tracing-controller.h" - -namespace v8 { -namespace platform { -namespace tracing { - -void PerfettoProducer::OnConnect() { - ::perfetto::DataSourceDescriptor ds_desc; - ds_desc.set_name("v8.trace_events"); - service_endpoint_->RegisterDataSource(ds_desc); -} - -void PerfettoProducer::StartDataSource( - ::perfetto::DataSourceInstanceID, const ::perfetto::DataSourceConfig& cfg) { - target_buffer_ = cfg.target_buffer(); - tracing_controller_->OnProducerReady(); -} - -void PerfettoProducer::StopDataSource(::perfetto::DataSourceInstanceID) { - target_buffer_ = 0; -} - -std::unique_ptr<::perfetto::TraceWriter> PerfettoProducer::CreateTraceWriter() - const { - CHECK_NE(0, target_buffer_); - return service_endpoint_->CreateTraceWriter(target_buffer_); -} - -PerfettoProducer::PerfettoProducer( - PerfettoTracingController* tracing_controller) - : tracing_controller_(tracing_controller) {} - -} // namespace tracing -} // namespace platform -} // namespace v8 diff --git a/src/libplatform/tracing/perfetto-producer.h b/src/libplatform/tracing/perfetto-producer.h deleted file mode 100644 index 2a363e8bf8..0000000000 --- a/src/libplatform/tracing/perfetto-producer.h +++ /dev/null @@ -1,70 +0,0 @@ -// 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. - -#ifndef V8_LIBPLATFORM_TRACING_PERFETTO_PRODUCER_H_ -#define V8_LIBPLATFORM_TRACING_PERFETTO_PRODUCER_H_ - -#include -#include - -#include "perfetto/tracing/core/producer.h" -#include "perfetto/tracing/core/tracing_service.h" -#include "src/base/logging.h" - -namespace v8 { -namespace platform { -namespace tracing { - -class PerfettoTracingController; - -class PerfettoProducer final : public ::perfetto::Producer { - public: - using ServiceEndpoint = ::perfetto::TracingService::ProducerEndpoint; - - explicit PerfettoProducer(PerfettoTracingController* tracing_controller); - - ServiceEndpoint* service_endpoint() const { return service_endpoint_.get(); } - void set_service_endpoint(std::unique_ptr endpoint) { - service_endpoint_ = std::move(endpoint); - } - - // Create a TraceWriter for the calling thread. The TraceWriter is a - // thread-local object that writes data into a buffer which is shared between - // all TraceWriters for a given PerfettoProducer instance. Can only be called - // after the StartDataSource() callback has been received from the service, as - // this provides the buffer. - std::unique_ptr<::perfetto::TraceWriter> CreateTraceWriter() const; - - private: - // ::perfetto::Producer implementation - void OnConnect() override; - void OnDisconnect() override {} - void OnTracingSetup() override {} - void SetupDataSource(::perfetto::DataSourceInstanceID, - const ::perfetto::DataSourceConfig&) override {} - void StartDataSource(::perfetto::DataSourceInstanceID, - const ::perfetto::DataSourceConfig& cfg) override; - void StopDataSource(::perfetto::DataSourceInstanceID) override; - // TODO(petermarshall): Implement Flush(). A final flush happens when the - // TraceWriter object for each thread is destroyed, but this will be more - // efficient. - void Flush(::perfetto::FlushRequestID, - const ::perfetto::DataSourceInstanceID*, size_t) override {} - - void ClearIncrementalState( - const ::perfetto::DataSourceInstanceID* data_source_ids, - size_t num_data_sources) override { - UNREACHABLE(); - } - - std::unique_ptr service_endpoint_; - uint32_t target_buffer_ = 0; - PerfettoTracingController* tracing_controller_; -}; - -} // namespace tracing -} // namespace platform -} // namespace v8 - -#endif // V8_LIBPLATFORM_TRACING_PERFETTO_PRODUCER_H_ diff --git a/src/libplatform/tracing/perfetto-shared-memory.cc b/src/libplatform/tracing/perfetto-shared-memory.cc deleted file mode 100644 index 6c31c05070..0000000000 --- a/src/libplatform/tracing/perfetto-shared-memory.cc +++ /dev/null @@ -1,28 +0,0 @@ -// 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-shared-memory.h" - -#include "src/base/platform/platform.h" -#include "src/base/template-utils.h" - -namespace v8 { -namespace platform { -namespace tracing { - -PerfettoSharedMemory::PerfettoSharedMemory(size_t size) - : size_(size), - paged_memory_(::perfetto::base::PagedMemory::Allocate(size)) { - // TODO(956543): Find a cross-platform solution. - // TODO(petermarshall): Don't assume that size is page-aligned. -} - -std::unique_ptr<::perfetto::SharedMemory> -PerfettoSharedMemoryFactory::CreateSharedMemory(size_t size) { - return base::make_unique(size); -} - -} // namespace tracing -} // namespace platform -} // namespace v8 diff --git a/src/libplatform/tracing/perfetto-shared-memory.h b/src/libplatform/tracing/perfetto-shared-memory.h deleted file mode 100644 index 7a987cc7f0..0000000000 --- a/src/libplatform/tracing/perfetto-shared-memory.h +++ /dev/null @@ -1,45 +0,0 @@ -// 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. - -#ifndef V8_LIBPLATFORM_TRACING_PERFETTO_SHARED_MEMORY_H_ -#define V8_LIBPLATFORM_TRACING_PERFETTO_SHARED_MEMORY_H_ - -#include "perfetto/tracing/core/shared_memory.h" - -#include "third_party/perfetto/include/perfetto/base/paged_memory.h" - -namespace v8 { -namespace platform { -namespace tracing { - -// Perfetto requires a shared memory implementation for multi-process embedders -// but V8 is single process. We implement it here using PagedMemory from -// perfetto. -class PerfettoSharedMemory : public ::perfetto::SharedMemory { - public: - explicit PerfettoSharedMemory(size_t size); - - // The PagedMemory destructor will free the underlying memory when this object - // is destroyed. - - void* start() const override { return paged_memory_.Get(); } - size_t size() const override { return size_; } - - private: - size_t size_; - ::perfetto::base::PagedMemory paged_memory_; -}; - -class PerfettoSharedMemoryFactory : public ::perfetto::SharedMemory::Factory { - public: - ~PerfettoSharedMemoryFactory() override = default; - std::unique_ptr<::perfetto::SharedMemory> CreateSharedMemory( - size_t size) override; -}; - -} // namespace tracing -} // namespace platform -} // namespace v8 - -#endif // V8_LIBPLATFORM_TRACING_PERFETTO_SHARED_MEMORY_H_ diff --git a/src/libplatform/tracing/perfetto-tasks.cc b/src/libplatform/tracing/perfetto-tasks.cc deleted file mode 100644 index 70d00ed626..0000000000 --- a/src/libplatform/tracing/perfetto-tasks.cc +++ /dev/null @@ -1,52 +0,0 @@ -// 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-tasks.h" - -#include "src/base/platform/semaphore.h" -#include "src/base/platform/time.h" - -namespace v8 { -namespace platform { -namespace tracing { - -PerfettoTaskRunner::PerfettoTaskRunner() : runner_(1, DefaultTimeFunction) {} - -PerfettoTaskRunner::~PerfettoTaskRunner() { runner_.Terminate(); } - -// static -double PerfettoTaskRunner::DefaultTimeFunction() { - return (base::TimeTicks::HighResolutionNow() - base::TimeTicks()) - .InSecondsF(); -} - -void PerfettoTaskRunner::PostTask(std::function f) { - runner_.PostTask(base::make_unique(std::move(f))); -} - -void PerfettoTaskRunner::PostDelayedTask(std::function f, - uint32_t delay_ms) { - double delay_in_seconds = - delay_ms / static_cast(base::Time::kMillisecondsPerSecond); - runner_.PostDelayedTask(base::make_unique(std::move(f)), - delay_in_seconds); -} - -bool PerfettoTaskRunner::RunsTasksOnCurrentThread() const { - return runner_.RunsTasksOnCurrentThread(); -} - -void PerfettoTaskRunner::FinishImmediateTasks() { - DCHECK(!RunsTasksOnCurrentThread()); - base::Semaphore semaphore(0); - // PostTask has guaranteed ordering so this will be the last task executed. - runner_.PostTask( - base::make_unique([&semaphore] { semaphore.Signal(); })); - - semaphore.Wait(); -} - -} // namespace tracing -} // namespace platform -} // namespace v8 diff --git a/src/libplatform/tracing/perfetto-tasks.h b/src/libplatform/tracing/perfetto-tasks.h deleted file mode 100644 index 054a9e157a..0000000000 --- a/src/libplatform/tracing/perfetto-tasks.h +++ /dev/null @@ -1,55 +0,0 @@ -// 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. - -#ifndef V8_LIBPLATFORM_TRACING_PERFETTO_TASKS_H_ -#define V8_LIBPLATFORM_TRACING_PERFETTO_TASKS_H_ - -#include - -#include "include/v8-platform.h" -#include "perfetto/base/task_runner.h" -#include "src/libplatform/default-worker-threads-task-runner.h" - -namespace v8 { -namespace platform { -namespace tracing { - -class TracingTask : public Task { - public: - explicit TracingTask(std::function f) : f_(std::move(f)) {} - - void Run() override { f_(); } - - private: - std::function f_; -}; - -class PerfettoTaskRunner : public ::perfetto::base::TaskRunner { - public: - PerfettoTaskRunner(); - ~PerfettoTaskRunner() override; - - // ::perfetto::base::TaskRunner implementation - void PostTask(std::function f) override; - void PostDelayedTask(std::function f, uint32_t delay_ms) override; - void AddFileDescriptorWatch(int fd, std::function) override { - UNREACHABLE(); - } - void RemoveFileDescriptorWatch(int fd) override { UNREACHABLE(); } - bool RunsTasksOnCurrentThread() const override; - - // PerfettoTaskRunner implementation - void FinishImmediateTasks(); - - private: - static double DefaultTimeFunction(); - - DefaultWorkerThreadsTaskRunner runner_; -}; - -} // namespace tracing -} // namespace platform -} // namespace v8 - -#endif // V8_LIBPLATFORM_TRACING_PERFETTO_TASKS_H_ diff --git a/src/libplatform/tracing/perfetto-tracing-controller.cc b/src/libplatform/tracing/perfetto-tracing-controller.cc deleted file mode 100644 index 9b62c2ae78..0000000000 --- a/src/libplatform/tracing/perfetto-tracing-controller.cc +++ /dev/null @@ -1,130 +0,0 @@ -// 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-consumer.h" -#include "src/libplatform/tracing/perfetto-producer.h" -#include "src/libplatform/tracing/perfetto-shared-memory.h" -#include "src/libplatform/tracing/perfetto-tasks.h" -#include "src/libplatform/tracing/trace-event-listener.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(!task_runner_); - task_runner_ = base::make_unique(); - // 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(); - - 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(this); - consumer_ = - base::make_unique(&consumer_finished_semaphore_); - - for (TraceEventListener* listener : listeners_) { - consumer_->AddTraceEventListener(listener); - } - - 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 - // PerfettoConsumer::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(); -} - -void PerfettoTracingController::AddTraceEventListener( - TraceEventListener* listener) { - listeners_.push_back(listener); -} - -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 diff --git a/src/libplatform/tracing/perfetto-tracing-controller.h b/src/libplatform/tracing/perfetto-tracing-controller.h deleted file mode 100644 index 67a3c26cef..0000000000 --- a/src/libplatform/tracing/perfetto-tracing-controller.h +++ /dev/null @@ -1,86 +0,0 @@ -// 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. - -#ifndef V8_LIBPLATFORM_TRACING_PERFETTO_TRACING_CONTROLLER_H_ -#define V8_LIBPLATFORM_TRACING_PERFETTO_TRACING_CONTROLLER_H_ - -#include -#include -#include -#include - -#include "src/base/platform/platform.h" -#include "src/base/platform/semaphore.h" - -namespace perfetto { -class TraceConfig; -class TraceWriter; -class TracingService; -} // namespace perfetto - -namespace v8 { -namespace platform { -namespace tracing { - -class PerfettoConsumer; -class PerfettoProducer; -class PerfettoTaskRunner; -class TraceEventListener; - -// This is the top-level interface for performing tracing with perfetto. The -// user of this class should call StartTracing() to start tracing, and -// StopTracing() to stop it. To write trace events, the user can obtain a -// thread-local TraceWriter object using GetOrCreateThreadLocalWriter(). -class PerfettoTracingController { - public: - 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. Tracing output will be sent to - // the TraceEventListeners registered via AddTraceEventListener(). - void StartTracing(const ::perfetto::TraceConfig& trace_config); - - // Blocks and finishes all existing AddTraceEvent tasks. Stops the tracing - // thread. - void StopTracing(); - - // Register a trace event listener that will receive trace events. This can be - // called multiple times to register multiple listeners, but must be called - // before starting tracing. - void AddTraceEventListener(TraceEventListener* listener); - - ~PerfettoTracingController(); - - // Each thread that wants to trace should call this to get their TraceWriter. - // PerfettoTracingController creates and owns the TraceWriter. - ::perfetto::TraceWriter* GetOrCreateThreadLocalWriter(); - - private: - // Signals the producer_ready_semaphore_. - void OnProducerReady(); - - // PerfettoProducer is the only class allowed to call OnProducerReady(). - friend class PerfettoProducer; - - std::unique_ptr<::perfetto::TracingService> service_; - std::unique_ptr producer_; - std::unique_ptr consumer_; - std::unique_ptr task_runner_; - std::vector listeners_; - base::Thread::LocalStorageKey writer_key_; - // A semaphore that is signalled when StartRecording is called. StartTracing - // waits on this semaphore to be notified when the tracing service is ready to - // receive trace events. - base::Semaphore producer_ready_semaphore_; - base::Semaphore consumer_finished_semaphore_; - - DISALLOW_COPY_AND_ASSIGN(PerfettoTracingController); -}; - -} // namespace tracing -} // namespace platform -} // namespace v8 - -#endif // V8_LIBPLATFORM_TRACING_PERFETTO_TRACING_CONTROLLER_H_ diff --git a/src/libplatform/tracing/trace-event-listener.cc b/src/libplatform/tracing/trace-event-listener.cc new file mode 100644 index 0000000000..8224221228 --- /dev/null +++ b/src/libplatform/tracing/trace-event-listener.cc @@ -0,0 +1,27 @@ +// 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/trace-event-listener.h" + +#include "perfetto/trace/trace.pb.h" +#include "src/base/logging.h" + +namespace v8 { +namespace platform { +namespace tracing { + +void TraceEventListener::ParseFromArray(const std::vector& array) { + perfetto::protos::Trace trace; + CHECK(trace.ParseFromArray(array.data(), static_cast(array.size()))); + + for (int i = 0; i < trace.packet_size(); i++) { + // TODO(petermarshall): ChromeTracePacket instead. + const perfetto::protos::TracePacket& packet = trace.packet(i); + ProcessPacket(packet); + } +} + +} // namespace tracing +} // namespace platform +} // namespace v8 diff --git a/src/libplatform/tracing/trace-event-listener.h b/src/libplatform/tracing/trace-event-listener.h index 4acdb2935b..6a535c79c5 100644 --- a/src/libplatform/tracing/trace-event-listener.h +++ b/src/libplatform/tracing/trace-event-listener.h @@ -5,9 +5,11 @@ #ifndef V8_LIBPLATFORM_TRACING_TRACE_EVENT_LISTENER_H_ #define V8_LIBPLATFORM_TRACING_TRACE_EVENT_LISTENER_H_ +#include + namespace perfetto { namespace protos { -class ChromeTracePacket; +class TracePacket; } // namespace protos } // namespace perfetto @@ -23,8 +25,9 @@ namespace tracing { class TraceEventListener { public: virtual ~TraceEventListener() = default; - virtual void ProcessPacket( - const ::perfetto::protos::ChromeTracePacket& packet) = 0; + virtual void ProcessPacket(const ::perfetto::protos::TracePacket& packet) = 0; + + void ParseFromArray(const std::vector& array); }; } // namespace tracing diff --git a/src/libplatform/tracing/tracing-controller.cc b/src/libplatform/tracing/tracing-controller.cc index 91d042ba1e..c31967b904 100644 --- a/src/libplatform/tracing/tracing-controller.cc +++ b/src/libplatform/tracing/tracing-controller.cc @@ -16,12 +16,25 @@ #include "base/trace_event/common/trace_event_common.h" #include "perfetto/trace/chrome/chrome_trace_event.pbzero.h" #include "perfetto/trace/trace_packet.pbzero.h" -#include "perfetto/tracing/core/data_source_config.h" -#include "perfetto/tracing/core/trace_config.h" -#include "perfetto/tracing/core/trace_packet.h" -#include "perfetto/tracing/core/trace_writer.h" +#include "perfetto/tracing.h" +#include "src/base/platform/platform.h" +#include "src/base/platform/semaphore.h" #include "src/libplatform/tracing/json-trace-event-listener.h" -#include "src/libplatform/tracing/perfetto-tracing-controller.h" +#endif // V8_USE_PERFETTO + +#ifdef V8_USE_PERFETTO +class V8DataSource : public perfetto::DataSource { + public: + void OnSetup(const SetupArgs&) override {} + void OnStart(const StartArgs&) override { started_.Signal(); } + void OnStop(const StopArgs&) override {} + + static v8::base::Semaphore started_; +}; + +v8::base::Semaphore V8DataSource::started_{0}; + +PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(V8DataSource); #endif // V8_USE_PERFETTO namespace v8 { @@ -171,43 +184,38 @@ uint64_t TracingController::AddTraceEventWithTimestamp( int64_t cpu_now_us = CurrentCpuTimestampMicroseconds(); #ifdef V8_USE_PERFETTO - if (perfetto_recording_.load()) { // Don't use COMPLETE events with perfetto - instead transform them into // BEGIN/END pairs. This avoids the need for a thread-local stack of pending // trace events as perfetto does not support handles into the trace buffer. if (phase == TRACE_EVENT_PHASE_COMPLETE) phase = TRACE_EVENT_PHASE_BEGIN; - ::perfetto::TraceWriter* writer = - perfetto_tracing_controller_->GetOrCreateThreadLocalWriter(); - // TODO(petermarshall): We shouldn't start one packet for each event. - // We should try to bundle them together in one bundle. - auto packet = writer->NewTracePacket(); - auto* trace_event_bundle = packet->set_chrome_events(); - auto* trace_event = trace_event_bundle->add_trace_events(); - trace_event->set_name(name); - trace_event->set_timestamp(timestamp); - trace_event->set_phase(phase); - trace_event->set_thread_id(base::OS::GetCurrentThreadId()); - trace_event->set_duration(0); - trace_event->set_thread_duration(0); - if (scope) trace_event->set_scope(scope); - trace_event->set_id(id); - trace_event->set_flags(flags); - if (category_enabled_flag) { - const char* category_group_name = - GetCategoryGroupName(category_enabled_flag); - DCHECK_NOT_NULL(category_group_name); - trace_event->set_category_group_name(category_group_name); - } - trace_event->set_process_id(base::OS::GetCurrentProcessId()); - trace_event->set_thread_timestamp(cpu_now_us); - trace_event->set_bind_id(bind_id); + V8DataSource::Trace([&](V8DataSource::TraceContext ctx) { + auto packet = ctx.NewTracePacket(); + auto* trace_event_bundle = packet->set_chrome_events(); + auto* trace_event = trace_event_bundle->add_trace_events(); - AddArgsToTraceProto(trace_event, num_args, arg_names, arg_types, arg_values, - arg_convertables); + trace_event->set_name(name); + trace_event->set_timestamp(timestamp); + trace_event->set_phase(phase); + trace_event->set_thread_id(base::OS::GetCurrentThreadId()); + trace_event->set_duration(0); + trace_event->set_thread_duration(0); + if (scope) trace_event->set_scope(scope); + trace_event->set_id(id); + trace_event->set_flags(flags); + if (category_enabled_flag) { + const char* category_group_name = + GetCategoryGroupName(category_enabled_flag); + DCHECK_NOT_NULL(category_group_name); + trace_event->set_category_group_name(category_group_name); + } + trace_event->set_process_id(base::OS::GetCurrentProcessId()); + trace_event->set_thread_timestamp(cpu_now_us); + trace_event->set_bind_id(bind_id); - packet->Finalize(); - } + AddArgsToTraceProto(trace_event, num_args, arg_names, arg_types, + arg_values, arg_convertables); + }); #endif // V8_USE_PERFETTO uint64_t handle = 0; @@ -232,15 +240,8 @@ void TracingController::UpdateTraceEventDuration( int64_t cpu_now_us = CurrentCpuTimestampMicroseconds(); #ifdef V8_USE_PERFETTO - // TODO(petermarshall): Should we still record the end of unfinished events - // when tracing has stopped? - if (perfetto_recording_.load()) { - // TODO(petermarshall): We shouldn't start one packet for each event. We - // should try to bundle them together in one bundle. - ::perfetto::TraceWriter* writer = - perfetto_tracing_controller_->GetOrCreateThreadLocalWriter(); - - auto packet = writer->NewTracePacket(); + V8DataSource::Trace([&](V8DataSource::TraceContext ctx) { + auto packet = ctx.NewTracePacket(); auto* trace_event_bundle = packet->set_chrome_events(); auto* trace_event = trace_event_bundle->add_trace_events(); @@ -249,9 +250,7 @@ void TracingController::UpdateTraceEventDuration( trace_event->set_timestamp(now_us); trace_event->set_process_id(base::OS::GetCurrentProcessId()); trace_event->set_thread_timestamp(cpu_now_us); - - packet->Finalize(); - } + }); #endif // V8_USE_PERFETTO TraceObject* trace_object = trace_buffer_->GetEventByHandle(handle); @@ -277,24 +276,27 @@ const char* TracingController::GetCategoryGroupName( void TracingController::StartTracing(TraceConfig* trace_config) { #ifdef V8_USE_PERFETTO - perfetto_tracing_controller_ = base::make_unique(); - - if (listener_for_testing_) { - perfetto_tracing_controller_->AddTraceEventListener(listener_for_testing_); - } DCHECK_NOT_NULL(output_stream_); DCHECK(output_stream_->good()); json_listener_ = base::make_unique(output_stream_); - perfetto_tracing_controller_->AddTraceEventListener(json_listener_.get()); - ::perfetto::TraceConfig perfetto_trace_config; + // TODO(petermarshall): Set other the params for the config. + ::perfetto::TraceConfig perfetto_trace_config; perfetto_trace_config.add_buffers()->set_size_kb(4096); auto* ds_config = perfetto_trace_config.add_data_sources()->mutable_config(); ds_config->set_name("v8.trace_events"); - // TODO(petermarshall): Set all the params from |perfetto_trace_config|. - perfetto_tracing_controller_->StartTracing(perfetto_trace_config); - perfetto_recording_.store(true); + perfetto::DataSourceDescriptor dsd; + dsd.set_name("v8.trace_events"); + V8DataSource::Register(dsd); + + tracing_session_ = + perfetto::Tracing::NewTrace(perfetto::BackendType::kUnspecifiedBackend); + tracing_session_->Setup(perfetto_trace_config); + // TODO(petermarshall): Switch to StartBlocking when available. + tracing_session_->Start(); + V8DataSource::started_.Wait(); + #endif // V8_USE_PERFETTO trace_config_.reset(trace_config); @@ -327,10 +329,17 @@ void TracingController::StopTracing() { } #ifdef V8_USE_PERFETTO - perfetto_recording_.store(false); - perfetto_tracing_controller_->StopTracing(); - perfetto_tracing_controller_.reset(); + base::Semaphore stopped_{0}; + tracing_session_->SetOnStopCallback([&stopped_]() { stopped_.Signal(); }); + tracing_session_->Stop(); + stopped_.Wait(); + + std::vector trace = tracing_session_->ReadTraceBlocking(); + json_listener_->ParseFromArray(trace); + if (listener_for_testing_) listener_for_testing_->ParseFromArray(trace); + json_listener_.reset(); + #endif // V8_USE_PERFETTO { diff --git a/test/cctest/BUILD.gn b/test/cctest/BUILD.gn index 096c2fd39c..ac0d51faca 100644 --- a/test/cctest/BUILD.gn +++ b/test/cctest/BUILD.gn @@ -32,6 +32,10 @@ v8_executable("cctest") { ldflags = [] + if (v8_use_perfetto) { + deps += [ "//third_party/perfetto/include/perfetto/tracing" ] + } + # TODO(machenbach): Translate from gyp. #["OS=="aix"", { # "ldflags": [ "-Wl,-bbigtoc" ], @@ -417,7 +421,11 @@ v8_source_set("cctest_sources") { } if (v8_use_perfetto) { - deps += [ "//third_party/perfetto/protos/perfetto/trace/chrome:minimal_complete_lite" ] + deps += [ + "//third_party/perfetto/include/perfetto/tracing", + "//third_party/perfetto/protos/perfetto/trace/chrome:lite", + "//third_party/perfetto/protos/perfetto/trace/chrome:zero", + ] } } diff --git a/test/cctest/DEPS b/test/cctest/DEPS index 7210fb5317..909e60372e 100644 --- a/test/cctest/DEPS +++ b/test/cctest/DEPS @@ -1,4 +1,5 @@ include_rules = [ "+src", - "+torque-generated" + "+torque-generated", + "+perfetto/tracing.h" ] diff --git a/test/cctest/cctest.cc b/test/cctest/cctest.cc index 6e71d528a8..d1477ac6cc 100644 --- a/test/cctest/cctest.cc +++ b/test/cctest/cctest.cc @@ -39,6 +39,10 @@ #include "test/cctest/profiler-extension.h" #include "test/cctest/trace-extension.h" +#ifdef V8_USE_PERFETTO +#include "perfetto/tracing.h" +#endif // V8_USE_PERFETTO + #if V8_OS_WIN #include // NOLINT #if V8_CC_MSVC @@ -270,7 +274,6 @@ static void SuggestTestHarness(int tests) { "bogus failure. Consider using tools/run-tests.py instead.\n"); } - int main(int argc, char* argv[]) { #if V8_OS_WIN UINT new_flags = @@ -302,6 +305,12 @@ int main(int argc, char* argv[]) { } } +#ifdef V8_USE_PERFETTO + perfetto::TracingInitArgs init_args; + init_args.backends = perfetto::BackendType::kInProcessBackend; + perfetto::Tracing::Initialize(init_args); +#endif // V8_USE_PERFETTO + v8::V8::InitializeICUDefaultLocation(argv[0]); std::unique_ptr platform(v8::platform::NewDefaultPlatform()); v8::V8::InitializePlatform(platform.get()); diff --git a/test/cctest/libplatform/test-tracing.cc b/test/cctest/libplatform/test-tracing.cc index 8194e6aef4..4ecc4cf1e3 100644 --- a/test/cctest/libplatform/test-tracing.cc +++ b/test/cctest/libplatform/test-tracing.cc @@ -11,9 +11,28 @@ #ifdef V8_USE_PERFETTO #include "perfetto/trace/chrome/chrome_trace_event.pb.h" +#include "perfetto/trace/chrome/chrome_trace_event.pbzero.h" #include "perfetto/trace/chrome/chrome_trace_packet.pb.h" +#include "perfetto/trace/trace.pb.h" +#include "perfetto/tracing.h" +#include "src/libplatform/tracing/json-trace-event-listener.h" #include "src/libplatform/tracing/trace-event-listener.h" -#endif +#endif // V8_USE_PERFETTO + +#ifdef V8_USE_PERFETTO +class TestDataSource : public perfetto::DataSource { + public: + void OnSetup(const SetupArgs&) override {} + void OnStart(const StartArgs&) override { started_.Signal(); } + void OnStop(const StopArgs&) override {} + + static v8::base::Semaphore started_; +}; + +v8::base::Semaphore TestDataSource::started_{0}; + +PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(TestDataSource); +#endif // V8_USE_PERFETTO namespace v8 { namespace platform { @@ -552,8 +571,7 @@ struct TraceEvent { class TestListener : public TraceEventListener { public: - void ProcessPacket( - const ::perfetto::protos::ChromeTracePacket& packet) override { + void ProcessPacket(const ::perfetto::protos::TracePacket& packet) { for (const ::perfetto::protos::ChromeTraceEvent& event : packet.chrome_events().trace_events()) { TraceEvent trace_event{event.name(), event.timestamp(), @@ -683,6 +701,54 @@ TEST(Perfetto) { CHECK_EQ(6, harness.events_size()); } +TEST(TracingPerfetto) { + ::perfetto::TraceConfig perfetto_trace_config; + perfetto_trace_config.add_buffers()->set_size_kb(4096); + auto* ds_config = perfetto_trace_config.add_data_sources()->mutable_config(); + ds_config->set_name("v8.trace_events"); + + perfetto::DataSourceDescriptor dsd; + dsd.set_name("v8.trace_events"); + TestDataSource::Register(dsd); + + auto tracing_session_ = + perfetto::Tracing::NewTrace(perfetto::BackendType::kInProcessBackend); + tracing_session_->Setup(perfetto_trace_config); + tracing_session_->Start(); + TestDataSource::started_.Wait(); + + for (int i = 0; i < 15; i++) { + TestDataSource::Trace([&](TestDataSource::TraceContext ctx) { + auto packet = ctx.NewTracePacket(); + auto* trace_event_bundle = packet->set_chrome_events(); + auto* trace_event = trace_event_bundle->add_trace_events(); + + trace_event->set_phase('c'); + trace_event->set_thread_id(v8::base::OS::GetCurrentThreadId()); + trace_event->set_timestamp(123); + trace_event->set_process_id(v8::base::OS::GetCurrentProcessId()); + trace_event->set_thread_timestamp(123); + }); + } + v8::base::Semaphore stopped_{0}; + tracing_session_->SetOnStopCallback([&stopped_]() { stopped_.Signal(); }); + tracing_session_->Stop(); + stopped_.Wait(); + + std::ostringstream perfetto_json_stream_; + + { + v8::platform::tracing::JSONTraceEventListener json_listener_( + &perfetto_json_stream_); + + std::vector trace = tracing_session_->ReadTraceBlocking(); + json_listener_.ParseFromArray(trace); + } + + printf("%s\n", perfetto_json_stream_.str().c_str()); + CHECK_GT(perfetto_json_stream_.str().length(), 0); +} + #endif // V8_USE_PERFETTO } // namespace tracing