Skip to content

Commit 02fa27d

Browse files
committed
worker: add cpu profile APIs for worker
1 parent ca76b39 commit 02fa27d

File tree

15 files changed

+380
-1
lines changed

15 files changed

+380
-1
lines changed

doc/api/errors.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,36 @@ when an error occurs (and is caught) during the creation of the
826826
context, for example, when the allocation fails or the maximum call stack
827827
size is reached when the context is created.
828828

829+
<a id="ERR_CPU_PROFILE_ALREADY_STARTED"></a>
830+
831+
### `ERR_CPU_PROFILE_ALREADY_STARTED`
832+
833+
<!-- YAML
834+
added: REPLACEME
835+
-->
836+
837+
The CPU profile with the given name is already started.
838+
839+
<a id="ERR_CPU_PROFILE_NOT_STARTED"></a>
840+
841+
### `ERR_CPU_PROFILE_NOT_STARTED`
842+
843+
<!-- YAML
844+
added: REPLACEME
845+
-->
846+
847+
The CPU profile with the given name is not started.
848+
849+
<a id="ERR_CPU_PROFILE_TOO_MANY"></a>
850+
851+
### `ERR_CPU_PROFILE_TOO_MANY`
852+
853+
<!-- YAML
854+
added: REPLACEME
855+
-->
856+
857+
There are too many CPU profiles being collected.
858+
829859
<a id="ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED"></a>
830860

831861
### `ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED`

doc/api/worker_threads.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,6 +1957,20 @@ this matches its values.
19571957
19581958
If the worker has stopped, the return value is an empty object.
19591959
1960+
### `worker.startCpuProfile(name)`
1961+
1962+
<!-- YAML
1963+
added: REPLACEME
1964+
-->
1965+
1966+
* name: {string}
1967+
* Returns: {Promise}
1968+
1969+
Starting a CPU profile with the given `name`, then return a Promise that fulfills
1970+
with an error or an object which has a `stop` method. Calling the `stop` method will
1971+
stop collecting the profile, then return a Promise that fulfills with an error or the
1972+
profile data.
1973+
19601974
### `worker.stderr`
19611975
19621976
<!-- YAML

lib/internal/worker.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,40 @@ class Worker extends EventEmitter {
506506
};
507507
});
508508
}
509+
510+
// TODO(theanarkh): add options, such as sample_interval, CpuProfilingMode
511+
startCpuProfile(name) {
512+
validateString(name, 'name');
513+
const startTaker = this[kHandle]?.startCpuProfile(name);
514+
return new Promise((resolve, reject) => {
515+
if (!startTaker) return reject(new ERR_WORKER_NOT_RUNNING());
516+
startTaker.ondone = (err) => {
517+
if (err) {
518+
return reject(err);
519+
}
520+
let stopped = false;
521+
const stop = () => {
522+
if (stopped) {
523+
return;
524+
}
525+
stopped = true;
526+
const stopTaker = this[kHandle]?.stopCpuProfile(name);
527+
return new Promise((resolve, reject) => {
528+
if (!stopTaker) return reject(new ERR_WORKER_NOT_RUNNING());
529+
stopTaker.ondone = (status, profile) => {
530+
if (err) {
531+
return reject(err);
532+
}
533+
resolve(profile);
534+
};
535+
});
536+
};
537+
resolve({
538+
stop,
539+
});
540+
};
541+
});
542+
}
509543
}
510544

