summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2017-12-21 14:29:05 -0800
committerAnna Henningsen <anna@addaleax.net>2017-12-27 19:44:40 +0100
commit9e5ccf0313b7167d710e50c511db17ecfcdf416f (patch)
tree503308ce701ff3e18b2f9c2744c068f028904572
parent6c0da349056578d36254d1aed973ddbaa252ce89 (diff)
downloadandroid-node-v8-9e5ccf0313b7167d710e50c511db17ecfcdf416f.tar.gz
android-node-v8-9e5ccf0313b7167d710e50c511db17ecfcdf416f.tar.bz2
android-node-v8-9e5ccf0313b7167d710e50c511db17ecfcdf416f.zip
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>
-rw-r--r--src/node_perf.cc259
-rw-r--r--src/node_perf.h134
2 files changed, 150 insertions, 243 deletions
diff --git a/src/node_perf.cc b/src/node_perf.cc
index 37256a943c..fcf7cd8b5a 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);
diff --git a/src/node_perf.h b/src/node_perf.h
index 690f708309..e5655f54fe 100644
--- a/src/node_perf.h
+++ b/src/node_perf.h
@@ -42,120 +42,51 @@ static inline PerformanceEntryType ToPerformanceEntryTypeEnum(
NODE_EXTERN inline void MarkPerformanceMilestone(
Environment* env,
PerformanceMilestone milestone) {
- env->performance_state()->milestones[milestone] = PERFORMANCE_NOW();
- }
+ env->performance_state()->milestones[milestone] = PERFORMANCE_NOW();
+}
-class PerformanceEntry : public BaseObject {
+class PerformanceEntry {
public:
- // Used for temporary storage of performance entry details when the
- // object cannot be created immediately.
- class Data {
- public:
- Data(
- Environment* env,
- const char* name,
- const char* type,
- uint64_t startTime,
- uint64_t endTime,
- int data = 0) :
- env_(env),
- name_(name),
- type_(type),
- startTime_(startTime),
- endTime_(endTime),
- data_(data) {}
-
- Environment* env() const {
- return env_;
- }
-
- const std::string& name() const {
- return name_;
- }
-
- const std::string& type() const {
- return type_;
- }
-
- uint64_t startTime() const {
- return startTime_;
- }
-
- uint64_t endTime() const {
- return endTime_;
- }
-
- int data() const {
- return data_;
- }
-
- private:
- Environment* const env_;
- const std::string name_;
- const std::string type_;
- const uint64_t startTime_;
- const uint64_t endTime_;
- const int data_;
- };
-
- static void NotifyObservers(Environment* env, PerformanceEntry* entry);
+ static inline void Notify(Environment* env,
+ PerformanceEntryType type,
+ Local<Value> object);
static void New(const FunctionCallbackInfo<Value>& args);
PerformanceEntry(Environment* env,
- Local<Object> wrap,
const char* name,
const char* type,
uint64_t startTime,
- uint64_t endTime) :
- BaseObject(env, wrap),
- name_(name),
- type_(type),
- startTime_(startTime),
- endTime_(endTime) {
- MakeWeak<PerformanceEntry>(this);
- NotifyObservers(env, this);
- }
+ uint64_t endTime) : env_(env),
+ name_(name),
+ type_(type),
+ startTime_(startTime),
+ endTime_(endTime) { }
- PerformanceEntry(Environment* env,
- Local<Object> wrap,
- Data* data) :
- BaseObject(env, wrap),
- name_(data->name()),
- type_(data->type()),
- startTime_(data->startTime()),
- endTime_(data->endTime()) {
- MakeWeak<PerformanceEntry>(this);
- NotifyObservers(env, this);
- }
+ virtual ~PerformanceEntry() { }
- ~PerformanceEntry() {}
+ virtual const Local<Object> ToObject() const;
- const std::string& name() const {
- return name_;
- }
+ Environment* env() const { return env_; }
- const std::string& type() const {
- return type_;
- }
+ const std::string& name() const { return name_; }
- double startTime() const {
- return startTime_ / 1e6;
- }
+ const std::string& type() const { return type_; }
- double duration() const {
- return durationNano() / 1e6;
+ PerformanceEntryType kind() {
+ return ToPerformanceEntryTypeEnum(type().c_str());
}
- uint64_t startTimeNano() const {
- return startTime_;
- }
+ double startTime() const { return startTime_ / 1e6; }
- uint64_t durationNano() const {
- return endTime_ - startTime_;
- }
+ double duration() const { return durationNano() / 1e6; }
+
+ uint64_t startTimeNano() const { return startTime_; }
+
+ uint64_t durationNano() const { return endTime_ - startTime_; }
private:
+ Environment* env_;
const std::string name_;
const std::string type_;
const uint64_t startTime_;
@@ -169,6 +100,21 @@ enum PerformanceGCKind {
NODE_PERFORMANCE_GC_WEAKCB = GCType::kGCTypeProcessWeakCallbacks
};
+class GCPerformanceEntry : public PerformanceEntry {
+ public:
+ GCPerformanceEntry(Environment* env,
+ PerformanceGCKind gckind,
+ uint64_t startTime,
+ uint64_t endTime) :
+ PerformanceEntry(env, "gc", "gc", startTime, endTime),
+ gckind_(gckind) { }
+
+ PerformanceGCKind gckind() const { return gckind_; }
+
+ private:
+ PerformanceGCKind gckind_;
+};
+
} // namespace performance
} // namespace node