src: keep track of env properly in node_perf.cc
Currently, measuring GC timing using `node_perf` is somewhat broken, because Isolates and Node Environments do not necessarily match 1:1; each environment adds its own hook, so possibly the hook code runs multiple times, but since it can’t reliably compute its corresponding event loop based on the Isolate, each run targets the same Environment right now. This fixes that problem by using new overloads of the GC tracking APIs that can pass data to the callback through opaque pointers. PR-URL: https://github.com/nodejs/node/pull/15391 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com>
This commit is contained in:
parent
8403d6b999
commit
dcb24e3be5
@ -170,13 +170,14 @@ void SetupPerformanceObservers(const FunctionCallbackInfo<Value>& args) {
|
|||||||
env->set_performance_entry_callback(args[0].As<Function>());
|
env->set_performance_entry_callback(args[0].As<Function>());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void PerformanceGCCallback(uv_async_t* handle) {
|
void PerformanceGCCallback(uv_async_t* handle) {
|
||||||
PerformanceEntry::Data* data =
|
PerformanceEntry::Data* data =
|
||||||
static_cast<PerformanceEntry::Data*>(handle->data);
|
static_cast<PerformanceEntry::Data*>(handle->data);
|
||||||
Isolate* isolate = Isolate::GetCurrent();
|
Environment* env = data->env();
|
||||||
|
Isolate* isolate = env->isolate();
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
Environment* env = Environment::GetCurrent(isolate);
|
|
||||||
Local<Context> context = env->context();
|
Local<Context> context = env->context();
|
||||||
|
Context::Scope context_scope(context);
|
||||||
Local<Function> fn;
|
Local<Function> fn;
|
||||||
Local<Object> obj;
|
Local<Object> obj;
|
||||||
PerformanceGCKind kind = static_cast<PerformanceGCKind>(data->data());
|
PerformanceGCKind kind = static_cast<PerformanceGCKind>(data->data());
|
||||||
@ -199,28 +200,31 @@ inline void PerformanceGCCallback(uv_async_t* handle) {
|
|||||||
uv_close(reinterpret_cast<uv_handle_t*>(handle), closeCB);
|
uv_close(reinterpret_cast<uv_handle_t*>(handle), closeCB);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MarkGarbageCollectionStart(Isolate* isolate,
|
void MarkGarbageCollectionStart(Isolate* isolate,
|
||||||
v8::GCType type,
|
v8::GCType type,
|
||||||
v8::GCCallbackFlags flags) {
|
v8::GCCallbackFlags flags) {
|
||||||
performance_last_gc_start_mark_ = PERFORMANCE_NOW();
|
performance_last_gc_start_mark_ = PERFORMANCE_NOW();
|
||||||
performance_last_gc_type_ = type;
|
performance_last_gc_type_ = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MarkGarbageCollectionEnd(Isolate* isolate,
|
void MarkGarbageCollectionEnd(Isolate* isolate,
|
||||||
v8::GCType type,
|
v8::GCType type,
|
||||||
v8::GCCallbackFlags flags) {
|
v8::GCCallbackFlags flags,
|
||||||
|
void* data) {
|
||||||
|
Environment* env = static_cast<Environment*>(data);
|
||||||
uv_async_t *async = new uv_async_t;
|
uv_async_t *async = new uv_async_t;
|
||||||
async->data =
|
async->data =
|
||||||
new PerformanceEntry::Data("gc", "gc",
|
new PerformanceEntry::Data(env, "gc", "gc",
|
||||||
performance_last_gc_start_mark_,
|
performance_last_gc_start_mark_,
|
||||||
PERFORMANCE_NOW(), type);
|
PERFORMANCE_NOW(), type);
|
||||||
uv_async_init(uv_default_loop(), async, PerformanceGCCallback);
|
uv_async_init(env->event_loop(), async, PerformanceGCCallback);
|
||||||
uv_async_send(async);
|
uv_async_send(async);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SetupGarbageCollectionTracking(Isolate* isolate) {
|
inline void SetupGarbageCollectionTracking(Environment* env) {
|
||||||
isolate->AddGCPrologueCallback(MarkGarbageCollectionStart);
|
env->isolate()->AddGCPrologueCallback(MarkGarbageCollectionStart);
|
||||||
isolate->AddGCEpilogueCallback(MarkGarbageCollectionEnd);
|
env->isolate()->AddGCEpilogueCallback(MarkGarbageCollectionEnd,
|
||||||
|
static_cast<void*>(env));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Local<Value> GetName(Local<Function> fn) {
|
inline Local<Value> GetName(Local<Function> fn) {
|
||||||
@ -376,7 +380,7 @@ void Init(Local<Object> target,
|
|||||||
constants,
|
constants,
|
||||||
attr).ToChecked();
|
attr).ToChecked();
|
||||||
|
|
||||||
SetupGarbageCollectionTracking(isolate);
|
SetupGarbageCollectionTracking(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace performance
|
} // namespace performance
|
||||||
|
@ -56,17 +56,23 @@ class PerformanceEntry : public BaseObject {
|
|||||||
class Data {
|
class Data {
|
||||||
public:
|
public:
|
||||||
Data(
|
Data(
|
||||||
|
Environment* env,
|
||||||
const char* name,
|
const char* name,
|
||||||
const char* type,
|
const char* type,
|
||||||
uint64_t startTime,
|
uint64_t startTime,
|
||||||
uint64_t endTime,
|
uint64_t endTime,
|
||||||
int data = 0) :
|
int data = 0) :
|
||||||
|
env_(env),
|
||||||
name_(name),
|
name_(name),
|
||||||
type_(type),
|
type_(type),
|
||||||
startTime_(startTime),
|
startTime_(startTime),
|
||||||
endTime_(endTime),
|
endTime_(endTime),
|
||||||
data_(data) {}
|
data_(data) {}
|
||||||
|
|
||||||
|
Environment* env() const {
|
||||||
|
return env_;
|
||||||
|
}
|
||||||
|
|
||||||
std::string name() const {
|
std::string name() const {
|
||||||
return name_;
|
return name_;
|
||||||
}
|
}
|
||||||
@ -88,6 +94,7 @@ class PerformanceEntry : public BaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Environment* env_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
std::string type_;
|
std::string type_;
|
||||||
uint64_t startTime_;
|
uint64_t startTime_;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user