Skip to content

Commit 39bd5b5

Browse files
committed
src: trace threadpool event
1 parent ab89024 commit 39bd5b5

8 files changed

+112
-17
lines changed

doc/api/tracing.md

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ 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.threadpool`: Enables capture of Node.js threadpool,
26+
except asynchronous file IO and DNS.
2527
* `node.dns.native`: Enables capture of trace data for DNS queries.
2628
* `node.net.native`: Enables capture of trace data for network.
2729
* `node.environment`: Enables capture of Node.js Environment milestones.

src/crypto/crypto_util.h

+6-7
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, ThreadPoolWorkType::CRYPTO),
357356
mode_(mode),
358357
params_(std::move(params)) {
359358
// If the CryptoJob is async, then the instance will be

src/node_api.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1068,7 +1068,7 @@ class Work : public node::AsyncResource, public node::ThreadPoolWork {
10681068
env->isolate,
10691069
async_resource,
10701070
*v8::String::Utf8Value(env->isolate, async_resource_name)),
1071-
ThreadPoolWork(env->node_env()),
1071+
ThreadPoolWork(env->node_env(), ThreadPoolWorkType::NAPI),
10721072
_env(env),
10731073
_data(data),
10741074
_execute(execute),

src/node_blob.cc

+5-6
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, ThreadPoolWorkType::BLOB),
318317
mode_(mode) {
319318
if (mode == FixedSizeBlobCopyJob::Mode::SYNC) MakeWeak();
320319
source_ = blob->entries();

src/node_internals.h

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

259259
class ThreadPoolWork {
260260
public:
261-
explicit inline ThreadPoolWork(Environment* env) : env_(env) {
261+
enum class ThreadPoolWorkType {
262+
BLOB,
263+
CRYPTO,
264+
ZLIB,
265+
NAPI,
266+
};
267+
explicit inline ThreadPoolWork(Environment* env, ThreadPoolWorkType type)
268+
: env_(env), type_(type) {
262269
CHECK_NOT_NULL(env);
263270
}
264271
inline virtual ~ThreadPoolWork() = default;
@@ -271,9 +278,25 @@ class ThreadPoolWork {
271278

272279
Environment* env() const { return env_; }
273280

281+
const char* typeName() {
282+
switch (type_) {
283+
case ThreadPoolWorkType::BLOB:
284+
return "blob";
285+
case ThreadPoolWorkType::CRYPTO:
286+
return "crypto";
287+
case ThreadPoolWorkType::ZLIB:
288+
return "zlib";
289+
case ThreadPoolWorkType::NAPI:
290+
return "napi";
291+
default:
292+
return "unknown";
293+
}
294+
}
295+
274296
private:
275297
Environment* env_;
276298
uv_work_t work_req_;
299+
ThreadPoolWorkType type_;
277300
};
278301

279302
#define TRACING_CATEGORY_NODE "node"

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, ThreadPoolWorkType::ZLIB),
263263
write_result_(nullptr) {
264264
MakeWeak();
265265
}

src/threadpoolwork-inl.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@
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_NODE1(threadpool), typeName(), this);
3437
int status = uv_queue_work(
3538
env_->event_loop(),
3639
&work_req_,
@@ -41,6 +44,11 @@ void ThreadPoolWork::ScheduleWork() {
4144
[](uv_work_t* req, int status) {
4245
ThreadPoolWork* self = ContainerOf(&ThreadPoolWork::work_req_, req);
4346
self->env_->DecreaseWaitingRequestCounter();
47+
TRACE_EVENT_NESTABLE_ASYNC_END1(TRACING_CATEGORY_NODE1(threadpool),
48+
self->typeName(),
49+
self,
50+
"result",
51+
status);
4452
self->AfterThreadPoolWork(status);
4553
});
4654
CHECK_EQ(status, 0);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
17+
if (process.env.isChild === '1') {
18+
hkdf('sha512', 'key', 'salt', 'info', 64, () => {});
19+
deflate('hello', () => {});
20+
// Make async call
21+
const blob = new Blob(['h'.repeat(4096 * 2)]);
22+
blob.arrayBuffer();
23+
return;
24+
}
25+
26+
tmpdir.refresh();
27+
const FILE_NAME = path.join(tmpdir.path, 'node_trace.1.log');
28+
29+
cp.spawnSync(process.execPath,
30+
[
31+
'--trace-events-enabled',
32+
'--trace-event-categories', 'node.threadpool',
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+
assert(traces.length > 0);
47+
let blobCount = 0;
48+
let zlibCount = 0;
49+
let cryptoCount = 0;
50+
traces.forEach((item) => {
51+
if (item.cat === 'node,node.threadpool') {
52+
if (item.name === 'blob') {
53+
blobCount++;
54+
} else if (item.name === 'zlib') {
55+
zlibCount++;
56+
} else if (item.name === 'crypto') {
57+
cryptoCount++;
58+
}
59+
}
60+
});
61+
// There are three types, each type has two events at least
62+
assert.strictEqual(blobCount >= 2, true);
63+
assert.strictEqual(zlibCount >= 2, true);
64+
assert.strictEqual(cryptoCount >= 2, true);

0 commit comments

Comments
 (0)