|
@@ -0,0 +1,370 @@
|
|
|
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
+From: Shelley Vohr <[email protected]>
|
|
|
+Date: Wed, 17 Apr 2024 08:17:49 -0400
|
|
|
+Subject: build: enable perfetto
|
|
|
+
|
|
|
+Enable perfetto by default in Node.js. Node.js disables perfetto by
|
|
|
+default but is broken on build - they don't currently add guards for
|
|
|
+`V8_USE_PERFETTO` and upstream only defines certain functions
|
|
|
+on `v8::TracingController` if perfetto is disabled. Electron already
|
|
|
+had minimal to no support for Node.js trace events, so the impact of
|
|
|
+adding associated guards there should be relatively small.
|
|
|
+
|
|
|
+We should upstream this as it will eventually impact Node.js as well.
|
|
|
+
|
|
|
+diff --git a/lib/internal/constants.js b/lib/internal/constants.js
|
|
|
+index 8d7204f6cb48f783adc4d1c1eb2de0c83b7fffe2..a154559a56bf383d3c26af523c9bb07b564ef600 100644
|
|
|
+--- a/lib/internal/constants.js
|
|
|
++++ b/lib/internal/constants.js
|
|
|
+@@ -5,12 +5,15 @@ const isWindows = process.platform === 'win32';
|
|
|
+ module.exports = {
|
|
|
+ // Alphabet chars.
|
|
|
+ CHAR_UPPERCASE_A: 65, /* A */
|
|
|
++ CHAR_UPPERCASE_B: 66, /* B */
|
|
|
+ CHAR_LOWERCASE_A: 97, /* a */
|
|
|
+ CHAR_UPPERCASE_Z: 90, /* Z */
|
|
|
+ CHAR_LOWERCASE_Z: 122, /* z */
|
|
|
+ CHAR_UPPERCASE_C: 67, /* C */
|
|
|
+ CHAR_LOWERCASE_B: 98, /* b */
|
|
|
++ CHAR_UPPERCASE_E: 69, /* E */
|
|
|
+ CHAR_LOWERCASE_E: 101, /* e */
|
|
|
++
|
|
|
+ CHAR_LOWERCASE_N: 110, /* n */
|
|
|
+
|
|
|
+ // Non-alphabetic chars.
|
|
|
+diff --git a/lib/internal/http.js b/lib/internal/http.js
|
|
|
+index b20b3cd229efcd9701791309361b7d106f315900..6b2820c9dcce5e658b694f53e75d93707c4320d7 100644
|
|
|
+--- a/lib/internal/http.js
|
|
|
++++ b/lib/internal/http.js
|
|
|
+@@ -10,8 +10,8 @@ const {
|
|
|
+ const { setUnrefTimeout } = require('internal/timers');
|
|
|
+ const { trace, isTraceCategoryEnabled } = internalBinding('trace_events');
|
|
|
+ const {
|
|
|
+- CHAR_LOWERCASE_B,
|
|
|
+- CHAR_LOWERCASE_E,
|
|
|
++ CHAR_UPPERCASE_B,
|
|
|
++ CHAR_UPPERCASE_E,
|
|
|
+ } = require('internal/constants');
|
|
|
+
|
|
|
+ let utcCache;
|
|
|
+@@ -44,11 +44,13 @@ function isTraceHTTPEnabled() {
|
|
|
+ const traceEventCategory = 'node,node.http';
|
|
|
+
|
|
|
+ function traceBegin(...args) {
|
|
|
+- trace(CHAR_LOWERCASE_B, traceEventCategory, ...args);
|
|
|
++ // See v8/src/builtins/builtins-trace.cc - must be uppercase for perfetto
|
|
|
++ trace(CHAR_UPPERCASE_B, traceEventCategory, ...args);
|
|
|
+ }
|
|
|
+
|
|
|
+ function traceEnd(...args) {
|
|
|
+- trace(CHAR_LOWERCASE_E, traceEventCategory, ...args);
|
|
|
++ // See v8/src/builtins/builtins-trace.cc - must be uppercase for perfetto
|
|
|
++ trace(CHAR_UPPERCASE_E, traceEventCategory, ...args);
|
|
|
+ }
|
|
|
+
|
|
|
+ module.exports = {
|
|
|
+diff --git a/src/tracing/agent.cc b/src/tracing/agent.cc
|
|
|
+index 7ce59674356f9743438350949be42fa7ead2afbe..c5fedc3be86a77730c57321b9c73cc8e94a001d7 100644
|
|
|
+--- a/src/tracing/agent.cc
|
|
|
++++ b/src/tracing/agent.cc
|
|
|
+@@ -50,7 +50,9 @@ using v8::platform::tracing::TraceWriter;
|
|
|
+ using std::string;
|
|
|
+
|
|
|
+ Agent::Agent() : tracing_controller_(new TracingController()) {
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ tracing_controller_->Initialize(nullptr);
|
|
|
++#endif
|
|
|
+
|
|
|
+ CHECK_EQ(uv_loop_init(&tracing_loop_), 0);
|
|
|
+ CHECK_EQ(uv_async_init(&tracing_loop_,
|
|
|
+@@ -86,10 +88,14 @@ Agent::~Agent() {
|
|
|
+ void Agent::Start() {
|
|
|
+ if (started_)
|
|
|
+ return;
|
|
|
+-
|
|
|
++#ifdef V8_USE_PERFETTO
|
|
|
++ std::ostringstream perfetto_output;
|
|
|
++ tracing_controller_->InitializeForPerfetto(&perfetto_output);
|
|
|
++#else
|
|
|
+ NodeTraceBuffer* trace_buffer_ = new NodeTraceBuffer(
|
|
|
+ NodeTraceBuffer::kBufferChunks, this, &tracing_loop_);
|
|
|
+ tracing_controller_->Initialize(trace_buffer_);
|
|
|
++#endif
|
|
|
+
|
|
|
+ // This thread should be created *after* async handles are created
|
|
|
+ // (within NodeTraceWriter and NodeTraceBuffer constructors).
|
|
|
+@@ -143,8 +149,10 @@ void Agent::StopTracing() {
|
|
|
+ return;
|
|
|
+ // Perform final Flush on TraceBuffer. We don't want the tracing controller
|
|
|
+ // to flush the buffer again on destruction of the V8::Platform.
|
|
|
+- tracing_controller_->StopTracing();
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ tracing_controller_->Initialize(nullptr);
|
|
|
++#endif
|
|
|
++ tracing_controller_->StopTracing();
|
|
|
+ started_ = false;
|
|
|
+
|
|
|
+ // Thread should finish when the tracing loop is stopped.
|
|
|
+@@ -202,6 +210,7 @@ std::string Agent::GetEnabledCategories() const {
|
|
|
+ return categories;
|
|
|
+ }
|
|
|
+
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ void Agent::AppendTraceEvent(TraceObject* trace_event) {
|
|
|
+ for (const auto& id_writer : writers_)
|
|
|
+ id_writer.second->AppendTraceEvent(trace_event);
|
|
|
+@@ -211,18 +220,21 @@ void Agent::AddMetadataEvent(std::unique_ptr<TraceObject> event) {
|
|
|
+ Mutex::ScopedLock lock(metadata_events_mutex_);
|
|
|
+ metadata_events_.push_back(std::move(event));
|
|
|
+ }
|
|
|
++#endif
|
|
|
+
|
|
|
+ void Agent::Flush(bool blocking) {
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ {
|
|
|
+ Mutex::ScopedLock lock(metadata_events_mutex_);
|
|
|
+ for (const auto& event : metadata_events_)
|
|
|
+ AppendTraceEvent(event.get());
|
|
|
+ }
|
|
|
+-
|
|
|
++#endif
|
|
|
+ for (const auto& id_writer : writers_)
|
|
|
+ id_writer.second->Flush(blocking);
|
|
|
+ }
|
|
|
+
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ void TracingController::AddMetadataEvent(
|
|
|
+ const unsigned char* category_group_enabled,
|
|
|
+ const char* name,
|
|
|
+@@ -246,6 +258,6 @@ void TracingController::AddMetadataEvent(
|
|
|
+ if (node_agent != nullptr)
|
|
|
+ node_agent->AddMetadataEvent(std::move(trace_event));
|
|
|
+ }
|
|
|
+-
|
|
|
++#endif
|
|
|
+ } // namespace tracing
|
|
|
+ } // namespace node
|
|
|
+diff --git a/src/tracing/agent.h b/src/tracing/agent.h
|
|
|
+index b542a849fe8da7e8bbbcca7067b73dc32b18d6d3..059ce6f6ea17199ead09c6c13bcc680f18f8c4d0 100644
|
|
|
+--- a/src/tracing/agent.h
|
|
|
++++ b/src/tracing/agent.h
|
|
|
+@@ -27,7 +27,9 @@ class Agent;
|
|
|
+ class AsyncTraceWriter {
|
|
|
+ public:
|
|
|
+ virtual ~AsyncTraceWriter() = default;
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ virtual void AppendTraceEvent(TraceObject* trace_event) = 0;
|
|
|
++#endif
|
|
|
+ virtual void Flush(bool blocking) = 0;
|
|
|
+ virtual void InitializeOnThread(uv_loop_t* loop) {}
|
|
|
+ };
|
|
|
+@@ -36,6 +38,7 @@ class TracingController : public v8::platform::tracing::TracingController {
|
|
|
+ public:
|
|
|
+ TracingController() : v8::platform::tracing::TracingController() {}
|
|
|
+
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ int64_t CurrentTimestampMicroseconds() override {
|
|
|
+ return uv_hrtime() / 1000;
|
|
|
+ }
|
|
|
+@@ -48,6 +51,7 @@ class TracingController : public v8::platform::tracing::TracingController {
|
|
|
+ const uint64_t* arg_values,
|
|
|
+ std::unique_ptr<v8::ConvertableToTraceFormat>* convertable_values,
|
|
|
+ unsigned int flags);
|
|
|
++#endif
|
|
|
+ };
|
|
|
+
|
|
|
+ class AgentWriterHandle {
|
|
|
+@@ -108,11 +112,12 @@ class Agent {
|
|
|
+
|
|
|
+ // Returns a comma-separated list of enabled categories.
|
|
|
+ std::string GetEnabledCategories() const;
|
|
|
+-
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ // Writes to all writers registered through AddClient().
|
|
|
+ void AppendTraceEvent(TraceObject* trace_event);
|
|
|
+
|
|
|
+ void AddMetadataEvent(std::unique_ptr<TraceObject> event);
|
|
|
++#endif
|
|
|
+ // Flushes all writers registered through AddClient().
|
|
|
+ void Flush(bool blocking);
|
|
|
+
|
|
|
+@@ -152,7 +157,9 @@ class Agent {
|
|
|
+ std::set<AsyncTraceWriter*> to_be_initialized_;
|
|
|
+
|
|
|
+ Mutex metadata_events_mutex_;
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ std::list<std::unique_ptr<TraceObject>> metadata_events_;
|
|
|
++#endif
|
|
|
+ };
|
|
|
+
|
|
|
+ void AgentWriterHandle::reset() {
|
|
|
+diff --git a/src/tracing/node_trace_buffer.cc b/src/tracing/node_trace_buffer.cc
|
|
|
+index e187a1d78c81972b69cd4e03f7079cdb727956ad..3256c6326a08c6cafd83f1e49e3350193e813b51 100644
|
|
|
+--- a/src/tracing/node_trace_buffer.cc
|
|
|
++++ b/src/tracing/node_trace_buffer.cc
|
|
|
+@@ -55,6 +55,7 @@ TraceObject* InternalTraceBuffer::GetEventByHandle(uint64_t handle) {
|
|
|
+ }
|
|
|
+
|
|
|
+ void InternalTraceBuffer::Flush(bool blocking) {
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ {
|
|
|
+ Mutex::ScopedLock scoped_lock(mutex_);
|
|
|
+ if (total_chunks_ > 0) {
|
|
|
+@@ -75,6 +76,7 @@ void InternalTraceBuffer::Flush(bool blocking) {
|
|
|
+ flushing_ = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
++#endif
|
|
|
+ agent_->Flush(blocking);
|
|
|
+ }
|
|
|
+
|
|
|
+diff --git a/src/tracing/node_trace_writer.cc b/src/tracing/node_trace_writer.cc
|
|
|
+index 8f053efe93324b9acbb4e85f7b974b4f7712e200..e331ed5567caa39ade90ce28cea69f1d10533812 100644
|
|
|
+--- a/src/tracing/node_trace_writer.cc
|
|
|
++++ b/src/tracing/node_trace_writer.cc
|
|
|
+@@ -95,7 +95,7 @@ void NodeTraceWriter::OpenNewFileForStreaming() {
|
|
|
+ fd_ = -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+-
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ void NodeTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
|
|
|
+ Mutex::ScopedLock scoped_lock(stream_mutex_);
|
|
|
+ // If this is the first trace event, open a new file for streaming.
|
|
|
+@@ -112,7 +112,7 @@ void NodeTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
|
|
|
+ ++total_traces_;
|
|
|
+ json_trace_writer_->AppendTraceEvent(trace_event);
|
|
|
+ }
|
|
|
+-
|
|
|
++#endif
|
|
|
+ void NodeTraceWriter::FlushPrivate() {
|
|
|
+ std::string str;
|
|
|
+ int highest_request_id;
|
|
|
+diff --git a/src/tracing/node_trace_writer.h b/src/tracing/node_trace_writer.h
|
|
|
+index cd965d77b7859ff2edcf781a934594b5a9b6d251..fe1714ba77fddef693d37eeb8c7a196ddfd15c26 100644
|
|
|
+--- a/src/tracing/node_trace_writer.h
|
|
|
++++ b/src/tracing/node_trace_writer.h
|
|
|
+@@ -20,7 +20,9 @@ class NodeTraceWriter : public AsyncTraceWriter {
|
|
|
+ ~NodeTraceWriter() override;
|
|
|
+
|
|
|
+ void InitializeOnThread(uv_loop_t* loop) override;
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ void AppendTraceEvent(TraceObject* trace_event) override;
|
|
|
++#endif
|
|
|
+ void Flush(bool blocking) override;
|
|
|
+
|
|
|
+ static const int kTracesPerFile = 1 << 19;
|
|
|
+diff --git a/src/tracing/trace_event.h b/src/tracing/trace_event.h
|
|
|
+index be0f55a409a71bf9c1763c36fdc252857228742e..827b5330b2f8c545338a46c548f8abf4aab7f50c 100644
|
|
|
+--- a/src/tracing/trace_event.h
|
|
|
++++ b/src/tracing/trace_event.h
|
|
|
+@@ -69,8 +69,16 @@ enum CategoryGroupEnabledFlags {
|
|
|
+ // for best performance when tracing is disabled.
|
|
|
+ // const uint8_t*
|
|
|
+ // TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ #define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \
|
|
|
+ node::tracing::TraceEventHelper::GetCategoryGroupEnabled
|
|
|
++#else
|
|
|
++#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group) \
|
|
|
++ ([](const char*) -> const uint8_t* { \
|
|
|
++ static uint8_t no = 0; \
|
|
|
++ return &no; \
|
|
|
++ })(category_group)
|
|
|
++#endif
|
|
|
+
|
|
|
+ // Get the number of times traces have been recorded. This is used to implement
|
|
|
+ // the TRACE_EVENT_IS_NEW_TRACE facility.
|
|
|
+@@ -114,10 +122,15 @@ enum CategoryGroupEnabledFlags {
|
|
|
+ // const uint8_t* category_group_enabled,
|
|
|
+ // const char* name,
|
|
|
+ // uint64_t id)
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ #define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
|
|
|
+ if (auto controller = \
|
|
|
+ node::tracing::TraceEventHelper::GetTracingController()) \
|
|
|
+ controller->UpdateTraceEventDuration
|
|
|
++#else
|
|
|
++#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled, name, event_handle) \
|
|
|
++ (void)(category_group_enabled), (void)(name), (void)(event_handle)
|
|
|
++#endif
|
|
|
+
|
|
|
+ // Adds a metadata event to the trace log. The |AppendValueAsTraceFormat| method
|
|
|
+ // on the convertable value will be called at flush time.
|
|
|
+@@ -319,10 +332,13 @@ class TraceEventHelper {
|
|
|
+ static void SetAgent(Agent* agent);
|
|
|
+
|
|
|
+ static inline const uint8_t* GetCategoryGroupEnabled(const char* group) {
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ v8::TracingController* controller = GetTracingController();
|
|
|
+ static const uint8_t disabled = 0;
|
|
|
+ if (UNLIKELY(controller == nullptr)) return &disabled;
|
|
|
+ return controller->GetCategoryGroupEnabled(group);
|
|
|
++#endif
|
|
|
++ return 0;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+@@ -460,6 +476,7 @@ static inline uint64_t AddTraceEventImpl(
|
|
|
+ const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
|
|
|
+ const char** arg_names, const uint8_t* arg_types,
|
|
|
+ const uint64_t* arg_values, unsigned int flags) {
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
|
|
|
+ if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
|
|
|
+ arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
|
|
+@@ -469,13 +486,14 @@ static inline uint64_t AddTraceEventImpl(
|
|
|
+ arg_convertibles[1].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
|
|
+ static_cast<intptr_t>(arg_values[1])));
|
|
|
+ }
|
|
|
+- // DCHECK(num_args, 2);
|
|
|
+ v8::TracingController* controller =
|
|
|
+ node::tracing::TraceEventHelper::GetTracingController();
|
|
|
+ if (controller == nullptr) return 0;
|
|
|
+ return controller->AddTraceEvent(phase, category_group_enabled, name, scope, id,
|
|
|
+ bind_id, num_args, arg_names, arg_types,
|
|
|
+ arg_values, arg_convertibles, flags);
|
|
|
++#endif
|
|
|
++ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
|
|
|
+@@ -483,6 +501,7 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
|
|
|
+ const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
|
|
|
+ const char** arg_names, const uint8_t* arg_types,
|
|
|
+ const uint64_t* arg_values, unsigned int flags, int64_t timestamp) {
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertables[2];
|
|
|
+ if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
|
|
|
+ arg_convertables[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
|
|
+@@ -492,19 +511,21 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
|
|
|
+ arg_convertables[1].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
|
|
+ static_cast<intptr_t>(arg_values[1])));
|
|
|
+ }
|
|
|
+- // DCHECK_LE(num_args, 2);
|
|
|
+ v8::TracingController* controller =
|
|
|
+ node::tracing::TraceEventHelper::GetTracingController();
|
|
|
+ if (controller == nullptr) return 0;
|
|
|
+ return controller->AddTraceEventWithTimestamp(
|
|
|
+ phase, category_group_enabled, name, scope, id, bind_id, num_args,
|
|
|
+ arg_names, arg_types, arg_values, arg_convertables, flags, timestamp);
|
|
|
++#endif
|
|
|
++ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ static V8_INLINE void AddMetadataEventImpl(
|
|
|
+ const uint8_t* category_group_enabled, const char* name, int32_t num_args,
|
|
|
+ const char** arg_names, const uint8_t* arg_types,
|
|
|
+ const uint64_t* arg_values, unsigned int flags) {
|
|
|
++#ifndef V8_USE_PERFETTO
|
|
|
+ std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
|
|
|
+ if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
|
|
|
+ arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
|
|
+@@ -520,6 +541,7 @@ static V8_INLINE void AddMetadataEventImpl(
|
|
|
+ return agent->GetTracingController()->AddMetadataEvent(
|
|
|
+ category_group_enabled, name, num_args, arg_names, arg_types, arg_values,
|
|
|
+ arg_convertibles, flags);
|
|
|
++#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ // Define SetTraceValue for each allowed type. It stores the type and
|