Skip to content

Commit 05cbb9c

Browse files
committed
src: trace threadpool event
1 parent d3cb193 commit 05cbb9c

File tree

8 files changed

+105
-17
lines changed

8 files changed

+105
-17
lines changed

doc/api/tracing.md

Lines changed: 4 additions & 0 deletions
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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -346,14 +346,13 @@ class CryptoJob : public AsyncWrap, public ThreadPoolWork {
346346
public:
347347
using AdditionalParams = typename CryptoJobTraits::AdditionalParameters;
348348

349-
explicit CryptoJob(
350-
Environment* env,
351-
v8::Local<v8::Object> object,
352-
AsyncWrap::ProviderType type,
353-
CryptoJobMode mode,
354-
AdditionalParams&& params)
349+
explicit CryptoJob(Environment* env,
350+
v8::Local<v8::Object> object,
351+
AsyncWrap::ProviderType type,
352+
CryptoJobMode mode,
353+
AdditionalParams&& params)
355354
: AsyncWrap(env, object, type),
356-
ThreadPoolWork(env),
355+
ThreadPoolWork(env, "crypto"),
357356
mode_(mode),
358357
params_(std::move(params)) {
359358
// If the CryptoJob is async, then the instance will be

src/node_api.cc

Lines changed: 1 addition & 1 deletion
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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -308,13 +308,12 @@ void Blob::GetDataObject(const v8::FunctionCallbackInfo<v8::Value>& args) {
308308
}
309309
}
310310

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

src/node_internals.h

Lines changed: 3 additions & 1 deletion
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_zlib.cc

Lines changed: 1 addition & 1 deletion
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

Lines changed: 14 additions & 1 deletion
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);
Lines changed: 71 additions & 0 deletions
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.strictEqual(blobCount >= 4, true);
70+
assert.strictEqual(zlibCount >= 4, true);
71+
assert.strictEqual(cryptoCount >= 4, true);

0 commit comments

Comments
 (0)