Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions doc/api/v8.md
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,30 @@ setTimeout(() => {
}, 1000);
```

## Class: `SyncCPUProfileHandle`

<!-- YAML
added: REPLACEME
-->

### `syncCpuProfileHandle.stop()`

<!-- YAML
added: REPLACEME
-->

* Returns: {string}

Stopping collecting the profile and return the profile data.

### `syncCpuProfileHandle[Symbol.dispose]()`

<!-- YAML
added: REPLACEME
-->

Stopping collecting the profile and the profile will be discarded.

## Class: `CPUProfileHandle`

<!-- YAML
Expand Down Expand Up @@ -1466,6 +1490,23 @@ writeString('hello');
writeString('你好');
```

## `v8.startCpuProfile()`

<!-- YAML
added: REPLACEME
-->

* Returns: {SyncCPUProfileHandle}

Starting a CPU profile then return a `SyncCPUProfileHandle` object.
This API supports `using` syntax.

```cjs
const handle = v8.startCpuProfile();
const profile = handle.stop();
console.log(profile);
```

[CppHeap]: https://v8docs.nodesource.com/node-22.4/d9/dc4/classv8_1_1_cpp_heap.html
[HTML structured clone algorithm]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
[Hook Callbacks]: #hook-callbacks
Expand Down
34 changes: 34 additions & 0 deletions lib/v8.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const {
Int8Array,
JSONParse,
ObjectPrototypeToString,
SymbolDispose,
Uint16Array,
Uint32Array,
Uint8Array,
Expand Down Expand Up @@ -112,6 +113,8 @@ const binding = internalBinding('v8');
const {
cachedDataVersionTag,
setFlagsFromString: _setFlagsFromString,
startCpuProfile: _startCpuProfile,
stopCpuProfile: _stopCpuProfile,
isStringOneByteRepresentation: _isStringOneByteRepresentation,
updateHeapStatisticsBuffer,
updateHeapSpaceStatisticsBuffer,
Expand Down Expand Up @@ -166,6 +169,36 @@ function setFlagsFromString(flags) {
_setFlagsFromString(flags);
}

class SyncCPUProfileHandle {
#id = null;
#stopped = false;

constructor(id) {
this.#id = id;
}

stop() {
if (this.#stopped) {
return;
}
this.#stopped = true;
return _stopCpuProfile(this.#id);
};

[SymbolDispose]() {
this.stop();
}
}

/**
* Starting CPU Profile.
* @returns {SyncCPUProfileHandle}
*/
function startCpuProfile() {
const id = _startCpuProfile();
return new SyncCPUProfileHandle(id);
}

/**
* Return whether this string uses one byte as underlying representation or not.
* @param {string} content
Expand Down Expand Up @@ -478,4 +511,5 @@ module.exports = {
setHeapSnapshotNearHeapLimit,
GCProfiler,
isStringOneByteRepresentation,
startCpuProfile,
};
43 changes: 43 additions & 0 deletions src/node_v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "node.h"
#include "node_external_reference.h"
#include "util-inl.h"
#include "v8-profiler.h"
#include "v8.h"

namespace node {
Expand All @@ -35,6 +36,9 @@ using v8::Array;
using v8::BigInt;
using v8::CFunction;
using v8::Context;
using v8::CpuProfile;
using v8::CpuProfilingResult;
using v8::CpuProfilingStatus;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::HandleScope;
Expand All @@ -47,6 +51,7 @@ using v8::Local;
using v8::LocalVector;
using v8::MaybeLocal;
using v8::Name;
using v8::Number;
using v8::Object;
using v8::ScriptCompiler;
using v8::String;
Expand Down Expand Up @@ -243,6 +248,39 @@ void SetFlagsFromString(const FunctionCallbackInfo<Value>& args) {
V8::SetFlagsFromString(*flags, static_cast<size_t>(flags.length()));
}

void StartCpuProfile(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
CpuProfilingResult result = env->StartCpuProfile();
if (result.status == CpuProfilingStatus::kErrorTooManyProfilers) {
return THROW_ERR_CPU_PROFILE_TOO_MANY(isolate,
"There are too many CPU profiles");
} else if (result.status == CpuProfilingStatus::kStarted) {
args.GetReturnValue().Set(Number::New(isolate, result.id));
}
}

void StopCpuProfile(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
CHECK(args[0]->IsUint32());
uint32_t profile_id = args[0]->Uint32Value(env->context()).FromJust();
CpuProfile* profile = env->StopCpuProfile(profile_id);
if (!profile) {
return THROW_ERR_CPU_PROFILE_NOT_STARTED(isolate,
"CPU profile not started");
}
auto json_out_stream = std::make_unique<node::JSONOutputStream>();
profile->Serialize(json_out_stream.get(),
CpuProfile::SerializationFormat::kJSON);
profile->Delete();
Local<Value> ret;
if (ToV8Value(env->context(), json_out_stream->out_stream().str(), isolate)
.ToLocal(&ret)) {
args.GetReturnValue().Set(ret);
}
}

static void IsStringOneByteRepresentation(
const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(args.Length(), 1);
Expand Down Expand Up @@ -682,6 +720,9 @@ void Initialize(Local<Object> target,
// Export symbols used by v8.setFlagsFromString()
SetMethod(context, target, "setFlagsFromString", SetFlagsFromString);

SetMethod(context, target, "startCpuProfile", StartCpuProfile);
SetMethod(context, target, "stopCpuProfile", StopCpuProfile);

// Export symbols used by v8.isStringOneByteRepresentation()
SetFastMethodNoSideEffect(context,
target,
Expand Down Expand Up @@ -726,6 +767,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(GetCppHeapStatistics);
registry->Register(IsStringOneByteRepresentation);
registry->Register(fast_is_string_one_byte_representation_);
registry->Register(StartCpuProfile);
registry->Register(StopCpuProfile);
}

} // namespace v8_utils
Expand Down
1 change: 1 addition & 0 deletions src/node_v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "aliased_buffer.h"
#include "base_object.h"
#include "json_utils.h"
#include "node_errors.h"
#include "node_snapshotable.h"
#include "util.h"
#include "v8.h"
Expand Down
11 changes: 11 additions & 0 deletions test/parallel/test-v8-cpu-profile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use strict';

require('../common');
const assert = require('assert');
const v8 = require('v8');

const handle = v8.startCpuProfile();
const profile = handle.stop();
assert.ok(!!profile);
// Call stop() again
assert.ok(handle.stop() === undefined);
1 change: 1 addition & 0 deletions tools/doc/type-parser.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ const customTypesMap = {
'LockManager': 'worker_threads.html#class-lockmanager',
'LockManagerSnapshot': 'https://developer.mozilla.org/en-US/docs/Web/API/LockManagerSnapshot',
'CPUProfileHandle': 'v8.html#class-cpuprofilehandle',
'SyncCPUProfileHandle': 'v8.html#class-synccpuprofilehandle',
};

const arrayPart = /(?:\[])+$/;
Expand Down
Loading