From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
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
