Skip to content

Commit a329cf6

Browse files
jasnellMylesBorins
authored andcommitted
perf_hooks: refactor internals
Refactor and simplify the perf_hooks native internals. PR-URL: #17822 Reviewed-By: Anna Henningsen <[email protected]>
1 parent f82439b commit a329cf6

File tree

2 files changed

+150
-243
lines changed

2 files changed

+150
-243
lines changed

src/node_perf.cc

+110-149
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ using v8::Integer;
1717
using v8::Isolate;
1818
using v8::Local;
1919
using v8::Name;
20+
using v8::Number;
2021
using v8::Object;
21-
using v8::ObjectTemplate;
22-
using v8::Signature;
2322
using v8::String;
2423
using v8::Value;
2524

@@ -30,63 +29,106 @@ uint64_t performance_v8_start;
3029
uint64_t performance_last_gc_start_mark_ = 0;
3130
v8::GCType performance_last_gc_type_ = v8::GCType::kGCTypeAll;
3231

32+
// Initialize the performance entry object properties
33+
inline void InitObject(const PerformanceEntry& entry, Local<Object> obj) {
34+
Environment* env = entry.env();
35+
Isolate* isolate = env->isolate();
36+
Local<Context> context = env->context();
37+
v8::PropertyAttribute attr =
38+
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
39+
obj->DefineOwnProperty(context,
40+
env->name_string(),
41+
String::NewFromUtf8(isolate,
42+
entry.name().c_str(),
43+
String::kNormalString),
44+
attr).FromJust();
45+
obj->DefineOwnProperty(context,
46+
FIXED_ONE_BYTE_STRING(isolate, "entryType"),
47+
String::NewFromUtf8(isolate,
48+
entry.type().c_str(),
49+
String::kNormalString),
50+
attr).FromJust();
51+
obj->DefineOwnProperty(context,
52+
FIXED_ONE_BYTE_STRING(isolate, "startTime"),
53+
Number::New(isolate, entry.startTime()),
54+
attr).FromJust();
55+
obj->DefineOwnProperty(context,
56+
FIXED_ONE_BYTE_STRING(isolate, "duration"),
57+
Number::New(isolate, entry.duration()),
58+
attr).FromJust();
59+
}
60+
61+
// Create a new PerformanceEntry object
62+
const Local<Object> PerformanceEntry::ToObject() const {
63+
Local<Object> obj =
64+
env_->performance_entry_template()
65+
->NewInstance(env_->context()).ToLocalChecked();
66+
InitObject(*this, obj);
67+
return obj;
68+
}
69+
70+
// Allow creating a PerformanceEntry object from JavaScript
3371
void PerformanceEntry::New(const FunctionCallbackInfo<Value>& args) {
3472
Environment* env = Environment::GetCurrent(args);
3573
Isolate* isolate = env->isolate();
3674
Utf8Value name(isolate, args[0]);
3775
Utf8Value type(isolate, args[1]);
3876
uint64_t now = PERFORMANCE_NOW();
39-
new PerformanceEntry(env, args.This(), *name, *type, now, now);
77+
PerformanceEntry entry(env, *name, *type, now, now);
78+
Local<Object> obj = args.This();
79+
InitObject(entry, obj);
80+
PerformanceEntry::Notify(env, entry.kind(), obj);
4081
}
4182

