Skip to content

Commit f7114fb

Browse files
committed
v8: add cpu profile APIs
1 parent 60a58f6 commit f7114fb

File tree

5 files changed

+110
-0
lines changed

5 files changed

+110
-0
lines changed

lib/v8.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ const binding = internalBinding('v8');
112112
const {
113113
cachedDataVersionTag,
114114
setFlagsFromString: _setFlagsFromString,
115+
startCpuProfile: _startCpuProfile,
116+
stopCpuProfile: _stopCpuProfile,
115117
isStringOneByteRepresentation: _isStringOneByteRepresentation,
116118
updateHeapStatisticsBuffer,
117119
updateHeapSpaceStatisticsBuffer,
@@ -166,6 +168,28 @@ function setFlagsFromString(flags) {
166168
_setFlagsFromString(flags);
167169
}
168170

171+
/**
172+
* Starting CPU Profile.
173+
* @param {string} name
174+
* @returns {void}
175+
*/
176+
function startCpuProfile(name) {
177+
validateString(name, 'name');
178+
const status = _startCpuProfile(name);
179+
180+
}
181+
182+
/**
183+
* Stopping CPU Profile.
184+
* @param {string} name
185+
* @returns {string}
186+
*/
187+
function stopCpuProfile(name) {
188+
validateString(name, 'name');
189+
const profile = _stopCpuProfile(name);
190+
return profile;
191+
}
192+
169193
/**
170194
* Return whether this string uses one byte as underlying representation or not.
171195
* @param {string} content
@@ -478,4 +502,6 @@ module.exports = {
478502
setHeapSnapshotNearHeapLimit,
479503
GCProfiler,
480504
isStringOneByteRepresentation,
505+
startCpuProfile,
506+
stopCpuProfile,
481507
};

src/env-inl.h

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

919+
inline void Environment::set_cpu_profiler(v8::CpuProfiler* cpu_profiler) {
920+
cpu_profiler_ = cpu_profiler;
921+
}
922+
923+
inline v8::CpuProfiler* Environment::cpu_profiler() {
924+
return cpu_profiler_;
925+
}
926+
919927
} // namespace node
920928

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

src/env.cc

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

10701070
delete external_memory_accounter_;
1071+
1072+
if (!cpu_profiler_) {
1073+
cpu_profiler_->Dispose();
1074+
cpu_profiler_ = nullptr;
1075+
}
10711076
}
10721077

10731078
void Environment::InitializeLibuv() {

src/env.h

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

5455
#if HAVE_OPENSSL
5556
#include <openssl/evp.h>
@@ -1011,6 +1012,9 @@ class Environment final : public MemoryRetainer {
10111012
inline void set_heap_prof_interval(uint64_t interval);
10121013
inline uint64_t heap_prof_interval() const;
10131014

1015+
void set_cpu_profiler(v8::CpuProfiler* cpu_profiler);
1016+
v8::CpuProfiler* cpu_profiler();
1017+
10141018
#endif // HAVE_INSPECTOR
10151019

10161020
inline const EmbedderPreloadCallback& embedder_preload() const;
@@ -1244,6 +1248,8 @@ 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;
12471253
};
12481254

12491255
} // namespace node

src/node_v8.cc

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,17 @@
2828
#include "node_external_reference.h"
2929
#include "util-inl.h"
3030
#include "v8.h"
31+
#include "v8-profiler.h"
3132

3233
namespace node {
3334
namespace v8_utils {
3435
using v8::Array;
3536
using v8::BigInt;
3637
using v8::CFunction;
3738
using v8::Context;
39+
using v8::CpuProfile;
40+
using v8::CpuProfiler;
41+
using v8::CpuProfilingStatus;
3842
using v8::FunctionCallbackInfo;
3943
using v8::FunctionTemplate;
4044
using v8::HandleScope;
@@ -243,6 +247,62 @@ void SetFlagsFromString(const FunctionCallbackInfo<Value>& args) {
243247
V8::SetFlagsFromString(*flags, static_cast<size_t>(flags.length()));
244248
}
245249

250+
class JSONOutputStream : public v8::OutputStream {
251+
public:
252+
JSONOutputStream() {}
253+
254+
int GetChunkSize() override { return 65536; }
255+
256+
void EndOfStream() override {}
257+
258+
WriteResult WriteAsciiChunk(char* data, const int size) override {
259+
out_stream_.write(data, size);
260+
return kContinue;
261+
}
262+
263+
std::ostringstream& out_stream() { return out_stream_; }
264+
265+
private:
266+
std::ostringstream out_stream_;
267+
};
268+
269+
void StartCpuProfile(const FunctionCallbackInfo<Value>& args) {
270+
Environment* env = Environment::GetCurrent(args);
271+
CHECK(args[0]->IsString());
272+
String::Utf8Value name(env->isolate(), args[0]);
273+
if (!env->cpu_profiler()) {
274+
env->set_cpu_profiler(CpuProfiler::New(env->isolate()));
275+
}
276+
Local<String> title = String::NewFromUtf8(isolate,
277+
*name,
278+
NewStringType::kNormal,
279+
name.length())
280+
.ToLocalChecked();
281+
CpuProfilingStatus status = env->cpu_profiler()->StartProfiling(title, true);
282+
args.GetReturnValue().Set(Number::New(env->isolate(), static_cast<double>(status)));
283+
}
284+
285+
void StopCpuProfile(const FunctionCallbackInfo<Value>& args) {
286+
Environment* env = Environment::GetCurrent(args);
287+
CHECK(args[0]->IsString());
288+
String::Utf8Value name(env->isolate(), args[0]);
289+
Local<String> title = String::NewFromUtf8(env->isolate(),
290+
*name,
291+
NewStringType::kNormal,
292+
name.length())
293+
.ToLocalChecked();
294+
auto json_out_stream = std::make_unique<JSONOutputStream>();
295+
if (env->cpu_profiler()) {
296+
CpuProfile* profile = env->cpu_profiler()->StopProfiling(title);
297+
if (profile) {
298+
profile->Serialize(json_out_stream.get(),
299+
CpuProfile::SerializationFormat::kJSON);
300+
profile->Delete();
301+
}
302+
}
303+
args.GetReturnValue().Set(json_out_stream->out_stream().str());
304+
}
305+
246306
static void IsStringOneByteRepresentation(
247307
const FunctionCallbackInfo<Value>& args) {
248308
CHECK_EQ(args.Length(), 1);
@@ -682,6 +742,9 @@ void Initialize(Local<Object> target,
682742
// Export symbols used by v8.setFlagsFromString()
683743
SetMethod(context, target, "setFlagsFromString", SetFlagsFromString);
684744

745+
SetMethod(context, target, "startCpuProfile", StartCpuProfile);
746+
SetMethod(context, target, "stopCpuProfile", StopCpuProfile);
747+
685748
// Export symbols used by v8.isStringOneByteRepresentation()
686749
SetFastMethodNoSideEffect(context,
687750
target,
@@ -726,6 +789,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
726789
registry->Register(GetCppHeapStatistics);
727790
registry->Register(IsStringOneByteRepresentation);
728791
registry->Register(fast_is_string_one_byte_representation_);
792+
registry->Register(StartCpuProfile);
793+
registry->Register(StopCpuProfile);
729794
}
730795

731796
} // namespace v8_utils

0 commit comments

Comments
 (0)