mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
4 Commits
remove-dec
...
robo/enabl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22c8b7cf17 | ||
|
|
26f169d9d1 | ||
|
|
15416ef8e4 | ||
|
|
2d4e638722 |
@@ -151,3 +151,4 @@ fix_pulseaudio_stream_and_icon_names.patch
|
||||
fix_fire_menu_popup_start_for_dynamically_created_aria_menus.patch
|
||||
feat_allow_enabling_extensions_on_custom_protocols.patch
|
||||
fix_initialize_com_on_desktopmedialistcapturethread_on_windows.patch
|
||||
chore_register_node_as_a_dynamic_trace_category_prefix.patch
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: deepak1556 <hop2deep@gmail.com>
|
||||
Date: Tue, 31 Mar 2026 09:03:39 +0900
|
||||
Subject: chore: register node as a dynamic trace category prefix
|
||||
|
||||
This allows Node.js trace categories to be treated as dynamic Perfetto
|
||||
categories in the Chromium build. Without this, the categories
|
||||
must be registered in the static registry base/trace_event/builtin_categories.h
|
||||
which is backed by constexpr function ValidateCategories() that
|
||||
recursively validates to a depth of index + longest_category_name_length,
|
||||
adding the node categories exceeds the current constexpr recursion depth
|
||||
of 512 and requires additional patching to add `-fconstexpr-depth` to //base
|
||||
target. Given neither the static nor the dynamic registration can be
|
||||
upstreamed, the minimal of the two changes is chosen here.
|
||||
|
||||
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h
|
||||
index 85c6f973788938b6a48a7a89e9fa803dc1030580..ae25a8188d57ff4c15e9a20e91629d585314db87 100644
|
||||
--- a/base/trace_event/builtin_categories.h
|
||||
+++ b/base/trace_event/builtin_categories.h
|
||||
@@ -14,6 +14,7 @@ PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES("cat",
|
||||
"foo",
|
||||
"test",
|
||||
"kTest",
|
||||
+ "node",
|
||||
"noise",
|
||||
"Testing",
|
||||
"NotTesting",
|
||||
@@ -133,10 +133,10 @@ index 6fe4f0492dc1f3eaf576c8ff7866080a54cb81c1..41e8e052ff81df78ece87163b0499966
|
||||
// Recreate the buffer in the constructor.
|
||||
InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info);
|
||||
diff --git a/src/env.cc b/src/env.cc
|
||||
index b5cf58cc953590493beb52abf249e33e486ffc46..347ec5c42e098186ff489dff199ac5989961f6e3 100644
|
||||
index 57a46c8be2e052b298ed841eed6f291d62711750..e4ffaa465a4ffe21334496c52334fcb1404f67a9 100644
|
||||
--- a/src/env.cc
|
||||
+++ b/src/env.cc
|
||||
@@ -1765,10 +1765,10 @@ void AsyncHooks::Deserialize(Local<Context> context) {
|
||||
@@ -1764,10 +1764,10 @@ void AsyncHooks::Deserialize(Local<Context> context) {
|
||||
context->GetDataFromSnapshotOnce<Array>(
|
||||
info_->js_execution_async_resources).ToLocalChecked();
|
||||
} else {
|
||||
@@ -149,7 +149,7 @@ index b5cf58cc953590493beb52abf249e33e486ffc46..347ec5c42e098186ff489dff199ac598
|
||||
|
||||
// The native_execution_async_resources_ field requires v8::Local<> instances
|
||||
// for async calls whose resources were on the stack as JS objects when they
|
||||
@@ -1808,7 +1808,7 @@ AsyncHooks::SerializeInfo AsyncHooks::Serialize(Local<Context> context,
|
||||
@@ -1807,7 +1807,7 @@ AsyncHooks::SerializeInfo AsyncHooks::Serialize(Local<Context> context,
|
||||
info.async_id_fields = async_id_fields_.Serialize(context, creator);
|
||||
if (!js_execution_async_resources_.IsEmpty()) {
|
||||
info.js_execution_async_resources = creator->AddData(
|
||||
@@ -458,7 +458,7 @@ index fea0426496978c0003fe1481afcf93fc9c23edca..c9588880d05435ab9f4e23fcff74c933
|
||||
|
||||
CHECK(
|
||||
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
|
||||
index 3c234205e89be7e976dae5c3fcc73ca67953e034..e66d4fcb0c064f96cdb819c783027d864fe88d12 100644
|
||||
index 986a2d8da7fd04b5d4060d9c8d44c61a231dcce6..9f11d32c70366524cf3b7c1cfdfd24f31e438e7b 100644
|
||||
--- a/src/node_contextify.cc
|
||||
+++ b/src/node_contextify.cc
|
||||
@@ -113,7 +113,7 @@ namespace {
|
||||
@@ -479,7 +479,7 @@ index 3c234205e89be7e976dae5c3fcc73ca67953e034..e66d4fcb0c064f96cdb819c783027d86
|
||||
|
||||
PropertyAttribute attributes = PropertyAttribute::None;
|
||||
bool is_declared =
|
||||
@@ -1666,7 +1666,7 @@ static MaybeLocal<Function> CompileFunctionForCJSLoader(
|
||||
@@ -1665,7 +1665,7 @@ static MaybeLocal<Function> CompileFunctionForCJSLoader(
|
||||
bool* cache_rejected,
|
||||
bool is_cjs_scope,
|
||||
ScriptCompiler::CachedData* cached_data) {
|
||||
@@ -533,10 +533,10 @@ index 55a0c986c5b6989ee9ce277bb6a9778abb2ad2ee..809d88f21e5572807e38132d40ee7587
|
||||
READONLY_PROPERTY(target, "exitCodes", exit_codes);
|
||||
|
||||
diff --git a/src/node_file.cc b/src/node_file.cc
|
||||
index 96aac2d86695732bf6805f2ad2168a62241b5045..547455bb5011677719a8de1f98cb447561bce6aa 100644
|
||||
index c7a9648b0f83e910190dc620f4b72577ffde6c44..46cd16b535d9bd651ef733ca52ea58db7d39b09f 100644
|
||||
--- a/src/node_file.cc
|
||||
+++ b/src/node_file.cc
|
||||
@@ -3850,7 +3850,7 @@ void BindingData::Deserialize(Local<Context> context,
|
||||
@@ -3857,7 +3857,7 @@ void BindingData::Deserialize(Local<Context> context,
|
||||
int index,
|
||||
InternalFieldInfoBase* info) {
|
||||
DCHECK_IS_SNAPSHOT_SLOT(index);
|
||||
|
||||
@@ -14,10 +14,10 @@ We don't need to do this for zlib, as the existing gn workflow uses the same
|
||||
Upstreamed at https://github.com/nodejs/node/pull/55903
|
||||
|
||||
diff --git a/unofficial.gni b/unofficial.gni
|
||||
index bff7b0650cfe8578a044e45d0f9e352859909695..4ab316e45bd84e43a53335df60f847b17fe6c2fa 100644
|
||||
index a773152813376bef1fa227c331241a1d944c9317..43f09d1e68c88d3ba3b862a1a74769f73c370894 100644
|
||||
--- a/unofficial.gni
|
||||
+++ b/unofficial.gni
|
||||
@@ -199,7 +199,17 @@ template("node_gn_build") {
|
||||
@@ -203,7 +203,17 @@ template("node_gn_build") {
|
||||
configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
|
||||
configs += [ "//build/config/gcc:symbol_visibility_default" ]
|
||||
}
|
||||
@@ -36,7 +36,7 @@ index bff7b0650cfe8578a044e45d0f9e352859909695..4ab316e45bd84e43a53335df60f847b1
|
||||
if (v8_enable_i18n_support) {
|
||||
deps += [ "//third_party/icu" ]
|
||||
}
|
||||
@@ -232,6 +242,19 @@ template("node_gn_build") {
|
||||
@@ -236,6 +246,19 @@ template("node_gn_build") {
|
||||
sources += node_inspector.node_inspector_sources +
|
||||
node_inspector.node_inspector_generated_sources
|
||||
}
|
||||
|
||||
@@ -3,20 +3,14 @@ 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.
|
||||
Enable perfetto by default in Node.js and wire track events
|
||||
through legacy shim.
|
||||
|
||||
diff --git a/lib/internal/constants.js b/lib/internal/constants.js
|
||||
index 8d7204f6cb48f783adc4d1c1eb2de0c83b7fffe2..a154559a56bf383d3c26af523c9bb07b564ef600 100644
|
||||
index 8d7204f6cb48f783adc4d1c1eb2de0c83b7fffe2..8061013fcfe3c3b02aabaca0447069423ac853b2 100644
|
||||
--- a/lib/internal/constants.js
|
||||
+++ b/lib/internal/constants.js
|
||||
@@ -5,12 +5,15 @@ const isWindows = process.platform === 'win32';
|
||||
@@ -5,12 +5,16 @@ const isWindows = process.platform === 'win32';
|
||||
module.exports = {
|
||||
// Alphabet chars.
|
||||
CHAR_UPPERCASE_A: 65, /* A */
|
||||
@@ -28,61 +22,216 @@ index 8d7204f6cb48f783adc4d1c1eb2de0c83b7fffe2..a154559a56bf383d3c26af523c9bb07b
|
||||
CHAR_LOWERCASE_B: 98, /* b */
|
||||
+ CHAR_UPPERCASE_E: 69, /* E */
|
||||
CHAR_LOWERCASE_E: 101, /* e */
|
||||
+ CHAR_UPPERCASE_I: 73, /* I */
|
||||
+
|
||||
CHAR_LOWERCASE_N: 110, /* n */
|
||||
|
||||
// Non-alphabetic chars.
|
||||
diff --git a/lib/internal/http.js b/lib/internal/http.js
|
||||
index f8b4fd7c4ca5a0907806c7e804de8c951675a36a..209e3bcf8be5a23ac528dcd673bed82cbad709ca 100644
|
||||
index f8b4fd7c4ca5a0907806c7e804de8c951675a36a..0f924a5cc6718415226ffef5f8bc40a51043be04 100644
|
||||
--- a/lib/internal/http.js
|
||||
+++ b/lib/internal/http.js
|
||||
@@ -11,8 +11,8 @@ const {
|
||||
const { setUnrefTimeout } = require('internal/timers');
|
||||
const { getCategoryEnabledBuffer, trace } = internalBinding('trace_events');
|
||||
const {
|
||||
- CHAR_LOWERCASE_B,
|
||||
- CHAR_LOWERCASE_E,
|
||||
+ CHAR_UPPERCASE_B,
|
||||
+ CHAR_UPPERCASE_E,
|
||||
} = require('internal/constants');
|
||||
@@ -9,7 +9,7 @@ const {
|
||||
} = primordials;
|
||||
|
||||
const { URL } = require('internal/url');
|
||||
@@ -51,11 +51,13 @@ function isTraceHTTPEnabled() {
|
||||
const traceEventCategory = 'node,node.http';
|
||||
const { setUnrefTimeout } = require('internal/timers');
|
||||
-const { getCategoryEnabledBuffer, trace } = internalBinding('trace_events');
|
||||
+const { isTraceCategoryEnabled, trace } = internalBinding('trace_events');
|
||||
const {
|
||||
CHAR_LOWERCASE_B,
|
||||
CHAR_LOWERCASE_E,
|
||||
@@ -42,13 +42,11 @@ function getNextTraceEventId() {
|
||||
return ++traceEventId;
|
||||
}
|
||||
|
||||
-const httpEnabled = getCategoryEnabledBuffer('node.http');
|
||||
-
|
||||
function isTraceHTTPEnabled() {
|
||||
- return httpEnabled[0] > 0;
|
||||
+ return isTraceCategoryEnabled('node.http');
|
||||
}
|
||||
|
||||
-const traceEventCategory = 'node,node.http';
|
||||
+const traceEventCategory = '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);
|
||||
trace(CHAR_LOWERCASE_B, traceEventCategory, ...args);
|
||||
diff --git a/lib/internal/perf/usertiming.js b/lib/internal/perf/usertiming.js
|
||||
index 88bb63ead2d3d620dea6b54db043a404b484ead9..a37386bbf51b55b26a140cd81fbaf26d78015f21 100644
|
||||
--- a/lib/internal/perf/usertiming.js
|
||||
+++ b/lib/internal/perf/usertiming.js
|
||||
@@ -13,6 +13,12 @@ const { PerformanceEntry, kSkipThrow } = require('internal/perf/performance_entr
|
||||
const { now } = require('internal/perf/utils');
|
||||
const { enqueue, bufferUserTiming } = require('internal/perf/observe');
|
||||
const nodeTiming = require('internal/perf/nodetiming');
|
||||
+const { isTraceCategoryEnabled, trace } = internalBinding('trace_events');
|
||||
+const {
|
||||
+ CHAR_LOWERCASE_B,
|
||||
+ CHAR_LOWERCASE_E,
|
||||
+ CHAR_UPPERCASE_I
|
||||
+} = require('internal/constants');
|
||||
|
||||
const {
|
||||
validateNumber,
|
||||
@@ -41,6 +47,9 @@ const kDetail = Symbol('kDetail');
|
||||
|
||||
const markTimings = new SafeMap();
|
||||
|
||||
+const traceEventCategory = 'node.perf.usertiming';
|
||||
+let traceEventId = 0;
|
||||
+
|
||||
const nodeTimingReadOnlyAttributes = new SafeSet(new SafeArrayIterator([
|
||||
'nodeStart',
|
||||
'v8Start',
|
||||
@@ -168,6 +177,10 @@ function mark(name, options) {
|
||||
const mark = new PerformanceMark(name, options);
|
||||
enqueue(mark);
|
||||
bufferUserTiming(mark);
|
||||
+ if (isTraceCategoryEnabled(traceEventCategory)) {
|
||||
+ trace(CHAR_UPPERCASE_I, traceEventCategory, name, undefined,
|
||||
+ { startTime: mark.startTime });
|
||||
+ }
|
||||
return mark;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -233,6 +246,13 @@ function measure(name, startOrMeasureOptions, endMark) {
|
||||
const measure = createPerformanceMeasure(name, start, duration, detail);
|
||||
enqueue(measure);
|
||||
bufferUserTiming(measure);
|
||||
+ if (isTraceCategoryEnabled(traceEventCategory)) {
|
||||
+ const id = ++traceEventId;
|
||||
+ trace(CHAR_LOWERCASE_B, traceEventCategory, name, id,
|
||||
+ { startTime: start });
|
||||
+ trace(CHAR_LOWERCASE_E, traceEventCategory, name, id,
|
||||
+ { startTime: start, duration });
|
||||
+ }
|
||||
return measure;
|
||||
}
|
||||
|
||||
function ipToInt(ip) {
|
||||
diff --git a/lib/internal/trace_events_async_hooks.js b/lib/internal/trace_events_async_hooks.js
|
||||
index a9f517ffc9e4eea5bc68997ffadc85d43dde2a52..e85bcd2f500ff3f5bbd2b25922c13cb29de50993 100644
|
||||
--- a/lib/internal/trace_events_async_hooks.js
|
||||
+++ b/lib/internal/trace_events_async_hooks.js
|
||||
@@ -20,7 +20,7 @@ const {
|
||||
// the specific C++ macros.
|
||||
const kBeforeEvent = CHAR_LOWERCASE_B;
|
||||
const kEndEvent = CHAR_LOWERCASE_E;
|
||||
-const kTraceEventCategory = 'node,node.async_hooks';
|
||||
+const kTraceEventCategory = 'node.async_hooks';
|
||||
|
||||
const kEnabled = Symbol('enabled');
|
||||
|
||||
diff --git a/lib/internal/util/debuglog.js b/lib/internal/util/debuglog.js
|
||||
index 06a4f8a239855571dcc67cd81e7da7a255a9ebfd..1fa9e314ad796cdf74f718f0eb2a15530f5833d3 100644
|
||||
--- a/lib/internal/util/debuglog.js
|
||||
+++ b/lib/internal/util/debuglog.js
|
||||
@@ -20,7 +20,7 @@ const {
|
||||
CHAR_LOWERCASE_N: kTraceInstant,
|
||||
} = require('internal/constants');
|
||||
const { inspect, format, formatWithOptions } = require('internal/util/inspect');
|
||||
-const { getCategoryEnabledBuffer, trace } = internalBinding('trace_events');
|
||||
+const { isTraceCategoryEnabled, trace } = internalBinding('trace_events');
|
||||
|
||||
// `debugImpls` and `testEnabled` are deliberately not initialized so any call
|
||||
// to `debuglog()` before `initializeDebugEnv()` is called will throw.
|
||||
@@ -386,14 +386,13 @@ function debugWithTimer(set, cb) {
|
||||
}
|
||||
|
||||
const traceCategory = `node,node.${StringPrototypeToLowerCase(set)}`;
|
||||
- let traceCategoryBuffer;
|
||||
let debugLogCategoryEnabled = false;
|
||||
let timerFlags = kNone;
|
||||
|
||||
function ensureTimerFlagsAreUpdated() {
|
||||
timerFlags &= ~kSkipTrace;
|
||||
|
||||
- if (traceCategoryBuffer[0] === 0) {
|
||||
+ if (!isTraceCategoryEnabled(traceCategory)) {
|
||||
timerFlags |= kSkipTrace;
|
||||
}
|
||||
}
|
||||
@@ -467,7 +466,6 @@ function debugWithTimer(set, cb) {
|
||||
}
|
||||
emitWarningIfNeeded(set);
|
||||
debugLogCategoryEnabled = testEnabled(set);
|
||||
- traceCategoryBuffer = getCategoryEnabledBuffer(traceCategory);
|
||||
|
||||
timerFlags = kNone;
|
||||
|
||||
@@ -475,7 +473,7 @@ function debugWithTimer(set, cb) {
|
||||
timerFlags |= kSkipLog;
|
||||
}
|
||||
|
||||
- if (traceCategoryBuffer[0] === 0) {
|
||||
+ if (!isTraceCategoryEnabled(traceCategory)) {
|
||||
timerFlags |= kSkipTrace;
|
||||
}
|
||||
|
||||
diff --git a/node.gyp b/node.gyp
|
||||
index f5cd416b5fe7a51084bc4af9a4427a8e62599fd8..5eb70ce3820f2b82121bc102c5182ab768cbef36 100644
|
||||
index f5cd416b5fe7a51084bc4af9a4427a8e62599fd8..b7072ce74354495bec49357f962f4ef2999bf727 100644
|
||||
--- a/node.gyp
|
||||
+++ b/node.gyp
|
||||
@@ -182,7 +182,6 @@
|
||||
@@ -182,9 +182,9 @@
|
||||
'src/timers.cc',
|
||||
'src/timer_wrap.cc',
|
||||
'src/tracing/agent.cc',
|
||||
- 'src/tracing/node_trace_buffer.cc',
|
||||
'src/tracing/node_trace_writer.cc',
|
||||
'src/tracing/trace_event.cc',
|
||||
+ 'src/tracing/trace_categories.cc',
|
||||
'src/tracing/traced_value.cc',
|
||||
@@ -314,7 +313,6 @@
|
||||
'src/tty_wrap.cc',
|
||||
'src/udp_wrap.cc',
|
||||
@@ -314,9 +314,9 @@
|
||||
'src/tcp_wrap.h',
|
||||
'src/timers.h',
|
||||
'src/tracing/agent.h',
|
||||
- 'src/tracing/node_trace_buffer.h',
|
||||
'src/tracing/node_trace_writer.h',
|
||||
'src/tracing/trace_event.h',
|
||||
+ 'src/tracing/trace_categories.h',
|
||||
'src/tracing/trace_event_common.h',
|
||||
'src/tracing/traced_value.h',
|
||||
'src/timer_wrap.h',
|
||||
diff --git a/src/async_wrap.cc b/src/async_wrap.cc
|
||||
index 301f77c419f178c4eea258e0896327f69389dda7..d5068a18392a6128ceee7f0146f8f9c77f9924bb 100644
|
||||
--- a/src/async_wrap.cc
|
||||
+++ b/src/async_wrap.cc
|
||||
@@ -110,8 +110,7 @@ void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
|
||||
}
|
||||
|
||||
void AsyncWrap::EmitTraceAsyncStart() const {
|
||||
- if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
|
||||
- TRACING_CATEGORY_NODE1(async_hooks))) {
|
||||
+ if (NODE_TRACE_CATEGORY_ENABLED(TRACING_CATEGORY_NODE1(async_hooks))) {
|
||||
tracing::AsyncWrapArgs data(env()->execution_async_id(),
|
||||
get_trigger_async_id());
|
||||
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(async_hooks),
|
||||
diff --git a/src/env.cc b/src/env.cc
|
||||
index fdabe48dd7776c59298f7d972286d0d2ed062752..c185d822b29c0b691bbf5f724f71f59638c6184d 100644
|
||||
--- a/src/env.cc
|
||||
+++ b/src/env.cc
|
||||
@@ -650,8 +650,8 @@ void TrackingTraceStateObserver::UpdateTraceCategoryState() {
|
||||
return;
|
||||
}
|
||||
|
||||
- bool async_hooks_enabled = (*(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
|
||||
- TRACING_CATEGORY_NODE1(async_hooks)))) != 0;
|
||||
+ bool async_hooks_enabled =
|
||||
+ NODE_TRACE_CATEGORY_ENABLED(TRACING_CATEGORY_NODE1(async_hooks));
|
||||
|
||||
Isolate* isolate = env_->isolate();
|
||||
HandleScope handle_scope(isolate);
|
||||
@@ -893,8 +893,7 @@ Environment::Environment(IsolateData* isolate_data,
|
||||
time_origin_timestamp_,
|
||||
MAYBE_FIELD_PTR(env_info, performance_state));
|
||||
|
||||
- if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
|
||||
- TRACING_CATEGORY_NODE1(environment)) != 0) {
|
||||
+ if (NODE_TRACE_CATEGORY_ENABLED(TRACING_CATEGORY_NODE1(environment))) {
|
||||
tracing::EnvironmentArgs traced_value(args, exec_args);
|
||||
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(environment),
|
||||
"Environment",
|
||||
diff --git a/src/inspector/tracing_agent.cc b/src/inspector/tracing_agent.cc
|
||||
index 40c8aea35c931c46fc62b717c978eab0659645fd..348cdfb0b42aa18f352c220cea0b896c09f67753 100644
|
||||
--- a/src/inspector/tracing_agent.cc
|
||||
@@ -104,6 +253,156 @@ index 40c8aea35c931c46fc62b717c978eab0659645fd..348cdfb0b42aa18f352c220cea0b896c
|
||||
void Flush(bool) override {
|
||||
if (!json_writer_)
|
||||
return;
|
||||
diff --git a/src/node.cc b/src/node.cc
|
||||
index 0bc086ccd1ff449c0f3fb08a972a0c45d3178f1c..ca74e83ef6f7b0e8b8496457af3813f07f52eb37 100644
|
||||
--- a/src/node.cc
|
||||
+++ b/src/node.cc
|
||||
@@ -78,6 +78,11 @@
|
||||
|
||||
#include "large_pages/node_large_page.h"
|
||||
|
||||
+#if defined(V8_USE_PERFETTO)
|
||||
+#include "perfetto/tracing/tracing.h"
|
||||
+#include "tracing/trace_categories.h"
|
||||
+#endif
|
||||
+
|
||||
#if defined(__APPLE__) || defined(__linux__) || defined(_WIN32)
|
||||
#define NODE_USE_V8_WASM_TRAP_HANDLER 1
|
||||
#else
|
||||
@@ -1261,6 +1266,14 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
|
||||
absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kIgnore);
|
||||
}
|
||||
|
||||
+#if defined(V8_USE_PERFETTO)
|
||||
+ // Register Node's Perfetto TrackEvent data source so that trace
|
||||
+ // categories are available.
|
||||
+ if (perfetto::Tracing::IsInitialized()) {
|
||||
+ node::perfetto_track_event::TrackEvent::Register();
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
#if NODE_USE_V8_WASM_TRAP_HANDLER
|
||||
bool use_wasm_trap_handler =
|
||||
!per_process::cli_options->disable_wasm_trap_handler;
|
||||
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
|
||||
index 3c234205e89be7e976dae5c3fcc73ca67953e034..986a2d8da7fd04b5d4060d9c8d44c61a231dcce6 100644
|
||||
--- a/src/node_contextify.cc
|
||||
+++ b/src/node_contextify.cc
|
||||
@@ -1026,8 +1026,7 @@ void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
ContextifyScript* contextify_script = New(env, args.This());
|
||||
|
||||
- if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
|
||||
- TRACING_CATEGORY_NODE2(vm, script)) != 0) {
|
||||
+ if (NODE_TRACE_CATEGORY_ENABLED(TRACING_CATEGORY_NODE2(vm, script))) {
|
||||
Utf8Value fn(isolate, filename);
|
||||
TRACE_EVENT_BEGIN1(TRACING_CATEGORY_NODE2(vm, script),
|
||||
"ContextifyScript::New",
|
||||
diff --git a/src/node_dir.cc b/src/node_dir.cc
|
||||
index c9173d404c79a69743fc75ddb6bba0ac9579c1ef..8ffac047a69b3900f37d712334c504a1c65c83fd 100644
|
||||
--- a/src/node_dir.cc
|
||||
+++ b/src/node_dir.cc
|
||||
@@ -61,18 +61,25 @@ static const char* get_dir_func_name_by_type(uv_fs_type req_type) {
|
||||
|
||||
#define TRACE_NAME(name) "fs_dir.sync." #name
|
||||
#define GET_TRACE_ENABLED \
|
||||
- (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( \
|
||||
- TRACING_CATEGORY_NODE2(fs_dir, sync)) != 0)
|
||||
+ NODE_TRACE_CATEGORY_ENABLED(TRACING_CATEGORY_NODE2(fs_dir, sync))
|
||||
#define FS_DIR_SYNC_TRACE_BEGIN(syscall, ...) \
|
||||
if (GET_TRACE_ENABLED) \
|
||||
TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs_dir, sync), \
|
||||
TRACE_NAME(syscall), \
|
||||
##__VA_ARGS__);
|
||||
+#if defined(V8_USE_PERFETTO)
|
||||
+// Perfetto's TRACE_EVENT_END does not accept a name; it matches the prior
|
||||
+// TRACE_EVENT_BEGIN on the same thread.
|
||||
+#define FS_DIR_SYNC_TRACE_END(syscall, ...) \
|
||||
+ if (GET_TRACE_ENABLED) \
|
||||
+ TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs_dir, sync), ##__VA_ARGS__);
|
||||
+#else
|
||||
#define FS_DIR_SYNC_TRACE_END(syscall, ...) \
|
||||
if (GET_TRACE_ENABLED) \
|
||||
TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs_dir, sync), \
|
||||
TRACE_NAME(syscall), \
|
||||
##__VA_ARGS__);
|
||||
+#endif
|
||||
|
||||
#define FS_DIR_ASYNC_TRACE_BEGIN0(fs_type, id) \
|
||||
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(TRACING_CATEGORY_NODE2(fs_dir, async), \
|
||||
diff --git a/src/node_file.cc b/src/node_file.cc
|
||||
index 96aac2d86695732bf6805f2ad2168a62241b5045..c7a9648b0f83e910190dc620f4b72577ffde6c44 100644
|
||||
--- a/src/node_file.cc
|
||||
+++ b/src/node_file.cc
|
||||
@@ -147,16 +147,23 @@ static const char* get_fs_func_name_by_type(uv_fs_type req_type) {
|
||||
|
||||
#define TRACE_NAME(name) "fs.sync." #name
|
||||
#define GET_TRACE_ENABLED \
|
||||
- (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( \
|
||||
- TRACING_CATEGORY_NODE2(fs, sync)) != 0)
|
||||
+ NODE_TRACE_CATEGORY_ENABLED(TRACING_CATEGORY_NODE2(fs, sync))
|
||||
#define FS_SYNC_TRACE_BEGIN(syscall, ...) \
|
||||
if (GET_TRACE_ENABLED) \
|
||||
TRACE_EVENT_BEGIN( \
|
||||
TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), ##__VA_ARGS__);
|
||||
+#if defined(V8_USE_PERFETTO)
|
||||
+// Perfetto's TRACE_EVENT_END does not accept a name; it matches the prior
|
||||
+// TRACE_EVENT_BEGIN on the same thread.
|
||||
+#define FS_SYNC_TRACE_END(syscall, ...) \
|
||||
+ if (GET_TRACE_ENABLED) \
|
||||
+ TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), ##__VA_ARGS__);
|
||||
+#else
|
||||
#define FS_SYNC_TRACE_END(syscall, ...) \
|
||||
if (GET_TRACE_ENABLED) \
|
||||
TRACE_EVENT_END( \
|
||||
TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), ##__VA_ARGS__);
|
||||
+#endif
|
||||
|
||||
#define FS_ASYNC_TRACE_BEGIN0(fs_type, id) \
|
||||
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(TRACING_CATEGORY_NODE2(fs, async), \
|
||||
diff --git a/src/node_internals.h b/src/node_internals.h
|
||||
index 8e930a6fecd6589b858293d91b2454ea14ae7c73..a95dd02d4149a02ff40c759010e130c89ad1d848 100644
|
||||
--- a/src/node_internals.h
|
||||
+++ b/src/node_internals.h
|
||||
@@ -315,6 +315,14 @@ class ThreadPoolWork {
|
||||
const char* type_;
|
||||
};
|
||||
|
||||
+#if defined(V8_USE_PERFETTO)
|
||||
+// Perfetto categories must be single strings (not comma-separated).
|
||||
+#define TRACING_CATEGORY_NODE "node"
|
||||
+#define TRACING_CATEGORY_NODE1(one) "node." #one
|
||||
+#define TRACING_CATEGORY_NODE2(one, two) "node." #one "." #two
|
||||
+#define NODE_TRACE_CATEGORY_ENABLED(category) \
|
||||
+ TRACE_EVENT_CATEGORY_ENABLED(category)
|
||||
+#else
|
||||
#define TRACING_CATEGORY_NODE "node"
|
||||
#define TRACING_CATEGORY_NODE1(one) \
|
||||
TRACING_CATEGORY_NODE "," \
|
||||
@@ -323,6 +331,9 @@ class ThreadPoolWork {
|
||||
TRACING_CATEGORY_NODE "," \
|
||||
TRACING_CATEGORY_NODE "." #one "," \
|
||||
TRACING_CATEGORY_NODE "." #one "." #two
|
||||
+#define NODE_TRACE_CATEGORY_ENABLED(category) \
|
||||
+ (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category) != 0)
|
||||
+#endif
|
||||
|
||||
// Functions defined in node.cc that are exposed via the bootstrapper object
|
||||
|
||||
diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc
|
||||
index 225b1465b7c97d972a38968faf6d685017a80bf0..4a53a07f4d5e79354e647ba3ff6e2e1095a5b684 100644
|
||||
--- a/src/node_trace_events.cc
|
||||
+++ b/src/node_trace_events.cc
|
||||
@@ -127,7 +127,8 @@ static void GetCategoryEnabledBuffer(const FunctionCallbackInfo<Value>& args) {
|
||||
node::Utf8Value category_name(isolate, args[0]);
|
||||
|
||||
const uint8_t* enabled_pointer =
|
||||
- TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_name.out());
|
||||
+ tracing::TraceEventHelper::GetCategoryGroupEnabled(
|
||||
+ category_name.out());
|
||||
uint8_t* enabled_pointer_cast = const_cast<uint8_t*>(enabled_pointer);
|
||||
uint8_t size = sizeof(*enabled_pointer_cast);
|
||||
|
||||
diff --git a/src/tracing/agent.cc b/src/tracing/agent.cc
|
||||
index eddcf6c3bf91b730d6ca72960e3048ceed7e7844..184e8647b2148bc597d9d3eb63f86ae99917c642 100644
|
||||
--- a/src/tracing/agent.cc
|
||||
@@ -297,48 +596,138 @@ index cd965d77b7859ff2edcf781a934594b5a9b6d251..fe1714ba77fddef693d37eeb8c7a196d
|
||||
void Flush(bool blocking) override;
|
||||
|
||||
static const int kTracesPerFile = 1 << 19;
|
||||
diff --git a/src/tracing/trace_categories.cc b/src/tracing/trace_categories.cc
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..4abc4dc5d9ef9c2a9b2e3d85d858f4bbf5ac6432
|
||||
--- /dev/null
|
||||
+++ b/src/tracing/trace_categories.cc
|
||||
@@ -0,0 +1,5 @@
|
||||
+#include "tracing/trace_categories.h"
|
||||
+
|
||||
+#if defined(V8_USE_PERFETTO)
|
||||
+PERFETTO_TRACK_EVENT_STATIC_STORAGE_IN_NAMESPACE(node);
|
||||
+#endif
|
||||
diff --git a/src/tracing/trace_categories.h b/src/tracing/trace_categories.h
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b28d4baa7bf766301c9281b80e0d29729ef9832e
|
||||
--- /dev/null
|
||||
+++ b/src/tracing/trace_categories.h
|
||||
@@ -0,0 +1,66 @@
|
||||
+#ifndef SRC_TRACING_TRACE_CATEGORIES_H_
|
||||
+#define SRC_TRACING_TRACE_CATEGORIES_H_
|
||||
+
|
||||
+#if defined(V8_USE_PERFETTO)
|
||||
+
|
||||
+#ifdef BASE_TRACE_EVENT_BUILTIN_CATEGORIES_H_
|
||||
+// Compiling mode where Chromium's Perfetto TrackEvent
|
||||
+// is already set up (via PERFETTO_USE_CATEGORIES_FROM_NAMESPACE(base)).
|
||||
+// Node trace categories (node.perf, node.async_hooks, etc.) will be treated
|
||||
+// as dynamic categories.
|
||||
+#else
|
||||
+// Set up Node's own Perfetto TrackEvent data source with its trace categories,
|
||||
+// following the same pattern V8 uses (PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE).
|
||||
+#define PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 1
|
||||
+
|
||||
+#include "perfetto/tracing/track_event.h"
|
||||
+#include "perfetto/tracing/track_event_legacy.h"
|
||||
+
|
||||
+// Register Node.js trace categories as static Perfetto categories in the
|
||||
+// 'node' namespace.
|
||||
+PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE(
|
||||
+ node,
|
||||
+ perfetto::Category("__metadata"),
|
||||
+ perfetto::Category("node"),
|
||||
+ perfetto::Category("node.perf"),
|
||||
+ perfetto::Category("node.perf.timerify"),
|
||||
+ perfetto::Category("node.perf.usertiming"),
|
||||
+ perfetto::Category("node.perf.event_loop"),
|
||||
+ perfetto::Category("node.async_hooks"),
|
||||
+ perfetto::Category("node.bootstrap"),
|
||||
+ perfetto::Category("node.dns.native"),
|
||||
+ perfetto::Category("node.environment"),
|
||||
+ perfetto::Category("node.fs.async"),
|
||||
+ perfetto::Category("node.fs.sync"),
|
||||
+ perfetto::Category("node.fs_dir.async"),
|
||||
+ perfetto::Category("node.fs_dir.sync"),
|
||||
+ perfetto::Category("node.http"),
|
||||
+ perfetto::Category("node.net.native"),
|
||||
+ perfetto::Category("node.promises.rejections"),
|
||||
+ perfetto::Category("node.realm"),
|
||||
+ perfetto::Category("node.threadpoolwork.async"),
|
||||
+ perfetto::Category("node.threadpoolwork.sync"),
|
||||
+ perfetto::Category("node.vm.script"),
|
||||
+ perfetto::Category("v8"));
|
||||
+
|
||||
+// Make Node's categories available through the default TrackEvent namespace
|
||||
+// so that TRACE_EVENT macros work without qualification.
|
||||
+PERFETTO_USE_CATEGORIES_FROM_NAMESPACE(node);
|
||||
+
|
||||
+// These deprecated phase constants are not defined by Perfetto's legacy shim
|
||||
+// but are still exported to JavaScript by node_constants.cc.
|
||||
+#ifndef TRACE_EVENT_PHASE_ENTER_CONTEXT
|
||||
+#define TRACE_EVENT_PHASE_ENTER_CONTEXT ('(')
|
||||
+#endif
|
||||
+#ifndef TRACE_EVENT_PHASE_LEAVE_CONTEXT
|
||||
+#define TRACE_EVENT_PHASE_LEAVE_CONTEXT (')')
|
||||
+#endif
|
||||
+#ifndef TRACE_EVENT_PHASE_LINK_IDS
|
||||
+#define TRACE_EVENT_PHASE_LINK_IDS ('=')
|
||||
+#endif
|
||||
+
|
||||
+#endif // BASE_TRACE_EVENT_BUILTIN_CATEGORIES_H_
|
||||
+
|
||||
+#endif // defined(V8_USE_PERFETTO)
|
||||
+
|
||||
+#endif // SRC_TRACING_TRACE_CATEGORIES_H_
|
||||
diff --git a/src/tracing/trace_event.h b/src/tracing/trace_event.h
|
||||
index a662a081dc3bf356bf93e4063fcb043e4d8df07b..c89cdfe2b2681fbf9946200a03d7d1f7bad21226 100644
|
||||
index a662a081dc3bf356bf93e4063fcb043e4d8df07b..a7d0363e15a260feaaa5c7826a3b3137be531934 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
|
||||
@@ -7,13 +7,23 @@
|
||||
|
||||
// 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
|
||||
#include "v8-platform.h"
|
||||
#include "tracing/agent.h"
|
||||
-#include "trace_event_common.h"
|
||||
#include <atomic>
|
||||
|
||||
// Adds a metadata event to the trace log. The |AppendValueAsTraceFormat| method
|
||||
// on the convertable value will be called at flush time.
|
||||
@@ -319,12 +332,15 @@ class TraceEventHelper {
|
||||
+#if defined(V8_USE_PERFETTO)
|
||||
+#include "tracing/trace_categories.h"
|
||||
+#else
|
||||
+#include "trace_event_common.h"
|
||||
+#endif
|
||||
+
|
||||
// This header file defines implementation details of how the trace macros in
|
||||
// trace_event_common.h collect and store trace events. Anything not
|
||||
// implementation-specific should go in trace_macros_common.h instead of here.
|
||||
|
||||
+#if !defined(V8_USE_PERFETTO)
|
||||
+// When Perfetto is enabled, all trace event macros and their internal
|
||||
+// implementation are provided by Perfetto's track event legacy shim
|
||||
+// (included via trace_categories.h). The following definitions are only
|
||||
+// needed for the non-Perfetto tracing backend.
|
||||
|
||||
// The pointer returned from GetCategoryGroupEnabled() points to a
|
||||
// value with zero or more of the following bits. Used in this class only.
|
||||
@@ -301,6 +311,8 @@ enum CategoryGroupEnabledFlags {
|
||||
INTERNAL_TRACE_EVENT_UID(ScopedContext) \
|
||||
INTERNAL_TRACE_EVENT_UID(scoped_context)(context);
|
||||
|
||||
+#endif // !defined(V8_USE_PERFETTO)
|
||||
+
|
||||
namespace node {
|
||||
namespace tracing {
|
||||
|
||||
@@ -319,15 +331,24 @@ class TraceEventHelper {
|
||||
static void SetAgent(Agent* agent);
|
||||
|
||||
static inline const uint8_t* GetCategoryGroupEnabled(const char* group) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
+#if defined(V8_USE_PERFETTO)
|
||||
+ // Under Perfetto, callers should use TRACE_EVENT_CATEGORY_ENABLED()
|
||||
+ // instead. This function exists only for backward compatibility with
|
||||
+ // non-Perfetto builds.
|
||||
+ static const uint8_t disabled = 0;
|
||||
+ return &disabled;
|
||||
+#else
|
||||
v8::TracingController* controller = GetTracingController();
|
||||
static const uint8_t disabled = 0;
|
||||
if (controller == nullptr) [[unlikely]] {
|
||||
@@ -346,56 +735,90 @@ index a662a081dc3bf356bf93e4063fcb043e4d8df07b..c89cdfe2b2681fbf9946200a03d7d1f7
|
||||
}
|
||||
return controller->GetCategoryGroupEnabled(group);
|
||||
+#endif
|
||||
+ return 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -462,6 +478,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*>(
|
||||
@@ -478,6 +495,8 @@ static inline uint64_t AddTraceEventImpl(
|
||||
+#if !defined(V8_USE_PERFETTO)
|
||||
// TraceID encapsulates an ID that can either be an integer or pointer. Pointers
|
||||
// are by default mangled with the Process ID so that they are unlikely to
|
||||
// collide when the same pointer is used on different processes.
|
||||
@@ -478,6 +499,7 @@ static inline uint64_t AddTraceEventImpl(
|
||||
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(
|
||||
@@ -485,6 +504,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_convertibles[2];
|
||||
if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
|
||||
arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
||||
@@ -501,12 +521,15 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
|
||||
@@ -501,6 +523,7 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
|
||||
return controller->AddTraceEventWithTimestamp(
|
||||
phase, category_group_enabled, name, scope, id, bind_id, num_args,
|
||||
arg_names, arg_types, arg_values, arg_convertibles, 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*>(
|
||||
@@ -522,6 +545,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
|
||||
}
|
||||
@@ -716,6 +739,8 @@ class ScopedTracer {
|
||||
Data data_;
|
||||
};
|
||||
|
||||
// Define SetTraceValue for each allowed type. It stores the type and
|
||||
+#endif // !defined(V8_USE_PERFETTO)
|
||||
+
|
||||
} // namespace tracing
|
||||
} // namespace node
|
||||
|
||||
diff --git a/src/tracing/traced_value.h b/src/tracing/traced_value.h
|
||||
index 0bc9df81d87562243817a6618641a49b602654e3..b6dd8b9a9c21051f3d385d5ecea9c50c8b8b1629 100644
|
||||
--- a/src/tracing/traced_value.h
|
||||
+++ b/src/tracing/traced_value.h
|
||||
@@ -11,6 +11,26 @@
|
||||
#include <span>
|
||||
#include <string>
|
||||
|
||||
+#if defined(V8_USE_PERFETTO)
|
||||
+#include "perfetto/tracing/traced_value.h"
|
||||
+
|
||||
+namespace perfetto {
|
||||
+
|
||||
+template <>
|
||||
+struct TraceFormatTraits<
|
||||
+ std::unique_ptr<v8::ConvertableToTraceFormat>> {
|
||||
+ static void WriteIntoTrace(
|
||||
+ TracedValue context,
|
||||
+ const std::unique_ptr<v8::ConvertableToTraceFormat>& value) {
|
||||
+ std::string json;
|
||||
+ value->AppendAsTraceFormat(&json);
|
||||
+ std::move(context).WriteString(json);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+} // namespace perfetto
|
||||
+#endif // defined(V8_USE_PERFETTO)
|
||||
+
|
||||
namespace node {
|
||||
namespace tracing {
|
||||
|
||||
diff --git a/unofficial.gni b/unofficial.gni
|
||||
index bff7b0650cfe8578a044e45d0f9e352859909695..a773152813376bef1fa227c331241a1d944c9317 100644
|
||||
--- a/unofficial.gni
|
||||
+++ b/unofficial.gni
|
||||
@@ -143,7 +143,10 @@ template("node_gn_build") {
|
||||
[ "node.gyp" ])
|
||||
|
||||
source_set("libnode") {
|
||||
- configs += [ ":node_internal_config" ]
|
||||
+ configs += [
|
||||
+ ":node_internal_config",
|
||||
+ "$node_v8_path:v8_tracing_config",
|
||||
+ ]
|
||||
public_configs = [
|
||||
":node_external_config",
|
||||
"deps/googletest:googletest_config",
|
||||
@@ -173,6 +176,7 @@ template("node_gn_build") {
|
||||
"//third_party/zstd:headers",
|
||||
"$node_simdutf_path",
|
||||
"$node_v8_path:v8_libplatform",
|
||||
+ "$node_v8_path:v8_tracing",
|
||||
]
|
||||
|
||||
cflags_cc = [
|
||||
|
||||
@@ -20,22 +20,18 @@ index ab7dc27de3e304f6d912d5834da47e3b4eb25495..b6c0fd4ceee989dac55c7d54e52fef18
|
||||
}
|
||||
}
|
||||
diff --git a/unofficial.gni b/unofficial.gni
|
||||
index 4ab316e45bd84e43a53335df60f847b17fe6c2fa..def9a302830e493e51cc2b3588816fcbd3a1bb51 100644
|
||||
index 43f09d1e68c88d3ba3b862a1a74769f73c370894..cedd2b0a0941fe66bdae479c4fc768ce3d7bc6ac 100644
|
||||
--- a/unofficial.gni
|
||||
+++ b/unofficial.gni
|
||||
@@ -143,7 +143,10 @@ template("node_gn_build") {
|
||||
[ "node.gyp" ])
|
||||
|
||||
source_set("libnode") {
|
||||
- configs += [ ":node_internal_config" ]
|
||||
+ configs += [
|
||||
+ ":node_internal_config",
|
||||
@@ -146,6 +146,7 @@ template("node_gn_build") {
|
||||
configs += [
|
||||
":node_internal_config",
|
||||
"$node_v8_path:v8_tracing_config",
|
||||
+ "//build/config/compiler:no_exit_time_destructors"
|
||||
+ ]
|
||||
]
|
||||
public_configs = [
|
||||
":node_external_config",
|
||||
"deps/googletest:googletest_config",
|
||||
@@ -364,6 +367,7 @@ template("node_gn_build") {
|
||||
@@ -368,6 +369,7 @@ template("node_gn_build") {
|
||||
"src/embedded_data.h",
|
||||
]
|
||||
include_dirs = [ "src", "tools" ]
|
||||
|
||||
@@ -18,10 +18,10 @@ Stage 3.
|
||||
Upstreamed in https://github.com/nodejs/node/pull/60364
|
||||
|
||||
diff --git a/src/node.cc b/src/node.cc
|
||||
index b9d35e60f39d1edd910cd0fc1e57157458db93f5..4421ddd05f69e32f38d074a4cc04e4e7eac89e76 100644
|
||||
index 6e7df97bfdb3bb2ff9fcbb0eba6118239018d632..2b221e84bb5e84829af8193b38eec31b57668e75 100644
|
||||
--- a/src/node.cc
|
||||
+++ b/src/node.cc
|
||||
@@ -778,7 +778,7 @@ static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args,
|
||||
@@ -783,7 +783,7 @@ static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args,
|
||||
|
||||
if (std::ranges::find(v8_args, "--no-js-source-phase-imports") ==
|
||||
v8_args.end()) {
|
||||
|
||||
@@ -12,10 +12,10 @@ This can be removed/refactored once Node.js upgrades to a version of V8
|
||||
containing the above CL.
|
||||
|
||||
diff --git a/src/node.cc b/src/node.cc
|
||||
index 0bc086ccd1ff449c0f3fb08a972a0c45d3178f1c..b9d35e60f39d1edd910cd0fc1e57157458db93f5 100644
|
||||
index ca74e83ef6f7b0e8b8496457af3813f07f52eb37..6e7df97bfdb3bb2ff9fcbb0eba6118239018d632 100644
|
||||
--- a/src/node.cc
|
||||
+++ b/src/node.cc
|
||||
@@ -1244,7 +1244,7 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
|
||||
@@ -1249,7 +1249,7 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
|
||||
result->platform_ = per_process::v8_platform.Platform();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@ change, it seems to introduce an incompatibility when compiling
|
||||
using clang modules. Disabling them resolves the issue.
|
||||
|
||||
diff --git a/unofficial.gni b/unofficial.gni
|
||||
index def9a302830e493e51cc2b3588816fcbd3a1bb51..900c5e4d8a48d0725420518c923c7024518158b8 100644
|
||||
index cedd2b0a0941fe66bdae479c4fc768ce3d7bc6ac..86bd7d18ca299d0866c872b52fb0508174c148d9 100644
|
||||
--- a/unofficial.gni
|
||||
+++ b/unofficial.gni
|
||||
@@ -197,6 +197,10 @@ template("node_gn_build") {
|
||||
@@ -199,6 +199,10 @@ template("node_gn_build") {
|
||||
"CoreFoundation.framework",
|
||||
"Security.framework",
|
||||
]
|
||||
@@ -24,7 +24,7 @@ index def9a302830e493e51cc2b3588816fcbd3a1bb51..900c5e4d8a48d0725420518c923c7024
|
||||
}
|
||||
if (is_posix) {
|
||||
configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
|
||||
@@ -369,6 +373,12 @@ template("node_gn_build") {
|
||||
@@ -371,6 +375,12 @@ template("node_gn_build") {
|
||||
include_dirs = [ "src", "tools" ]
|
||||
configs += [ "//build/config/compiler:no_exit_time_destructors" ]
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@ libc++ added [[nodiscard]] to std::filesystem::copy_options operator|=
|
||||
which causes build failures with -Werror.
|
||||
|
||||
diff --git a/src/node_file.cc b/src/node_file.cc
|
||||
index 547455bb5011677719a8de1f98cb447561bce6aa..385db5fd6fe5db6bb7ff17e98309b6cd605a82d3 100644
|
||||
index 46cd16b535d9bd651ef733ca52ea58db7d39b09f..7a7c71a0fcbb71e1c3dfcac7a00da207c4c3bf56 100644
|
||||
--- a/src/node_file.cc
|
||||
+++ b/src/node_file.cc
|
||||
@@ -3460,11 +3460,11 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
|
||||
@@ -3467,11 +3467,11 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
auto file_copy_opts = std::filesystem::copy_options::recursive;
|
||||
if (force) {
|
||||
|
||||
@@ -89,7 +89,7 @@ index fb2af584a4ae777022c9ef8c20ada1edcbbbefdc..fe6300a5d5d2d6602a84cbd33736c213
|
||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
diff --git a/src/env.cc b/src/env.cc
|
||||
index fdabe48dd7776c59298f7d972286d0d2ed062752..b5cf58cc953590493beb52abf249e33e486ffc46 100644
|
||||
index c185d822b29c0b691bbf5f724f71f59638c6184d..57a46c8be2e052b298ed841eed6f291d62711750 100644
|
||||
--- a/src/env.cc
|
||||
+++ b/src/env.cc
|
||||
@@ -611,7 +611,7 @@ IsolateData::~IsolateData() {}
|
||||
|
||||
@@ -19,7 +19,7 @@ index 2c95ac99be70b0750372e9c858753bf519498e3d..5ab30502fd232196739ca2b450e35cc9
|
||||
Local<Module> module = obj->module_.Get(isolate);
|
||||
if (module->GetStatus() < Module::kInstantiated) {
|
||||
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
|
||||
index e66d4fcb0c064f96cdb819c783027d864fe88d12..619980b36db457ef7e476eacd446e3bf2a9a71d2 100644
|
||||
index 9f11d32c70366524cf3b7c1cfdfd24f31e438e7b..3f1772b62aa0300540d25fb93012c49bce9d8134 100644
|
||||
--- a/src/node_contextify.cc
|
||||
+++ b/src/node_contextify.cc
|
||||
@@ -460,7 +460,7 @@ ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
chore_allow_customizing_microtask_policy_per_context.patch
|
||||
build_warn_instead_of_abort_on_builtin_pgo_profile_mismatch.patch
|
||||
src_use_legacy_trace_macros_in_perfetto_to_support_all_phases.patch
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: deepak1556 <hop2deep@gmail.com>
|
||||
Date: Tue, 31 Mar 2026 07:05:17 +0900
|
||||
Subject: src: use legacy trace macros in perfetto to support all phases
|
||||
|
||||
Replace the phase-specific SDK macros with the INTERNAL_TRACE_EVENT_ADD
|
||||
and INTERNAL_TRACE_EVENT_ADD_WITH_ID legacy shim macros, which accept an
|
||||
arbitrary phase character and forward it through Perfetto's legacy
|
||||
compatibility layer. This supports nestable async ('b'/'e'/'n')
|
||||
and counter ('C') trace event phases needed for Node.js.
|
||||
|
||||
Additionally:
|
||||
|
||||
1. Clear TRACE_EVENT_FLAG_COPY before calling Perfetto macros. Perfetto
|
||||
manages string lifetimes internally via DynamicString and
|
||||
TRACE_STR_COPY; passing FLAG_COPY triggers a CHECK failure in
|
||||
Perfetto's legacy shim.
|
||||
|
||||
2. Default instant events (phase 'I') with GLOBAL scope to THREAD scope.
|
||||
Under Perfetto, global-scope instant events land on Track::Global(0),
|
||||
producing pid:0/tid:0 in the trace output, making them effectively
|
||||
invisible in trace viewers.
|
||||
|
||||
diff --git a/src/builtins/builtins-trace.cc b/src/builtins/builtins-trace.cc
|
||||
index c17d72d477d4c28d25e3f385d8af3c5b7024f7f7..5990e6cee1d08ba0e86059cb7f3affc878dcc632 100644
|
||||
--- a/src/builtins/builtins-trace.cc
|
||||
+++ b/src/builtins/builtins-trace.cc
|
||||
@@ -181,37 +181,44 @@ BUILTIN(Trace) {
|
||||
}
|
||||
|
||||
#if defined(V8_USE_PERFETTO)
|
||||
- // TODO(skyostil): Use interned names to reduce trace size.
|
||||
- auto trace_args = [&](perfetto::EventContext ctx) {
|
||||
+ // Perfetto handles string lifetimes internally (via DynamicString and
|
||||
+ // TRACE_STR_COPY), so TRACE_EVENT_FLAG_COPY must not be set — Perfetto's
|
||||
+ // legacy shim CHECKs against it.
|
||||
+ flags &= ~TRACE_EVENT_FLAG_COPY;
|
||||
+
|
||||
+ // Default instant events to thread scope under Perfetto. Without this,
|
||||
+ // scope bits are 0 (GLOBAL), which puts events on Track::Global(0)
|
||||
+ // resulting in pid:0/tid:0 in the trace output.
|
||||
+ if (phase == TRACE_EVENT_PHASE_INSTANT) {
|
||||
+ auto scope = flags & TRACE_EVENT_FLAG_SCOPE_MASK;
|
||||
+ if (scope == TRACE_EVENT_SCOPE_GLOBAL) {
|
||||
+ flags = (flags & ~TRACE_EVENT_FLAG_SCOPE_MASK) | TRACE_EVENT_SCOPE_THREAD;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Use the legacy trace event macros which support all phase types
|
||||
+ // (including nestable async 'b'/'e'/'n' and counter 'C' used by Node.js)
|
||||
+ if (flags & TRACE_EVENT_FLAG_HAS_ID) {
|
||||
if (num_args) {
|
||||
MaybeUtf8 arg_contents(isolate, Cast<String>(arg_json));
|
||||
- auto annotation = ctx.event()->add_debug_annotations();
|
||||
- annotation->set_name(arg_name);
|
||||
- annotation->set_legacy_json_value(*arg_contents);
|
||||
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(
|
||||
+ phase, dynamic_category, perfetto::DynamicString(*name), id, flags,
|
||||
+ arg_name, TRACE_STR_COPY(*arg_contents));
|
||||
+ } else {
|
||||
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(
|
||||
+ phase, dynamic_category, perfetto::DynamicString(*name), id, flags);
|
||||
}
|
||||
- if (flags & TRACE_EVENT_FLAG_HAS_ID) {
|
||||
- auto legacy_event = ctx.event()->set_legacy_event();
|
||||
- legacy_event->set_global_id(id);
|
||||
+ } else {
|
||||
+ if (num_args) {
|
||||
+ MaybeUtf8 arg_contents(isolate, Cast<String>(arg_json));
|
||||
+ INTERNAL_TRACE_EVENT_ADD(
|
||||
+ phase, dynamic_category, perfetto::DynamicString(*name), flags,
|
||||
+ arg_name, TRACE_STR_COPY(*arg_contents));
|
||||
+ } else {
|
||||
+ INTERNAL_TRACE_EVENT_ADD(phase, dynamic_category,
|
||||
+ perfetto::DynamicString(*name), flags);
|
||||
}
|
||||
- };
|
||||
-
|
||||
- switch (phase) {
|
||||
- case TRACE_EVENT_PHASE_BEGIN:
|
||||
- TRACE_EVENT_BEGIN(dynamic_category, perfetto::DynamicString(*name),
|
||||
- trace_args);
|
||||
- break;
|
||||
- case TRACE_EVENT_PHASE_END:
|
||||
- TRACE_EVENT_END(dynamic_category, trace_args);
|
||||
- break;
|
||||
- case TRACE_EVENT_PHASE_INSTANT:
|
||||
- TRACE_EVENT_INSTANT(dynamic_category, perfetto::DynamicString(*name),
|
||||
- trace_args);
|
||||
- break;
|
||||
- default:
|
||||
- THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
- isolate, NewTypeError(MessageTemplate::kTraceEventPhaseError));
|
||||
}
|
||||
-
|
||||
#else // !defined(V8_USE_PERFETTO)
|
||||
uint8_t arg_type;
|
||||
uint64_t arg_value;
|
||||
@@ -185,4 +185,112 @@ ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== '
|
||||
expect(parsed.traceEvents.some((x: any) => x.cat === 'disabled-by-default-v8.cpu_profiler' && x.name === 'ProfileChunk')).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('node trace categories', () => {
|
||||
it('captures performance.mark() as instant trace events', async function () {
|
||||
const { performance } = require('node:perf_hooks');
|
||||
|
||||
await contentTracing.startRecording({
|
||||
included_categories: ['node.perf.usertiming']
|
||||
});
|
||||
|
||||
performance.mark('test-trace-mark');
|
||||
|
||||
const resultPath = await contentTracing.stopRecording();
|
||||
const data = fs.readFileSync(resultPath, 'utf8');
|
||||
const parsed = JSON.parse(data);
|
||||
|
||||
const markEvents = parsed.traceEvents.filter(
|
||||
(x: any) => x.cat === 'node.perf.usertiming' && x.name === 'test-trace-mark'
|
||||
);
|
||||
expect(markEvents).to.have.lengthOf.at.least(1, 'should have node.perf.usertiming events for performance.mark()');
|
||||
expect(markEvents[0].ph).to.equal('I', 'performance.mark() should emit instant (I) phase events');
|
||||
});
|
||||
|
||||
it('captures performance.measure() as nestable async begin/end trace events', async function () {
|
||||
const { performance } = require('node:perf_hooks');
|
||||
|
||||
await contentTracing.startRecording({
|
||||
included_categories: ['node.perf.usertiming']
|
||||
});
|
||||
|
||||
performance.mark('trace-measure-start');
|
||||
await setTimeout(100);
|
||||
performance.mark('trace-measure-end');
|
||||
performance.measure('test-trace-measure', 'trace-measure-start', 'trace-measure-end');
|
||||
|
||||
const resultPath = await contentTracing.stopRecording();
|
||||
const data = fs.readFileSync(resultPath, 'utf8');
|
||||
const parsed = JSON.parse(data);
|
||||
|
||||
const measureEvents = parsed.traceEvents.filter(
|
||||
(x: any) => x.cat === 'node.perf.usertiming' && x.name === 'test-trace-measure'
|
||||
);
|
||||
expect(measureEvents.some((x: any) => x.ph === 'b')).to.be.true('should have nestable async begin (b) event');
|
||||
expect(measureEvents.some((x: any) => x.ph === 'e')).to.be.true('should have nestable async end (e) event');
|
||||
});
|
||||
|
||||
it('captures node.fs.sync trace events for file operations', async function () {
|
||||
await contentTracing.startRecording({
|
||||
included_categories: ['node.fs.sync']
|
||||
});
|
||||
|
||||
fs.readFileSync(__filename, 'utf8');
|
||||
|
||||
const resultPath = await contentTracing.stopRecording();
|
||||
const data = fs.readFileSync(resultPath, 'utf8');
|
||||
const parsed = JSON.parse(data);
|
||||
|
||||
const fsEvents = parsed.traceEvents.filter(
|
||||
(x: any) => typeof x.cat === 'string' && x.cat.includes('node.fs.sync')
|
||||
);
|
||||
expect(fsEvents).to.have.lengthOf.at.least(1, 'should have node.fs.sync trace events');
|
||||
});
|
||||
|
||||
it('captures multiple node categories simultaneously', async function () {
|
||||
const vm = require('node:vm');
|
||||
|
||||
await contentTracing.startRecording({
|
||||
included_categories: ['node.async_hooks', 'node.vm.script']
|
||||
});
|
||||
|
||||
vm.runInNewContext('1 + 1');
|
||||
await fs.promises.readFile(__filename, 'utf8');
|
||||
|
||||
const resultPath = await contentTracing.stopRecording();
|
||||
const data = fs.readFileSync(resultPath, 'utf8');
|
||||
const parsed = JSON.parse(data);
|
||||
|
||||
const asyncHooksEvents = parsed.traceEvents.filter(
|
||||
(x: any) => typeof x.cat === 'string' && x.cat.includes('node.async_hooks')
|
||||
);
|
||||
const vmEvents = parsed.traceEvents.filter(
|
||||
(x: any) => typeof x.cat === 'string' && x.cat.includes('node.vm.script')
|
||||
);
|
||||
expect(asyncHooksEvents).to.have.lengthOf.at.least(1, 'should have node.async_hooks events');
|
||||
expect(vmEvents).to.have.lengthOf.at.least(1, 'should have node.vm.script events');
|
||||
});
|
||||
|
||||
it('captures events using wildcard category pattern node.fs.*', async function () {
|
||||
await contentTracing.startRecording({
|
||||
included_categories: ['node.fs.*']
|
||||
});
|
||||
|
||||
fs.readFileSync(__filename, 'utf8');
|
||||
await fs.promises.readFile(__filename, 'utf8');
|
||||
|
||||
const resultPath = await contentTracing.stopRecording();
|
||||
const data = fs.readFileSync(resultPath, 'utf8');
|
||||
const parsed = JSON.parse(data);
|
||||
|
||||
const syncEvents = parsed.traceEvents.filter(
|
||||
(x: any) => typeof x.cat === 'string' && x.cat.includes('node.fs.sync')
|
||||
);
|
||||
const asyncEvents = parsed.traceEvents.filter(
|
||||
(x: any) => typeof x.cat === 'string' && x.cat.includes('node.fs.async')
|
||||
);
|
||||
expect(syncEvents).to.have.lengthOf.at.least(1, 'should have node.fs.sync events from wildcard pattern');
|
||||
expect(asyncEvents).to.have.lengthOf.at.least(1, 'should have node.fs.async events from wildcard pattern');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user