42-
void PerformanceEntry::NotifyObservers(Environment* env,
43-
PerformanceEntry* entry) {
83+
// Pass the PerformanceEntry object to the PerformanceObservers
84+
inline void PerformanceEntry::Notify(Environment* env,
85+
PerformanceEntryType type,
86+
Local<Value> object) {
87+
Context::Scope scope(env->context());
4488
uint32_t* observers = env->performance_state()->observers;
45-
PerformanceEntryType type = ToPerformanceEntryTypeEnum(entry->type().c_str());
46-
if (observers == nullptr ||
47-
type == NODE_PERFORMANCE_ENTRY_TYPE_INVALID ||
48-
!observers[type]) {
49-
return;
89+
if (observers != nullptr &&
90+
type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID &&
91+
observers[type]) {
92+
node::MakeCallback(env->isolate(),
93+
env->process_object(),
94+
env->performance_entry_callback(),
95+
1, &object);
5096
}
51-
Local<Context> context = env->context();
52-
Isolate* isolate = env->isolate();
53-
Local<Value> argv = entry->object();
54-
env->performance_entry_callback()->Call(context,
55-
v8::Undefined(isolate),
56-
1, &argv).ToLocalChecked();
5797
}
5898

99+
// Create a User Timing Mark
59100
void Mark(const FunctionCallbackInfo<Value>& args) {
60101
Environment* env = Environment::GetCurrent(args);
61-
Local<Context> context = env->context();
62-
Isolate* isolate = env->isolate();
63-
Utf8Value name(isolate, args[0]);
102+
HandleScope scope(env->isolate());
103+
Utf8Value name(env->isolate(), args[0]);
64104
uint64_t now = PERFORMANCE_NOW();
65105
auto marks = env->performance_marks();
66106
(*marks)[*name] = now;
67107

68108
// TODO(jasnell): Once Tracing API is fully implemented, this should
69109
// record a trace event also.
70110

71-
Local<Function> fn = env->performance_entry_template();
72-
Local<Object> obj = fn->NewInstance(context).ToLocalChecked();
73-
new PerformanceEntry(env, obj, *name, "mark", now, now);
111+
PerformanceEntry entry(env, *name, "mark", now, now);
112+
Local<Object> obj = entry.ToObject();
113+
PerformanceEntry::Notify(env, entry.kind(), obj);
74114
args.GetReturnValue().Set(obj);
75115
}
76116

117+
77118
inline uint64_t GetPerformanceMark(Environment* env, std::string name) {
78119
auto marks = env->performance_marks();
79120
auto res = marks->find(name);
80121
return res != marks->end() ? res->second : 0;
81122
}
82123

124+
// Create a User Timing Measure. A Measure is a PerformanceEntry that
125+
// measures the duration between two distinct user timing marks
83126
void Measure(const FunctionCallbackInfo<Value>& args) {
84127
Environment* env = Environment::GetCurrent(args);
85-
Local<Context> context = env->context();
86-
Isolate* isolate = env->isolate();
87-
Utf8Value name(isolate, args[0]);
88-
Utf8Value startMark(isolate, args[1]);
89-
Utf8Value endMark(isolate, args[2]);
128+
HandleScope scope(env->isolate());
129+
Utf8Value name(env->isolate(), args[0]);
130+
Utf8Value startMark(env->isolate(), args[1]);
131+
Utf8Value endMark(env->isolate(), args[2]);
90132

91133
double* milestones = env->performance_state()->milestones;
92134

@@ -113,41 +155,13 @@ void Measure(const FunctionCallbackInfo<Value>& args) {
113155
// TODO(jasnell): Once Tracing API is fully implemented, this should
114156
// record a trace event also.
115157

116-
Local<Function> fn = env->performance_entry_template();
117-
Local<Object> obj = fn->NewInstance(context).ToLocalChecked();
118-
new PerformanceEntry(env, obj, *name, "measure",
119-
startTimestamp, endTimestamp);
158+
PerformanceEntry entry(env, *name, "measure", startTimestamp, endTimestamp);
159+
Local<Object> obj = entry.ToObject();
160+
PerformanceEntry::Notify(env, entry.kind(), obj);
120161
args.GetReturnValue().Set(obj);
121162
}
122163

123-
void GetPerformanceEntryName(const FunctionCallbackInfo<Value>& info) {
124-
Isolate* isolate = info.GetIsolate();
125-
PerformanceEntry* entry;
126-
ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
127-
info.GetReturnValue().Set(
128-
String::NewFromUtf8(isolate, entry->name().c_str(), String::kNormalString));
129-
}
130-
131-
void GetPerformanceEntryType(const FunctionCallbackInfo<Value>& info) {
132-
Isolate* isolate = info.GetIsolate();
133-
PerformanceEntry* entry;
134-
ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
135-
info.GetReturnValue().Set(
136-
String::NewFromUtf8(isolate, entry->type().c_str(), String::kNormalString));
137-
}
138-
139-
void GetPerformanceEntryStartTime(const FunctionCallbackInfo<Value>& info) {
140-
PerformanceEntry* entry;
141-
ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
142-
info.GetReturnValue().Set(entry->startTime());
143-
}
144-
145-
void GetPerformanceEntryDuration(const FunctionCallbackInfo<Value>& info) {
146-
PerformanceEntry* entry;
147-
ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
148-
info.GetReturnValue().Set(entry->duration());
149-
}
150-
164+
// Allows specific Node.js lifecycle milestones to be set from JavaScript
151165
void MarkMilestone(const FunctionCallbackInfo<Value>& args) {
152166
Environment* env = Environment::GetCurrent(args);
153167
Local<Context> context = env->context();
@@ -160,73 +174,63 @@ void MarkMilestone(const FunctionCallbackInfo<Value>& args) {
160174
}
161175
}
162176

177+
163178
void SetupPerformanceObservers(const FunctionCallbackInfo<Value>& args) {
164179
Environment* env = Environment::GetCurrent(args);
165180
CHECK(args[0]->IsFunction());
166181
env->set_performance_entry_callback(args[0].As<Function>());
167182
}
168183

169-
void PerformanceGCCallback(uv_async_t* handle) {
170-
PerformanceEntry::Data* data =
171-
static_cast<PerformanceEntry::Data*>(handle->data);
172-
Environment* env = data->env();
173-
Isolate* isolate = env->isolate();
174-
HandleScope scope(isolate);
184+
// Creates a GC Performance Entry and passes it to observers
185+
void PerformanceGCCallback(Environment* env, void* ptr) {
186+
GCPerformanceEntry* entry = static_cast<GCPerformanceEntry*>(ptr);
187+
HandleScope scope(env->isolate());
175188
Local<Context> context = env->context();
176-
Context::Scope context_scope(context);
177-
Local<Function> fn;
178-
Local<Object> obj;
179-
PerformanceGCKind kind = static_cast<PerformanceGCKind>(data->data());
180189

181190
uint32_t* observers = env->performance_state()->observers;
182-
if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) {
183-
goto cleanup;
191+
if (observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) {
192+
Local<Object> obj = entry->ToObject();
193+
v8::PropertyAttribute attr =
194+
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
195+
obj->DefineOwnProperty(context,
196+
FIXED_ONE_BYTE_STRING(env->isolate(), "kind"),
197+
Integer::New(env->isolate(), entry->gckind()),
198+
attr).FromJust();
199+
PerformanceEntry::Notify(env, entry->kind(), obj);
184200
}
185201

186-
fn = env->performance_entry_template();
187-
obj = fn->NewInstance(context).ToLocalChecked();
188-
obj->Set(context,
189-
FIXED_ONE_BYTE_STRING(isolate, "kind"),
190-
Integer::New(isolate, kind)).FromJust();
191-
new PerformanceEntry(env, obj, data);
192-
193-
cleanup:
194-
delete data;
195-
auto closeCB = [](uv_handle_t* handle) {
196-
delete reinterpret_cast<uv_async_t*>(handle);
197-
};
198-
uv_close(reinterpret_cast<uv_handle_t*>(handle), closeCB);
202+
delete entry;
199203
}
200204

205+
// Marks the start of a GC cycle
201206
void MarkGarbageCollectionStart(Isolate* isolate,
202207
v8::GCType type,
203208
v8::GCCallbackFlags flags) {
204209
performance_last_gc_start_mark_ = PERFORMANCE_NOW();
205210
performance_last_gc_type_ = type;
206211
}
207212

213+
// Marks the end of a GC cycle
208214
void MarkGarbageCollectionEnd(Isolate* isolate,
209215
v8::GCType type,
210216
v8::GCCallbackFlags flags,
211217
void* data) {
212218
Environment* env = static_cast<Environment*>(data);
213-
uv_async_t* async = new uv_async_t(); // coverity[leaked_storage]
214-
if (uv_async_init(env->event_loop(), async, PerformanceGCCallback))
215-
return delete async;
216-
uv_unref(reinterpret_cast<uv_handle_t*>(async));
217-
async->data =
218-
new PerformanceEntry::Data(env, "gc", "gc",
219-
performance_last_gc_start_mark_,
220-
PERFORMANCE_NOW(), type);
221-
CHECK_EQ(0, uv_async_send(async));
219+
env->SetImmediate(PerformanceGCCallback,
220+
new GCPerformanceEntry(env,
221+
static_cast<PerformanceGCKind>(type),
222+
performance_last_gc_start_mark_,
223+
PERFORMANCE_NOW()));
222224
}
223225

226+
224227
inline void SetupGarbageCollectionTracking(Environment* env) {
225228
env->isolate()->AddGCPrologueCallback(MarkGarbageCollectionStart);
226229
env->isolate()->AddGCEpilogueCallback(MarkGarbageCollectionEnd,
227230
static_cast<void*>(env));
228231
}
229232

233+
// Gets the name of a function
230234
inline Local<Value> GetName(Local<Function> fn) {
231235
Local<Value> val = fn->GetDebugName();
232236
if (val.IsEmpty() || val->IsUndefined()) {
@@ -238,6 +242,9 @@ inline Local<Value> GetName(Local<Function> fn) {
238242
return val;
239243
}
240244

245+
// Executes a wrapped Function and captures timing information, causing a
246+
// Function PerformanceEntry to be emitted to PerformanceObservers after
247+
// execution.
241248
void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
242249
Isolate* isolate = args.GetIsolate();
243250
HandleScope scope(isolate);
@@ -247,9 +254,8 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
247254
size_t count = args.Length();
248255
size_t idx;
249256
std::vector<Local<Value>> call_args;
250-
for (size_t i = 0; i < count; ++i) {
257+
for (size_t i = 0; i < count; ++i)
251258
call_args.push_back(args[i]);
252-
}
253259

254260
Utf8Value name(isolate, GetName(fn));
255261

@@ -286,15 +292,14 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
286292
if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION])
287293
return;
288294

289-
Local<Function> ctor = env->performance_entry_template();
290-
v8::MaybeLocal<Object> instance = ctor->NewInstance(context);
291-
Local<Object> obj = instance.ToLocalChecked();
292-
for (idx = 0; idx < count; idx++) {
293-
obj->Set(context, idx, args[idx]).ToChecked();
294-
}
295-
new PerformanceEntry(env, obj, *name, "function", start, end);
295+
PerformanceEntry entry(env, *name, "function", start, end);
296+
Local<Object> obj = entry.ToObject();
297+
for (idx = 0; idx < count; idx++)
298+
obj->Set(context, idx, args[idx]).FromJust();
299+
PerformanceEntry::Notify(env, entry.kind(), obj);
296300
}
297301

302+
// Wraps a Function in a TimerFunctionCall
298303
void Timerify(const FunctionCallbackInfo<Value>& args) {
299304
Environment* env = Environment::GetCurrent(args);
300305
Local<Context> context = env->context();
@@ -307,6 +312,7 @@ void Timerify(const FunctionCallbackInfo<Value>& args) {
307312
args.GetReturnValue().Set(wrap);
308313
}
309314

315+
310316
void Init(Local<Object> target,
311317
Local<Value> unused,
312318
Local<Context> context) {
@@ -329,55 +335,10 @@ void Init(Local<Object> target,
329335
Local<String> performanceEntryString =
330336
FIXED_ONE_BYTE_STRING(isolate, "PerformanceEntry");
331337

332-
Local<FunctionTemplate> pe = env->NewFunctionTemplate(PerformanceEntry::New);
333-
pe->InstanceTemplate()->SetInternalFieldCount(1);
338+
Local<FunctionTemplate> pe = FunctionTemplate::New(isolate);
334339
pe->SetClassName(performanceEntryString);
335-
336-
Local<Signature> signature = Signature::New(env->isolate(), pe);
337-
338-
Local<FunctionTemplate> get_performance_entry_name_templ =
339-
FunctionTemplate::New(env->isolate(),
340-
GetPerformanceEntryName,
341-
env->as_external(),
342-
signature);
343-
344-
Local<FunctionTemplate> get_performance_entry_type_templ =
345-
FunctionTemplate::New(env->isolate(),
346-
GetPerformanceEntryType,
347-
env->as_external(),
348-
signature);
349-
350-
Local<FunctionTemplate> get_performance_entry_start_time_templ =
351-
FunctionTemplate::New(env->isolate(),
352-
GetPerformanceEntryStartTime,
353-
env->as_external(),
354-
signature);
355-
356-
Local<FunctionTemplate> get_performance_entry_duration_templ =
357-
FunctionTemplate::New(env->isolate(),
358-
GetPerformanceEntryDuration,
359-
env->as_external(),
360-
signature);
361-
362-
Local<ObjectTemplate> ot = pe->InstanceTemplate();
363-
ot->SetAccessorProperty(env->name_string(),
364-
get_performance_entry_name_templ,
365-
Local<FunctionTemplate>());
366-
367-
ot->SetAccessorProperty(FIXED_ONE_BYTE_STRING(isolate, "entryType"),
368-
get_performance_entry_type_templ,
369-
Local<FunctionTemplate>());
370-
371-
ot->SetAccessorProperty(FIXED_ONE_BYTE_STRING(isolate, "startTime"),
372-
get_performance_entry_start_time_templ,
373-
Local<FunctionTemplate>());
374-
375-
ot->SetAccessorProperty(FIXED_ONE_BYTE_STRING(isolate, "duration"),
376-
get_performance_entry_duration_templ,
377-
Local<FunctionTemplate>());
378-
379340
Local<Function> fn = pe->GetFunction();
380-
target->Set(performanceEntryString, fn);
341+
target->Set(context, performanceEntryString, fn).FromJust();
381342
env->set_performance_entry_template(fn);
382343

383344
env->SetMethod(target, "mark", Mark);

0 commit comments

Comments
 (0)