Skip to content

Commit 3e46ebd

Browse files
theanarkhRafaelGSS
authored andcommitted
src: trace threadpool event
PR-URL: #44458 Reviewed-By: Chengzhong Wu <[email protected]>
1 parent 670def3 commit 3e46ebd

10 files changed

+114
-20
lines changed

doc/api/tracing.md

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ The available categories are:
2222
* `node.bootstrap`: Enables capture of Node.js bootstrap milestones.
2323
* `node.console`: Enables capture of `console.time()` and `console.count()`
2424
output.
25+
* `node.threadpoolwork.sync`: Enables capture of trace data for threadpool
26+
synchronous operations, such as `blob`, `zlib`, `crypto` and `node_api`.
27+
* `node.threadpoolwork.async`: Enables capture of trace data for threadpool
28+
asynchronous operations, such as `blob`, `zlib`, `crypto` and `node_api`.
2529
* `node.dns.native`: Enables capture of trace data for DNS queries.
2630
* `node.net.native`: Enables capture of trace data for network.
2731
* `node.environment`: Enables capture of Node.js Environment milestones.

src/crypto/crypto_util.h

+6-7
Original file line numberDiff line numberDiff line change
@@ -333,14 +333,13 @@ class CryptoJob : public AsyncWrap, public ThreadPoolWork {
333333
public:
334334
using AdditionalParams = typename CryptoJobTraits::AdditionalParameters;
335335

336-
explicit CryptoJob(
337-
Environment* env,
338-
v8::Local<v8::Object> object,
339-
AsyncWrap::ProviderType type,
340-
CryptoJobMode mode,
341-
AdditionalParams&& params)
336+
explicit CryptoJob(Environment* env,
337+
v8::Local<v8::Object> object,
338+
AsyncWrap::ProviderType type,
339+
CryptoJobMode mode,
340+
AdditionalParams&& params)
342341
: AsyncWrap(env, object, type),
343-
ThreadPoolWork(env),
342+
ThreadPoolWork(env, "crypto"),
344343
mode_(mode),
345344
params_(std::move(params)) {
346345
// If the CryptoJob is async, then the instance will be

src/node_api.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ class Work : public node::AsyncResource, public node::ThreadPoolWork {
10691069
env->isolate,
10701070
async_resource,
10711071
*v8::String::Utf8Value(env->isolate, async_resource_name)),
1072-
ThreadPoolWork(env->node_env()),
1072+
ThreadPoolWork(env->node_env(), "node_api"),
10731073
_env(env),
10741074
_data(data),
10751075
_execute(execute),

src/node_blob.cc

+5-6
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,12 @@ void Blob::GetDataObject(const v8::FunctionCallbackInfo<v8::Value>& args) {
306306
}
307307
}
308308

309-
FixedSizeBlobCopyJob::FixedSizeBlobCopyJob(
310-
Environment* env,
311-
Local<Object> object,
312-
Blob* blob,
313-
FixedSizeBlobCopyJob::Mode mode)
309+
FixedSizeBlobCopyJob::FixedSizeBlobCopyJob(Environment* env,
310+
Local<Object> object,
311+
Blob* blob,
312+
FixedSizeBlobCopyJob::Mode mode)
314313
: AsyncWrap(env, object, AsyncWrap::PROVIDER_FIXEDSIZEBLOBCOPY),
315-
ThreadPoolWork(env),
314+
ThreadPoolWork(env, "blob"),
316315
mode_(mode) {
317316
if (mode == FixedSizeBlobCopyJob::Mode::SYNC) MakeWeak();
318317
source_ = blob->entries();

src/node_internals.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,8 @@ class DebugSealHandleScope {
258258

259259
class ThreadPoolWork {
260260
public:
261-
explicit inline ThreadPoolWork(Environment* env) : env_(env) {
261+
explicit inline ThreadPoolWork(Environment* env, const char* type)
262+
: env_(env), type_(type) {
262263
CHECK_NOT_NULL(env);
263264
}
264265
inline virtual ~ThreadPoolWork() = default;
@@ -274,6 +275,7 @@ class ThreadPoolWork {
274275
private:
275276
Environment* env_;
276277
uv_work_t work_req_;
278+
const char* type_;
277279
};
278280

279281
#define TRACING_CATEGORY_NODE "node"

src/node_v8_platform-inl.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,15 @@ struct V8Platform {
109109
if (!initialized_)
110110
return;
111111
initialized_ = false;
112-
112+
node::tracing::TraceEventHelper::SetAgent(nullptr);
113113
StopTracingAgent();
114114
platform_->Shutdown();
115115
delete platform_;
116116
platform_ = nullptr;
117117
// Destroy tracing after the platform (and platform threads) have been
118118
// stopped.
119119
tracing_agent_.reset(nullptr);
120+
// The observer remove itself in OnTraceEnabled
120121
trace_state_observer_.reset(nullptr);
121122
}
122123

src/node_zlib.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ class CompressionStream : public AsyncWrap, public ThreadPoolWork {
259259

260260
CompressionStream(Environment* env, Local<Object> wrap)
261261
: AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
262-
ThreadPoolWork(env),
262+
ThreadPoolWork(env, "zlib"),
263263
write_result_(nullptr) {
264264
MakeWeak();
265265
}

src/threadpoolwork-inl.h

+14-1
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,36 @@
2424

2525
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
2626

27-
#include "util-inl.h"
2827
#include "node_internals.h"
28+
#include "tracing/trace_event.h"
29+
#include "util-inl.h"
2930

3031
namespace node {
3132

3233
void ThreadPoolWork::ScheduleWork() {
3334
env_->IncreaseWaitingRequestCounter();
35+
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
36+
TRACING_CATEGORY_NODE2(threadpoolwork, async), type_, this);
3437
int status = uv_queue_work(
3538
env_->event_loop(),
3639
&work_req_,
3740
[](uv_work_t* req) {
3841
ThreadPoolWork* self = ContainerOf(&ThreadPoolWork::work_req_, req);
42+
TRACE_EVENT_BEGIN0(TRACING_CATEGORY_NODE2(threadpoolwork, sync),
43+
self->type_);
3944
self->DoThreadPoolWork();
45+
TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(threadpoolwork, sync),
46+
self->type_);
4047
},
4148
[](uv_work_t* req, int status) {
4249
ThreadPoolWork* self = ContainerOf(&ThreadPoolWork::work_req_, req);
4350
self->env_->DecreaseWaitingRequestCounter();
51+
TRACE_EVENT_NESTABLE_ASYNC_END1(
52+
TRACING_CATEGORY_NODE2(threadpoolwork, async),
53+
self->type_,
54+
self,
55+
"result",
56+
status);
4457
self->AfterThreadPoolWork(status);
4558
});
4659
CHECK_EQ(status, 0);

src/tracing/trace_event.cc

+7-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ Agent* g_agent = nullptr;
88
v8::TracingController* g_controller = nullptr;
99

1010
void TraceEventHelper::SetAgent(Agent* agent) {
11-
g_agent = agent;
12-
g_controller = agent->GetTracingController();
11+
if (agent) {
12+
g_agent = agent;
13+
g_controller = agent->GetTracingController();
14+
} else {
15+
g_agent = nullptr;
16+
g_controller = nullptr;
17+
}
1318
}
1419

1520
Agent* TraceEventHelper::GetAgent() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const cp = require('child_process');
5+
const fs = require('fs');
6+
const path = require('path');
7+
const tmpdir = require('../common/tmpdir');
8+
9+
if (!common.hasCrypto)
10+
common.skip('missing crypto');
11+
12+
const { hkdf } = require('crypto');
13+
const { deflate } = require('zlib');
14+
const { Blob } = require('buffer');
15+
16+
if (process.env.isChild === '1') {
17+
hkdf('sha512', 'key', 'salt', 'info', 64, () => {});
18+
deflate('hello', () => {});
19+
// Make async call
20+
const blob = new Blob(['h'.repeat(4096 * 2)]);
21+
blob.arrayBuffer();
22+
return;
23+
}
24+
25+
tmpdir.refresh();
26+
const FILE_NAME = path.join(tmpdir.path, 'node_trace.1.log');
27+
28+
cp.spawnSync(process.execPath,
29+
[
30+
'--trace-events-enabled',
31+
'--trace-event-categories',
32+
'node.threadpoolwork.sync,node.threadpoolwork.async',
33+
__filename,
34+
],
35+
{
36+
cwd: tmpdir.path,
37+
env: {
38+
...process.env,
39+
isChild: '1',
40+
},
41+
});
42+
43+
assert(fs.existsSync(FILE_NAME));
44+
const data = fs.readFileSync(FILE_NAME);
45+
const traces = JSON.parse(data.toString()).traceEvents;
46+
47+
assert(traces.length > 0);
48+
49+
let blobCount = 0;
50+
let zlibCount = 0;
51+
let cryptoCount = 0;
52+
53+
traces.forEach((item) => {
54+
if ([
55+
'node,node.threadpoolwork,node.threadpoolwork.sync',
56+
'node,node.threadpoolwork,node.threadpoolwork.async',
57+
].includes(item.cat)) {
58+
if (item.name === 'blob') {
59+
blobCount++;
60+
} else if (item.name === 'zlib') {
61+
zlibCount++;
62+
} else if (item.name === 'crypto') {
63+
cryptoCount++;
64+
}
65+
}
66+
});
67+
68+
// There are three types, each type has two async events and sync events at least
69+
assert.ok(blobCount >= 4);
70+
assert.ok(zlibCount >= 4);
71+
assert.ok(cryptoCount >= 4);

0 commit comments

Comments
 (0)