Skip to content

Commit 1b15c3a

Browse files
committed
Store profiling context in the CPED
1 parent 51fa650 commit 1b15c3a

File tree

2 files changed

+57
-10
lines changed

2 files changed

+57
-10
lines changed

bindings/profilers/wall.cc

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ void SignalHandler::HandleProfilerSignal(int sig,
323323
auto time_from = Now();
324324
old_handler(sig, info, context);
325325
auto time_to = Now();
326-
prof->PushContext(time_from, time_to, cpu_time);
326+
prof->PushContext(time_from, time_to, cpu_time, isolate);
327327
}
328328
#else
329329
class SignalHandler {
@@ -509,6 +509,8 @@ WallProfiler::WallProfiler(std::chrono::microseconds samplingPeriod,
509509
#endif
510510
jsArray_ = v8::Global<v8::Uint32Array>(isolate, jsArray);
511511
std::fill(fields_, fields_ + kFieldCount, 0);
512+
513+
cpedSymbol_ = v8::Global<v8::Symbol>(isolate, v8::Symbol::New(isolate));
512514
}
513515

514516
WallProfiler::~WallProfiler() {
@@ -953,23 +955,66 @@ v8::CpuProfiler* WallProfiler::CreateV8CpuProfiler() {
953955
}
954956

955957
v8::Local<v8::Value> WallProfiler::GetContext(Isolate* isolate) {
956-
auto context = GetContextPtr();
958+
auto context = GetContextPtr(isolate);
957959
if (!context) return v8::Undefined(isolate);
958960
return context->Get(isolate);
959961
}
960962

961963
void WallProfiler::SetContext(Isolate* isolate, Local<Value> value) {
964+
auto cped = isolate->GetContinuationPreservedEmbedderData();
965+
// No Node AsyncContextFrame in this continuation yet
966+
if (!cped->IsObject()) return;
967+
968+
auto cpedObj = cped.As<Object>();
969+
auto localSymbol = cpedSymbol_.Get(isolate);
970+
auto v8Ctx = isolate->GetCurrentContext();
971+
auto maybeProfData = cpedObj->Get(v8Ctx, localSymbol);
972+
if (maybeProfData.IsEmpty()) return;
973+
auto profData = maybeProfData.ToLocalChecked();
974+
975+
ContextPtr* contextPtr = nullptr;
976+
if (profData->IsNullOrUndefined()) {
977+
contextPtr = new ContextPtr();
978+
auto maybeSetResult = cpedObj->Set(v8Ctx, localSymbol, External::New(isolate, contextPtr));
979+
if (maybeSetResult.IsNothing()) {
980+
delete contextPtr;
981+
return;
982+
}
983+
984+
// Register a callback to delete contextPtr when the CPED object is GCed
985+
Persistent<Object>(isolate, cpedObj).SetWeak(contextPtr, [](const WeakCallbackInfo<ContextPtr>& data) {
986+
// Using SetSecondPassCallback as shared_ptr can trigger ~Global and any V8 API use needs to be in the second pass
987+
data.SetSecondPassCallback([](const WeakCallbackInfo<ContextPtr>& data) {
988+
delete data.GetParameter();
989+
});
990+
}, WeakCallbackType::kParameter);
991+
} else {
992+
contextPtr = reinterpret_cast<ContextPtr*>(profData.As<External>()->Value());
993+
}
994+
995+
// Signal-atomic update
962996
std::atomic_signal_fence(std::memory_order_release);
963997
std::atomic_store_explicit(
964-
&curContext_,
998+
contextPtr,
965999
value->IsNullOrUndefined()
9661000
? std::shared_ptr<Global<Value>>()
9671001
: std::make_shared<Global<Value>>(isolate, value),
9681002
std::memory_order_relaxed);
9691003
}
9701004

971-
ContextPtr WallProfiler::GetContextPtr() {
972-
auto contextPtr = atomic_load_explicit(&curContext_, std::memory_order_relaxed);
1005+
ContextPtr WallProfiler::GetContextPtr(Isolate* isolate) {
1006+
auto cped = isolate->GetContinuationPreservedEmbedderData(); // signal safe?
1007+
if (!cped->IsObject()) return std::shared_ptr<Global<Value>>();
1008+
1009+
auto cpedObj = cped.As<Object>();
1010+
auto localSymbol = cpedSymbol_.Get(isolate); // signal safe?
1011+
auto maybeProfData = cpedObj->Get(isolate->GetCurrentContext(), localSymbol); // signal safe?
1012+
if (maybeProfData.IsEmpty()) return std::shared_ptr<Global<Value>>();
1013+
auto profData = maybeProfData.ToLocalChecked();
1014+
1015+
if (profData->IsNullOrUndefined()) return std::shared_ptr<Global<Value>>();
1016+
1017+
auto contextPtr = std::atomic_load_explicit(reinterpret_cast<ContextPtr*>(profData.As<External>()->Value()), std::memory_order_relaxed);
9731018
std::atomic_signal_fence(std::memory_order_acquire);
9741019
return contextPtr;
9751020
}
@@ -1001,12 +1046,14 @@ NAN_METHOD(WallProfiler::Dispose) {
10011046

10021047
void WallProfiler::PushContext(int64_t time_from,
10031048
int64_t time_to,
1004-
int64_t cpu_time) {
1049+
int64_t cpu_time,
1050+
Isolate* isolate) {
10051051
// Be careful this is called in a signal handler context therefore all
10061052
// operations must be async signal safe (in particular no allocations).
10071053
// Our ring buffer avoids allocations.
10081054
if (contexts_.size() < contexts_.capacity()) {
1009-
contexts_.push_back({GetContextPtr(), time_from, time_to, cpu_time});
1055+
HandleScope handle_scope(isolate); // will this fly in a signal handler?
1056+
contexts_.push_back({GetContextPtr(isolate), time_from, time_to, cpu_time});
10101057
std::atomic_fetch_add_explicit(
10111058
reinterpret_cast<std::atomic<uint32_t>*>(&fields_[kSampleCount]),
10121059
1U,

bindings/profilers/wall.hh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class WallProfiler : public Nan::ObjectWrap {
5151
// avoid heap allocation. Need to figure out the right move/copy semantics in
5252
// and out of the ring buffer.
5353

54-
ContextPtr curContext_;
54+
v8::Global<v8::Symbol> cpedSymbol_;
5555

5656
std::atomic<CollectionMode> collectionMode_;
5757
std::atomic<uint64_t> noCollectCallCount_;
@@ -95,7 +95,7 @@ class WallProfiler : public Nan::ObjectWrap {
9595
int64_t startCpuTime);
9696

9797
bool waitForSignal(uint64_t targetCallCount = 0);
98-
ContextPtr GetContextPtr();
98+
ContextPtr GetContextPtr(v8::Isolate* isolate);
9999

100100
public:
101101
/**
@@ -115,7 +115,7 @@ class WallProfiler : public Nan::ObjectWrap {
115115

116116
v8::Local<v8::Value> GetContext(v8::Isolate*);
117117
void SetContext(v8::Isolate*, v8::Local<v8::Value>);
118-
void PushContext(int64_t time_from, int64_t time_to, int64_t cpu_time);
118+
void PushContext(int64_t time_from, int64_t time_to, int64_t cpu_time, v8::Isolate* isolate);
119119
Result StartImpl();
120120
std::string StartInternal();
121121
Result StopImpl(bool restart, v8::Local<v8::Value>& profile);

0 commit comments

Comments
 (0)