Skip to content
Merged
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
2 changes: 2 additions & 0 deletions bindings/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "allocation-profile-node.hh"
#include "profilers/heap.hh"
#include "profilers/wall.hh"
#include "translate-time-profile.hh"

#ifdef __linux__
#include <sys/syscall.h>
Expand Down Expand Up @@ -49,6 +50,7 @@ NODE_MODULE_INIT(/* exports, module, context */) {
#endif

dd::AllocationProfileNodeView::Init(exports);
dd::TimeProfileNodeView::Init(exports);
dd::HeapProfiler::Init(exports);
dd::WallProfiler::Init(exports);
Nan::SetMethod(exports, "getNativeThreadId", GetNativeThreadId);
Expand Down
4 changes: 4 additions & 0 deletions bindings/per-isolate-data.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ Nan::Global<v8::Function>& PerIsolateData::AllocationNodeConstructor() {
return allocation_node_constructor;
}

Nan::Global<v8::Function>& PerIsolateData::TimeProfileNodeConstructor() {
return time_profile_node_constructor;
}

std::shared_ptr<HeapProfilerState>& PerIsolateData::GetHeapProfilerState() {
return heap_profiler_state;
}
Expand Down
2 changes: 2 additions & 0 deletions bindings/per-isolate-data.hh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class PerIsolateData {
private:
Nan::Global<v8::Function> wall_profiler_constructor;
Nan::Global<v8::Function> allocation_node_constructor;
Nan::Global<v8::Function> time_profile_node_constructor;
std::shared_ptr<HeapProfilerState> heap_profiler_state;

PerIsolateData() {}
Expand All @@ -38,6 +39,7 @@ class PerIsolateData {

Nan::Global<v8::Function>& WallProfilerConstructor();
Nan::Global<v8::Function>& AllocationNodeConstructor();
Nan::Global<v8::Function>& TimeProfileNodeConstructor();
std::shared_ptr<HeapProfilerState>& GetHeapProfilerState();
};

Expand Down
89 changes: 77 additions & 12 deletions bindings/profilers/wall.cc
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,34 @@ NAN_METHOD(WallProfiler::Stop) {
info.GetReturnValue().Set(profile);
}

// stopAndCollect(restart, callback): callback result
NAN_METHOD(WallProfiler::StopAndCollect) {
if (info.Length() != 2) {
return Nan::ThrowTypeError("stopAndCollect must have two arguments.");
}
if (!info[0]->IsBoolean()) {
return Nan::ThrowTypeError("Restart must be a boolean.");
}
if (!info[1]->IsFunction()) {
return Nan::ThrowTypeError("stopAndCollect requires a callback.");
}

bool restart = info[0].As<Boolean>()->Value();
auto callback = info[1].As<Function>();

WallProfiler* wallProfiler =
Nan::ObjectWrap::Unwrap<WallProfiler>(info.This());

v8::Local<v8::Value> result;
auto err = wallProfiler->StopAndCollectImpl(restart, callback, result);
if (!err.success) {
return Nan::ThrowTypeError(err.msg.c_str());
}
if (!result.IsEmpty()) {
info.GetReturnValue().Set(result);
}
}

bool WallProfiler::waitForSignal(uint64_t targetCallCount) {
auto currentCallCount = noCollectCallCount_.load(std::memory_order_relaxed);
std::atomic_signal_fence(std::memory_order_acquire);
Expand All @@ -968,7 +996,8 @@ bool WallProfiler::waitForSignal(uint64_t targetCallCount) {
return res >= targetCallCount;
}

Result WallProfiler::StopImpl(bool restart, v8::Local<v8::Value>& profile) {
template <typename ProfileBuilder>
Result WallProfiler::StopCore(bool restart, ProfileBuilder&& buildProfile) {
if (!started_) {
return Result{"Stop called on not started profiler."};
}
Expand Down Expand Up @@ -1030,9 +1059,12 @@ Result WallProfiler::StopImpl(bool restart, v8::Local<v8::Value>& profile) {
std::memory_order_relaxed);
}

if (withContexts_) {
int64_t nonJSThreadsCpuTime{};
ContextsByNode contextsByNode;
ContextsByNode* contextsByNodePtr = nullptr;
int64_t nonJSThreadsCpuTime = 0;
bool hasCpuTime = false;

if (withContexts_) {
if (isMainThread_ && collectCpuTime_) {
// account for non-JS threads CPU only in main thread
// CPU time of non-JS threads is the difference between process CPU time
Expand All @@ -1044,18 +1076,14 @@ Result WallProfiler::StopImpl(bool restart, v8::Local<v8::Value>& profile) {
std::max(processCpu - totalWorkerCpu, ProcessCpuClock::duration{})
.count();
}
auto contextsByNode =
contextsByNode =
GetContextsByNode(v8_profile, contexts, startThreadCpuTime);
contextsByNodePtr = &contextsByNode;
hasCpuTime = collectCpuTime_;
}

profile = TranslateTimeProfile(v8_profile,
includeLines_,
&contextsByNode,
collectCpuTime_,
nonJSThreadsCpuTime);
buildProfile(v8_profile, hasCpuTime, nonJSThreadsCpuTime, contextsByNodePtr);

} else {
profile = TranslateTimeProfile(v8_profile, includeLines_);
}
v8_profile->Delete();

if (!restart) {
Expand All @@ -1072,6 +1100,42 @@ Result WallProfiler::StopImpl(bool restart, v8::Local<v8::Value>& profile) {
return {};
}

Result WallProfiler::StopImpl(bool restart, v8::Local<v8::Value>& profile) {
return StopCore(restart,
[&](const v8::CpuProfile* v8_profile,
bool hasCpuTime,
int64_t nonJSThreadsCpuTime,
ContextsByNode* contextsByNodePtr) {
profile = TranslateTimeProfile(v8_profile,
includeLines_,
contextsByNodePtr,
hasCpuTime,
nonJSThreadsCpuTime);
});
}

Result WallProfiler::StopAndCollectImpl(bool restart,
v8::Local<v8::Function> callback,
v8::Local<v8::Value>& result) {
return StopCore(
restart,
[&](const v8::CpuProfile* v8_profile,
bool hasCpuTime,
int64_t nonJSThreadsCpuTime,
ContextsByNode* contextsByNodePtr) {
auto* isolate = Isolate::GetCurrent();
TimeProfileViewState state{includeLines_, contextsByNodePtr, {}};
auto profile_view = BuildTimeProfileView(
v8_profile, hasCpuTime, nonJSThreadsCpuTime, state);
v8::Local<v8::Value> argv[] = {profile_view};
auto cb_result = Nan::Call(
callback, isolate->GetCurrentContext()->Global(), 1, argv);
if (!cb_result.IsEmpty()) {
result = cb_result.ToLocalChecked();
}
});
}

NAN_MODULE_INIT(WallProfiler::Init) {
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
Local<String> className = Nan::New("TimeProfiler").ToLocalChecked();
Expand All @@ -1085,6 +1149,7 @@ NAN_MODULE_INIT(WallProfiler::Init) {

Nan::SetPrototypeMethod(tpl, "start", Start);
Nan::SetPrototypeMethod(tpl, "stop", Stop);
Nan::SetPrototypeMethod(tpl, "stopAndCollect", StopAndCollect);
Nan::SetPrototypeMethod(tpl, "dispose", Dispose);
Nan::SetPrototypeMethod(tpl,
"v8ProfilerStuckEventLoopDetected",
Expand Down
6 changes: 6 additions & 0 deletions bindings/profilers/wall.hh
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,12 @@ class WallProfiler : public Nan::ObjectWrap {

Result StartImpl();
v8::ProfilerId StartInternal();
template <typename ProfileBuilder>
Result StopCore(bool restart, ProfileBuilder&& buildProfile);
Result StopImpl(bool restart, v8::Local<v8::Value>& profile);
Result StopAndCollectImpl(bool restart,
v8::Local<v8::Function> callback,
v8::Local<v8::Value>& result);

CollectionMode collectionMode() {
auto res = collectionMode_.load(std::memory_order_relaxed);
Expand Down Expand Up @@ -185,6 +190,7 @@ class WallProfiler : public Nan::ObjectWrap {
static NAN_METHOD(New);
static NAN_METHOD(Start);
static NAN_METHOD(Stop);
static NAN_METHOD(StopAndCollect);
static NAN_METHOD(V8ProfilerStuckEventLoopDetected);
static NAN_METHOD(Dispose);
static NAN_MODULE_INIT(Init);
Expand Down
Loading