Skip to content

Commit c1e4f73

Browse files
legendecasaduh95
authored andcommitted
lib: add perfetto support
Signed-off-by: Chengzhong Wu <cwu631@bloomberg.net> PR-URL: #64565 Refs: nodejs/diagnostics#654 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ryuhei Shima <shimaryuhei@gmail.com>
1 parent df608e0 commit c1e4f73

9 files changed

Lines changed: 102 additions & 39 deletions

File tree

lib/internal/console/constructor.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const {
3535
SymbolToStringTag,
3636
} = primordials;
3737

38-
const { trace } = internalBinding('trace_events');
38+
const { trace, nodeTraceEventCategory, kTraceCount } = require('internal/trace_events');
3939
const {
4040
codes: {
4141
ERR_CONSOLE_WRITABLE_STREAM,
@@ -59,9 +59,6 @@ const {
5959
const {
6060
isTypedArray, isSet, isMap, isSetIterator, isMapIterator,
6161
} = require('internal/util/types');
62-
const {
63-
CHAR_UPPERCASE_C: kTraceCount,
64-
} = require('internal/constants');
6562
const kCounts = Symbol('counts');
6663
const { time, timeLog, timeEnd, kNone } = require('internal/util/debuglog');
6764
const { channel } = require('diagnostics_channel');
@@ -72,7 +69,7 @@ const onError = channel('console.error');
7269
const onInfo = channel('console.info');
7370
const onDebug = channel('console.debug');
7471

75-
const kTraceConsoleCategory = 'node,node.console';
72+
const kTraceConsoleCategory = nodeTraceEventCategory('node.console');
7673

7774
const kMaxGroupIndentation = 1000;
7875

lib/internal/constants.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ module.exports = {
99
CHAR_UPPERCASE_Z: 90, /* Z */
1010
CHAR_LOWERCASE_Z: 122, /* z */
1111
CHAR_UPPERCASE_C: 67, /* C */
12+
CHAR_UPPERCASE_B: 66, /* B */
1213
CHAR_LOWERCASE_B: 98, /* b */
14+
CHAR_UPPERCASE_E: 69, /* E */
1315
CHAR_LOWERCASE_E: 101, /* e */
1416
CHAR_LOWERCASE_N: 110, /* n */
1517

lib/internal/http.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ const {
99
} = primordials;
1010

1111
const { setUnrefTimeout } = require('internal/timers');
12-
const { getCategoryEnabledBuffer, trace } = internalBinding('trace_events');
1312
const {
14-
CHAR_LOWERCASE_B,
15-
CHAR_LOWERCASE_E,
16-
} = require('internal/constants');
13+
getCategoryEnabledBuffer,
14+
trace,
15+
nodeTraceEventCategory,
16+
kAsyncBegin,
17+
kAsyncEnd,
18+
} = require('internal/trace_events');
1719

1820
const { URL } = require('internal/url');
1921
const { Buffer } = require('buffer');
@@ -48,14 +50,14 @@ function isTraceHTTPEnabled() {
4850
return httpEnabled[0] > 0;
4951
}
5052

51-
const traceEventCategory = 'node,node.http';
53+
const traceEventCategory = nodeTraceEventCategory('node.http');
5254

5355
function traceBegin(...args) {
54-
trace(CHAR_LOWERCASE_B, traceEventCategory, ...args);
56+
trace(kAsyncBegin, traceEventCategory, ...args);
5557
}
5658

5759
function traceEnd(...args) {
58-
trace(CHAR_LOWERCASE_E, traceEventCategory, ...args);
60+
trace(kAsyncEnd, traceEventCategory, ...args);
5961
}
6062

6163
function ipToInt(ip) {

lib/internal/trace_events.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
'use strict';
2+
3+
const { getCategoryEnabledBuffer, trace, usePerfetto } = internalBinding('trace_events');
4+
const {
5+
CHAR_UPPERCASE_B,
6+
CHAR_LOWERCASE_B,
7+
CHAR_UPPERCASE_C,
8+
CHAR_LOWERCASE_E,
9+
CHAR_UPPERCASE_E,
10+
CHAR_LOWERCASE_N,
11+
} = require('internal/constants');
12+
13+
let nodeTraceEventCategory;
14+
if (usePerfetto) {
15+
nodeTraceEventCategory = (category) => `${category}`;
16+
} else {
17+
nodeTraceEventCategory = (category) => `node,${category}`;
18+
}
19+
20+
// The async events describe the execution of a single asynchronous operation, and are
21+
// used to measure the time spent in a single asynchronous operation.
22+
// Async events may overlap with each other. Different events do not have
23+
// to be nested, or FILO (first in last out).
24+
// TODO(legendecas): V8 `trace` API does not support async marks in perfetto yet.
25+
const kAsyncBegin = usePerfetto ? CHAR_UPPERCASE_B : CHAR_LOWERCASE_B;
26+
const kAsyncEnd = usePerfetto ? CHAR_UPPERCASE_E : CHAR_LOWERCASE_E;
27+
28+
// The sync events describe the execution of a single thread, and are
29+
// used to measure the time spent in a function.
30+
// Sync events must be nested, and are FILO (first in last out), in a stack
31+
// manner.
32+
const kSyncBegin = CHAR_UPPERCASE_B;
33+
const kSyncEnd = CHAR_UPPERCASE_E;
34+
35+
// Counter events track a named numeric value as it changes over time. Each
36+
// event records the value at a point in time, and the trace viewer renders the
37+
// series as a graph.
38+
// TODO(legendecas): V8 `trace` API does not support count marks in perfetto yet.
39+
const kTraceCount = usePerfetto ? CHAR_LOWERCASE_N : CHAR_UPPERCASE_C;
40+
41+
// Instant events mark a single moment in time. They have no duration and do
42+
// not need to be paired or nested.
43+
const kTraceInstant = CHAR_LOWERCASE_N;
44+
45+
module.exports = {
46+
usePerfetto,
47+
getCategoryEnabledBuffer,
48+
trace,
49+
nodeTraceEventCategory,
50+
kAsyncBegin,
51+
kAsyncEnd,
52+
kSyncBegin,
53+
kSyncEnd,
54+
kTraceCount,
55+
kTraceInstant,
56+
};

lib/internal/trace_events_async_hooks.js

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,18 @@ const {
77
Symbol,
88
} = primordials;
99

10-
const { trace } = internalBinding('trace_events');
10+
const {
11+
trace,
12+
nodeTraceEventCategory,
13+
kAsyncBegin,
14+
kAsyncEnd,
15+
kSyncBegin,
16+
kSyncEnd,
17+
} = require('internal/trace_events');
1118
const async_wrap = internalBinding('async_wrap');
1219
const async_hooks = require('async_hooks');
13-
const {
14-
CHAR_LOWERCASE_B,
15-
CHAR_LOWERCASE_E,
16-
} = require('internal/constants');
1720

18-
// Use small letters such that chrome://tracing groups by the name.
19-
// The behavior is not only useful but the same as the events emitted using
20-
// the specific C++ macros.
21-
const kBeforeEvent = CHAR_LOWERCASE_B;
22-
const kEndEvent = CHAR_LOWERCASE_E;
23-
const kTraceEventCategory = 'node,node.async_hooks';
21+
const kTraceEventCategory = nodeTraceEventCategory('node.async_hooks');
2422

2523
const kEnabled = Symbol('enabled');
2624

@@ -45,7 +43,7 @@ function createHook() {
4543
if (nativeProviders.has(type)) return;
4644

4745
typeMemory.set(asyncId, type);
48-
trace(kBeforeEvent, kTraceEventCategory,
46+
trace(kAsyncBegin, kTraceEventCategory,
4947
type, asyncId,
5048
{
5149
triggerAsyncId,
@@ -57,21 +55,21 @@ function createHook() {
5755
const type = typeMemory.get(asyncId);
5856
if (type === undefined) return;
5957

60-
trace(kBeforeEvent, kTraceEventCategory, `${type}_CALLBACK`, asyncId);
58+
trace(kSyncBegin, kTraceEventCategory, `${type}_CALLBACK`, asyncId);
6159
},
6260

6361
after(asyncId) {
6462
const type = typeMemory.get(asyncId);
6563
if (type === undefined) return;
6664

67-
trace(kEndEvent, kTraceEventCategory, `${type}_CALLBACK`, asyncId);
65+
trace(kSyncEnd, kTraceEventCategory, `${type}_CALLBACK`, asyncId);
6866
},
6967

7068
destroy(asyncId) {
7169
const type = typeMemory.get(asyncId);
7270
if (type === undefined) return;
7371

74-
trace(kEndEvent, kTraceEventCategory, type, asyncId);
72+
trace(kAsyncEnd, kTraceEventCategory, type, asyncId);
7573

7674
// Cleanup asyncId to type map
7775
typeMemory.delete(asyncId);

lib/internal/util/debuglog.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ const {
1414
StringPrototypeToLowerCase,
1515
StringPrototypeToUpperCase,
1616
} = primordials;
17-
const {
18-
CHAR_LOWERCASE_B: kTraceBegin,
19-
CHAR_LOWERCASE_E: kTraceEnd,
20-
CHAR_LOWERCASE_N: kTraceInstant,
21-
} = require('internal/constants');
2217
const { inspect, format, formatWithOptions } = require('internal/util/inspect');
23-
const { getCategoryEnabledBuffer, trace } = internalBinding('trace_events');
18+
const {
19+
getCategoryEnabledBuffer,
20+
trace,
21+
nodeTraceEventCategory,
22+
kAsyncBegin,
23+
kAsyncEnd,
24+
kTraceInstant,
25+
} = require('internal/trace_events');
2426

2527
// `debugImpls` and `testEnabled` are deliberately not initialized so any call
2628
// to `debuglog()` before `initializeDebugEnv()` is called will throw.
@@ -246,7 +248,7 @@ function time(timesStore, traceCategory, implementation, timerFlags, logLabel =
246248

247249
if ((timerFlags & kSkipTrace) === 0) {
248250
traceLabel = safeTraceLabel(traceLabel);
249-
trace(kTraceBegin, traceCategory, traceLabel, 0);
251+
trace(kAsyncBegin, traceCategory, traceLabel, 0);
250252
}
251253

252254
timesStore.set(logLabel, process.hrtime());
@@ -286,7 +288,7 @@ function timeEnd(
286288

287289
if ((timerFlags & kSkipTrace) === 0) {
288290
traceLabel = safeTraceLabel(traceLabel);
289-
trace(kTraceEnd, traceCategory, traceLabel, 0);
291+
trace(kAsyncEnd, traceCategory, traceLabel, 0);
290292
}
291293

292294
timesStore.delete(logLabel);
@@ -385,7 +387,7 @@ function debugWithTimer(set, cb) {
385387
);
386388
}
387389

388-
const traceCategory = `node,node.${StringPrototypeToLowerCase(set)}`;
390+
const traceCategory = nodeTraceEventCategory(`node.${StringPrototypeToLowerCase(set)}`);
389391
let traceCategoryBuffer;
390392
let debugLogCategoryEnabled = false;
391393
let timerFlags = kNone;

src/node_constants.cc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,9 +1322,6 @@ void DefineTraceConstants(Local<Object> target) {
13221322
NODE_DEFINE_CONSTANT(target, TRACE_EVENT_PHASE_MEMORY_DUMP);
13231323
NODE_DEFINE_CONSTANT(target, TRACE_EVENT_PHASE_MARK);
13241324
NODE_DEFINE_CONSTANT(target, TRACE_EVENT_PHASE_CLOCK_SYNC);
1325-
NODE_DEFINE_CONSTANT(target, TRACE_EVENT_PHASE_ENTER_CONTEXT);
1326-
NODE_DEFINE_CONSTANT(target, TRACE_EVENT_PHASE_LEAVE_CONTEXT);
1327-
NODE_DEFINE_CONSTANT(target, TRACE_EVENT_PHASE_LINK_IDS);
13281325
}
13291326

13301327
void CreatePerContextProperties(Local<Object> target,

src/node_trace_events.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,14 @@ void NodeCategorySet::Initialize(Local<Object> target,
188188
.Check();
189189
target->Set(context, trace,
190190
binding->Get(context, trace).ToLocalChecked()).Check();
191+
192+
Local<String> use_perfetto =
193+
FIXED_ONE_BYTE_STRING(env->isolate(), "usePerfetto");
194+
#if defined(V8_USE_PERFETTO)
195+
target->Set(context, use_perfetto, v8::True(isolate)).Check();
196+
#else
197+
target->Set(context, use_perfetto, v8::False(isolate)).Check();
198+
#endif
191199
}
192200

193201
void NodeCategorySet::RegisterExternalReferences(

test/parallel/test-bootstrap-modules.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ expected.beforePreExec = new Set([
118118
'NativeModule internal/net',
119119
'NativeModule internal/dns/utils',
120120
'NativeModule internal/modules/esm/get_format',
121+
'NativeModule internal/trace_events',
121122
]);
122123

123124
expected.atRunTime = new Set([

0 commit comments

Comments
 (0)