2024-04-19 15:07:36 +00:00
|
|
|
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
|
2024-10-07 22:51:08 +00:00
|
|
|
index 251f51ec454f9cba4023b8b6729241ee753aac13..1de8cac6e3953ce9cab9db03530da327199acfd5 100644
|
2024-04-19 15:07:36 +00:00
|
|
|
--- a/lib/internal/http.js
|
|
|
|
+++ b/lib/internal/http.js
|
2024-10-07 22:51:08 +00:00
|
|
|
@@ -8,8 +8,8 @@ const {
|
2024-04-19 15:07:36 +00:00
|
|
|
const { setUnrefTimeout } = require('internal/timers');
|
2024-08-26 19:09:33 +00:00
|
|
|
const { getCategoryEnabledBuffer, trace } = internalBinding('trace_events');
|
2024-04-19 15:07:36 +00:00
|
|
|
const {
|
|
|
|
- CHAR_LOWERCASE_B,
|
|
|
|
- CHAR_LOWERCASE_E,
|
|
|
|
+ CHAR_UPPERCASE_B,
|
|
|
|
+ CHAR_UPPERCASE_E,
|
|
|
|
} = require('internal/constants');
|
|
|
|
|
|
|
|
let utcCache;
|
2024-10-07 22:51:08 +00:00
|
|
|
@@ -44,11 +44,13 @@ function isTraceHTTPEnabled() {
|
2024-04-19 15:07:36 +00:00
|
|
|
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
|