511545
/**

src/async_wrap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ namespace node {
7979
V(UDPWRAP) \
8080
V(SIGINTWATCHDOG) \
8181
V(WORKER) \
82+
V(WORKERCPUPROFILE) \
8283
V(WORKERCPUUSAGE) \
8384
V(WORKERHEAPSNAPSHOT) \
8485
V(WORKERHEAPSTATISTICS) \

src/env-inl.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,34 @@ inline void Environment::RemoveHeapSnapshotNearHeapLimitCallback(
916916
heap_limit);
917917
}
918918

919+
inline v8::CpuProfilingResult Environment::StartCpuProfile(
920+
v8::Local<v8::String> title) {
921+
if (!cpu_profiler_) {
922+
cpu_profiler_ = v8::CpuProfiler::New(isolate_);
923+
}
924+
v8::CpuProfilingResult result = cpu_profiler_->Start(title, true);
925+
if (result.status == v8::CpuProfilingStatus::kStarted) {
926+
node::Utf8Value key(isolate_, title);
927+
pending_profiles_.insert({*key, result.id});
928+
}
929+
return result;
930+
}
931+
932+
inline v8::CpuProfile* Environment::StopCpuProfile(
933+
v8::Local<v8::String> title) {
934+
if (!cpu_profiler_) {
935+
return nullptr;
936+
}
937+
node::Utf8Value key(isolate_, title);
938+
auto it = pending_profiles_.find(*key);
939+
if (it == pending_profiles_.end()) {
940+
return nullptr;
941+
}
942+
v8::CpuProfile* profile = cpu_profiler_->Stop(it->second);
943+
pending_profiles_.erase(it);
944+
return profile;
945+
}
946+
919947
} // namespace node
920948

921949
// These two files depend on each other. Including base_object-inl.h after this

src/env.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,13 @@ Environment::~Environment() {
10681068
}
10691069

10701070
delete external_memory_accounter_;
1071+
if (cpu_profiler_) {
1072+
for (auto it : pending_profiles_) {
1073+
cpu_profiler_->Stop(it.second);
1074+
}
1075+
cpu_profiler_->Dispose();
1076+
cpu_profiler_ = nullptr;
1077+
}
10711078
}
10721079

10731080
void Environment::InitializeLibuv() {

src/env.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "util.h"
5050
#include "uv.h"
5151
#include "v8-external-memory-accounter.h"
52+
#include "v8-profiler.h"
5253
#include "v8.h"
5354

5455
#if HAVE_OPENSSL
@@ -1048,6 +1049,9 @@ class Environment final : public MemoryRetainer {
10481049

10491050
inline void RemoveHeapSnapshotNearHeapLimitCallback(size_t heap_limit);
10501051

1052+
inline v8::CpuProfilingResult StartCpuProfile(v8::Local<v8::String> title);
1053+
inline v8::CpuProfile* StopCpuProfile(v8::Local<v8::String> title);
1054+
10511055
// Field identifiers for exit_info_
10521056
enum ExitInfoField {
10531057
kExiting = 0,
@@ -1244,6 +1248,9 @@ class Environment final : public MemoryRetainer {
12441248
// track of the BackingStore for a given pointer.
12451249
std::unordered_map<char*, std::unique_ptr<v8::BackingStore>>
12461250
released_allocated_buffers_;
1251+
1252+
v8::CpuProfiler* cpu_profiler_ = nullptr;
1253+
std::unordered_map<std::string, v8::ProfilerId> pending_profiles_;
12471254
};
12481255

12491256
} // namespace node

src/env_properties.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@
483483
V(tcp_constructor_template, v8::FunctionTemplate) \
484484
V(tty_constructor_template, v8::FunctionTemplate) \
485485
V(write_wrap_template, v8::ObjectTemplate) \
486+
V(worker_cpu_profile_taker_template, v8::ObjectTemplate) \
486487
V(worker_cpu_usage_taker_template, v8::ObjectTemplate) \
487488
V(worker_heap_snapshot_taker_template, v8::ObjectTemplate) \
488489
V(worker_heap_statistics_taker_template, v8::ObjectTemplate) \

src/node_errors.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ void OOMErrorHandler(const char* location, const v8::OOMDetails& details);
4848
V(ERR_CLOSED_MESSAGE_PORT, Error) \
4949
V(ERR_CONSTRUCT_CALL_REQUIRED, TypeError) \
5050
V(ERR_CONSTRUCT_CALL_INVALID, TypeError) \
51+
V(ERR_CPU_PROFILE_ALREADY_STARTED, Error) \
52+
V(ERR_CPU_PROFILE_NOT_STARTED, Error) \
53+
V(ERR_CPU_PROFILE_TOO_MANY, Error) \
5154
V(ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED, Error) \
5255
V(ERR_CRYPTO_INITIALIZATION_FAILED, Error) \
5356
V(ERR_CRYPTO_INVALID_AUTH_TAG, TypeError) \

0 commit comments

Comments
 (0)