diff options
author | James M Snell <jasnell@gmail.com> | 2017-12-22 01:29:05 +0300 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2017-12-27 21:44:40 +0300 |
commit | 9e5ccf0313b7167d710e50c511db17ecfcdf416f (patch) | |
tree | 503308ce701ff3e18b2f9c2744c068f028904572 /src/node_perf.cc | |
parent | 6c0da349056578d36254d1aed973ddbaa252ce89 (diff) |
perf_hooks: refactor internals
Refactor and simplify the perf_hooks native internals.
PR-URL: https://github.com/nodejs/node/pull/17822
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'src/node_perf.cc')
-rw-r--r-- | src/node_perf.cc | 259 |
1 files changed, 110 insertions, 149 deletions
diff --git a/src/node_perf.cc b/src/node_perf.cc index 37256a943cb..fcf7cd8b5af 100644 --- a/src/node_perf.cc +++ b/src/node_perf.cc @@ -17,9 +17,8 @@ using v8::Integer; using v8::Isolate; using v8::Local; using v8::Name; +using v8::Number; using v8::Object; -using v8::ObjectTemplate; -using v8::Signature; using v8::String; using v8::Value; @@ -30,37 +29,78 @@ uint64_t performance_v8_start; uint64_t performance_last_gc_start_mark_ = 0; v8::GCType performance_last_gc_type_ = v8::GCType::kGCTypeAll; +// Initialize the performance entry object properties +inline void InitObject(const PerformanceEntry& entry, Local<Object> obj) { + Environment* env = entry.env(); + Isolate* isolate = env->isolate(); + Local<Context> context = env->context(); + v8::PropertyAttribute attr = + static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); + obj->DefineOwnProperty(context, + env->name_string(), + String::NewFromUtf8(isolate, + entry.name().c_str(), + String::kNormalString), + attr).FromJust(); + obj->DefineOwnProperty(context, + FIXED_ONE_BYTE_STRING(isolate, "entryType"), + String::NewFromUtf8(isolate, + entry.type().c_str(), + String::kNormalString), + attr).FromJust(); + obj->DefineOwnProperty(context, + FIXED_ONE_BYTE_STRING(isolate, "startTime"), + Number::New(isolate, entry.startTime()), + attr).FromJust(); + obj->DefineOwnProperty(context, + FIXED_ONE_BYTE_STRING(isolate, "duration"), + Number::New(isolate, entry.duration()), + attr).FromJust(); +} + +// Create a new PerformanceEntry object +const Local<Object> PerformanceEntry::ToObject() const { + Local<Object> obj = + env_->performance_entry_template() + ->NewInstance(env_->context()).ToLocalChecked(); + InitObject(*this, obj); + return obj; +} + +// Allow creating a PerformanceEntry object from JavaScript void PerformanceEntry::New(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); Isolate* isolate = env->isolate(); Utf8Value name(isolate, args[0]); Utf8Value type(isolate, args[1]); uint64_t now = PERFORMANCE_NOW(); - new PerformanceEntry(env, args.This(), *name, *type, now, now); + PerformanceEntry entry(env, *name, *type, now, now); + Local<Object> obj = args.This(); + InitObject(entry, obj); + PerformanceEntry::Notify(env, entry.kind(), obj); } -void PerformanceEntry::NotifyObservers(Environment* env, - PerformanceEntry* entry) { +// Pass the PerformanceEntry object to the PerformanceObservers +inline void PerformanceEntry::Notify(Environment* env, + PerformanceEntryType type, + Local<Value> object) { + Context::Scope scope(env->context()); uint32_t* observers = env->performance_state()->observers; - PerformanceEntryType type = ToPerformanceEntryTypeEnum(entry->type().c_str()); - if (observers == nullptr || - type == NODE_PERFORMANCE_ENTRY_TYPE_INVALID || - !observers[type]) { - return; + if (observers != nullptr && + type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID && + observers[type]) { + node::MakeCallback(env->isolate(), + env->process_object(), + env->performance_entry_callback(), + 1, &object); } - Local<Context> context = env->context(); - Isolate* isolate = env->isolate(); - Local<Value> argv = entry->object(); - env->performance_entry_callback()->Call(context, - v8::Undefined(isolate), - 1, &argv).ToLocalChecked(); } +// Create a User Timing Mark void Mark(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); - Local<Context> context = env->context(); - Isolate* isolate = env->isolate(); - Utf8Value name(isolate, args[0]); + HandleScope scope(env->isolate()); + Utf8Value name(env->isolate(), args[0]); uint64_t now = PERFORMANCE_NOW(); auto marks = env->performance_marks(); (*marks)[*name] = now; @@ -68,25 +108,27 @@ void Mark(const FunctionCallbackInfo<Value>& args) { // TODO(jasnell): Once Tracing API is fully implemented, this should // record a trace event also. - Local<Function> fn = env->performance_entry_template(); - Local<Object> obj = fn->NewInstance(context).ToLocalChecked(); - new PerformanceEntry(env, obj, *name, "mark", now, now); + PerformanceEntry entry(env, *name, "mark", now, now); + Local<Object> obj = entry.ToObject(); + PerformanceEntry::Notify(env, entry.kind(), obj); args.GetReturnValue().Set(obj); } + inline uint64_t GetPerformanceMark(Environment* env, std::string name) { auto marks = env->performance_marks(); auto res = marks->find(name); return res != marks->end() ? res->second : 0; } +// Create a User Timing Measure. A Measure is a PerformanceEntry that +// measures the duration between two distinct user timing marks void Measure(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); - Local<Context> context = env->context(); - Isolate* isolate = env->isolate(); - Utf8Value name(isolate, args[0]); - Utf8Value startMark(isolate, args[1]); - Utf8Value endMark(isolate, args[2]); + HandleScope scope(env->isolate()); + Utf8Value name(env->isolate(), args[0]); + Utf8Value startMark(env->isolate(), args[1]); + Utf8Value endMark(env->isolate(), args[2]); double* milestones = env->performance_state()->milestones; @@ -113,41 +155,13 @@ void Measure(const FunctionCallbackInfo<Value>& args) { // TODO(jasnell): Once Tracing API is fully implemented, this should // record a trace event also. - Local<Function> fn = env->performance_entry_template(); - Local<Object> obj = fn->NewInstance(context).ToLocalChecked(); - new PerformanceEntry(env, obj, *name, "measure", - startTimestamp, endTimestamp); + PerformanceEntry entry(env, *name, "measure", startTimestamp, endTimestamp); + Local<Object> obj = entry.ToObject(); + PerformanceEntry::Notify(env, entry.kind(), obj); args.GetReturnValue().Set(obj); } -void GetPerformanceEntryName(const FunctionCallbackInfo<Value>& info) { - Isolate* isolate = info.GetIsolate(); - PerformanceEntry* entry; - ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder()); - info.GetReturnValue().Set( - String::NewFromUtf8(isolate, entry->name().c_str(), String::kNormalString)); -} - -void GetPerformanceEntryType(const FunctionCallbackInfo<Value>& info) { - Isolate* isolate = info.GetIsolate(); - PerformanceEntry* entry; - ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder()); - info.GetReturnValue().Set( - String::NewFromUtf8(isolate, entry->type().c_str(), String::kNormalString)); -} - -void GetPerformanceEntryStartTime(const FunctionCallbackInfo<Value>& info) { - PerformanceEntry* entry; - ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder()); - info.GetReturnValue().Set(entry->startTime()); -} - -void GetPerformanceEntryDuration(const FunctionCallbackInfo<Value>& info) { - PerformanceEntry* entry; - ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder()); - info.GetReturnValue().Set(entry->duration()); -} - +// Allows specific Node.js lifecycle milestones to be set from JavaScript void MarkMilestone(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); Local<Context> context = env->context(); @@ -160,44 +174,35 @@ void MarkMilestone(const FunctionCallbackInfo<Value>& args) { } } + void SetupPerformanceObservers(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); CHECK(args[0]->IsFunction()); env->set_performance_entry_callback(args[0].As<Function>()); } -void PerformanceGCCallback(uv_async_t* handle) { - PerformanceEntry::Data* data = - static_cast<PerformanceEntry::Data*>(handle->data); - Environment* env = data->env(); - Isolate* isolate = env->isolate(); - HandleScope scope(isolate); +// Creates a GC Performance Entry and passes it to observers +void PerformanceGCCallback(Environment* env, void* ptr) { + GCPerformanceEntry* entry = static_cast<GCPerformanceEntry*>(ptr); + HandleScope scope(env->isolate()); Local<Context> context = env->context(); - Context::Scope context_scope(context); - Local<Function> fn; - Local<Object> obj; - PerformanceGCKind kind = static_cast<PerformanceGCKind>(data->data()); uint32_t* observers = env->performance_state()->observers; - if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) { - goto cleanup; + if (observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) { + Local<Object> obj = entry->ToObject(); + v8::PropertyAttribute attr = + static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); + obj->DefineOwnProperty(context, + FIXED_ONE_BYTE_STRING(env->isolate(), "kind"), + Integer::New(env->isolate(), entry->gckind()), + attr).FromJust(); + PerformanceEntry::Notify(env, entry->kind(), obj); } - fn = env->performance_entry_template(); - obj = fn->NewInstance(context).ToLocalChecked(); - obj->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "kind"), - Integer::New(isolate, kind)).FromJust(); - new PerformanceEntry(env, obj, data); - - cleanup: - delete data; - auto closeCB = [](uv_handle_t* handle) { - delete reinterpret_cast<uv_async_t*>(handle); - }; - uv_close(reinterpret_cast<uv_handle_t*>(handle), closeCB); + delete entry; } +// Marks the start of a GC cycle void MarkGarbageCollectionStart(Isolate* isolate, v8::GCType type, v8::GCCallbackFlags flags) { @@ -205,28 +210,27 @@ void MarkGarbageCollectionStart(Isolate* isolate, performance_last_gc_type_ = type; } +// Marks the end of a GC cycle void MarkGarbageCollectionEnd(Isolate* isolate, v8::GCType type, v8::GCCallbackFlags flags, void* data) { Environment* env = static_cast<Environment*>(data); - uv_async_t* async = new uv_async_t(); // coverity[leaked_storage] - if (uv_async_init(env->event_loop(), async, PerformanceGCCallback)) - return delete async; - uv_unref(reinterpret_cast<uv_handle_t*>(async)); - async->data = - new PerformanceEntry::Data(env, "gc", "gc", - performance_last_gc_start_mark_, - PERFORMANCE_NOW(), type); - CHECK_EQ(0, uv_async_send(async)); + env->SetImmediate(PerformanceGCCallback, + new GCPerformanceEntry(env, + static_cast<PerformanceGCKind>(type), + performance_last_gc_start_mark_, + PERFORMANCE_NOW())); } + inline void SetupGarbageCollectionTracking(Environment* env) { env->isolate()->AddGCPrologueCallback(MarkGarbageCollectionStart); env->isolate()->AddGCEpilogueCallback(MarkGarbageCollectionEnd, static_cast<void*>(env)); } +// Gets the name of a function inline Local<Value> GetName(Local<Function> fn) { Local<Value> val = fn->GetDebugName(); if (val.IsEmpty() || val->IsUndefined()) { @@ -238,6 +242,9 @@ inline Local<Value> GetName(Local<Function> fn) { return val; } +// Executes a wrapped Function and captures timing information, causing a +// Function PerformanceEntry to be emitted to PerformanceObservers after +// execution. void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); HandleScope scope(isolate); @@ -247,9 +254,8 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) { size_t count = args.Length(); size_t idx; std::vector<Local<Value>> call_args; - for (size_t i = 0; i < count; ++i) { + for (size_t i = 0; i < count; ++i) call_args.push_back(args[i]); - } Utf8Value name(isolate, GetName(fn)); @@ -286,15 +292,14 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) { if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION]) return; - Local<Function> ctor = env->performance_entry_template(); - v8::MaybeLocal<Object> instance = ctor->NewInstance(context); - Local<Object> obj = instance.ToLocalChecked(); - for (idx = 0; idx < count; idx++) { - obj->Set(context, idx, args[idx]).ToChecked(); - } - new PerformanceEntry(env, obj, *name, "function", start, end); + PerformanceEntry entry(env, *name, "function", start, end); + Local<Object> obj = entry.ToObject(); + for (idx = 0; idx < count; idx++) + obj->Set(context, idx, args[idx]).FromJust(); + PerformanceEntry::Notify(env, entry.kind(), obj); } +// Wraps a Function in a TimerFunctionCall void Timerify(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); Local<Context> context = env->context(); @@ -307,6 +312,7 @@ void Timerify(const FunctionCallbackInfo<Value>& args) { args.GetReturnValue().Set(wrap); } + void Init(Local<Object> target, Local<Value> unused, Local<Context> context) { @@ -329,55 +335,10 @@ void Init(Local<Object> target, Local<String> performanceEntryString = FIXED_ONE_BYTE_STRING(isolate, "PerformanceEntry"); - Local<FunctionTemplate> pe = env->NewFunctionTemplate(PerformanceEntry::New); - pe->InstanceTemplate()->SetInternalFieldCount(1); + Local<FunctionTemplate> pe = FunctionTemplate::New(isolate); pe->SetClassName(performanceEntryString); - - Local<Signature> signature = Signature::New(env->isolate(), pe); - - Local<FunctionTemplate> get_performance_entry_name_templ = - FunctionTemplate::New(env->isolate(), - GetPerformanceEntryName, - env->as_external(), - signature); - - Local<FunctionTemplate> get_performance_entry_type_templ = - FunctionTemplate::New(env->isolate(), - GetPerformanceEntryType, - env->as_external(), - signature); - - Local<FunctionTemplate> get_performance_entry_start_time_templ = - FunctionTemplate::New(env->isolate(), - GetPerformanceEntryStartTime, - env->as_external(), - signature); - - Local<FunctionTemplate> get_performance_entry_duration_templ = - FunctionTemplate::New(env->isolate(), - GetPerformanceEntryDuration, - env->as_external(), - signature); - - Local<ObjectTemplate> ot = pe->InstanceTemplate(); - ot->SetAccessorProperty(env->name_string(), - get_performance_entry_name_templ, - Local<FunctionTemplate>()); - - ot->SetAccessorProperty(FIXED_ONE_BYTE_STRING(isolate, "entryType"), - get_performance_entry_type_templ, - Local<FunctionTemplate>()); - - ot->SetAccessorProperty(FIXED_ONE_BYTE_STRING(isolate, "startTime"), - get_performance_entry_start_time_templ, - Local<FunctionTemplate>()); - - ot->SetAccessorProperty(FIXED_ONE_BYTE_STRING(isolate, "duration"), - get_performance_entry_duration_templ, - Local<FunctionTemplate>()); - Local<Function> fn = pe->GetFunction(); - target->Set(performanceEntryString, fn); + target->Set(context, performanceEntryString, fn).FromJust(); env->set_performance_entry_template(fn); env->SetMethod(target, "mark", Mark); |