1 #include "aliased_buffer.h"
2 #include "memory_tracker-inl.h"
3 #include "node_internals.h"
4 #include "node_perf.h"
5 #include "node_buffer.h"
6 #include "node_process.h"
7 #include "util-inl.h"
8
9 #include <cinttypes>
10
11 namespace node {
12 namespace performance {
13
14 using v8::Context;
15 using v8::DontDelete;
16 using v8::Function;
17 using v8::FunctionCallbackInfo;
18 using v8::FunctionTemplate;
19 using v8::GCCallbackFlags;
20 using v8::GCType;
21 using v8::HandleScope;
22 using v8::Integer;
23 using v8::Isolate;
24 using v8::Local;
25 using v8::Map;
26 using v8::MaybeLocal;
27 using v8::NewStringType;
28 using v8::Number;
29 using v8::Object;
30 using v8::PropertyAttribute;
31 using v8::ReadOnly;
32 using v8::String;
33 using v8::Value;
34
35 // Microseconds in a millisecond, as a float.
36 #define MICROS_PER_MILLIS 1e3
37
38 // https://w3c.github.io/hr-time/#dfn-time-origin
39 const uint64_t timeOrigin = PERFORMANCE_NOW();
40 // https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
41 const double timeOriginTimestamp = GetCurrentTimeInMicroseconds();
42 uint64_t performance_v8_start;
43
Mark(enum PerformanceMilestone milestone,uint64_t ts)44 void PerformanceState::Mark(enum PerformanceMilestone milestone,
45 uint64_t ts) {
46 this->milestones[milestone] = ts;
47 TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
48 TRACING_CATEGORY_NODE1(bootstrap),
49 GetPerformanceMilestoneName(milestone),
50 TRACE_EVENT_SCOPE_THREAD, ts / 1000);
51 }
52
53 // Initialize the performance entry object properties
InitObject(const PerformanceEntry & entry,Local<Object> obj)54 inline void InitObject(const PerformanceEntry& entry, Local<Object> obj) {
55 Environment* env = entry.env();
56 Isolate* isolate = env->isolate();
57 Local<Context> context = env->context();
58 PropertyAttribute attr =
59 static_cast<PropertyAttribute>(ReadOnly | DontDelete);
60 obj->DefineOwnProperty(context,
61 env->name_string(),
62 String::NewFromUtf8(isolate,
63 entry.name().c_str(),
64 NewStringType::kNormal)
65 .ToLocalChecked(),
66 attr)
67 .Check();
68 obj->DefineOwnProperty(context,
69 env->entry_type_string(),
70 String::NewFromUtf8(isolate,
71 entry.type().c_str(),
72 NewStringType::kNormal)
73 .ToLocalChecked(),
74 attr)
75 .Check();
76 obj->DefineOwnProperty(context,
77 env->start_time_string(),
78 Number::New(isolate, entry.startTime()),
79 attr).Check();
80 obj->DefineOwnProperty(context,
81 env->duration_string(),
82 Number::New(isolate, entry.duration()),
83 attr).Check();
84 }
85
86 // Create a new PerformanceEntry object
ToObject() const87 MaybeLocal<Object> PerformanceEntry::ToObject() const {
88 Local<Object> obj;
89 if (!env_->performance_entry_template()
90 ->NewInstance(env_->context())
91 .ToLocal(&obj)) {
92 return MaybeLocal<Object>();
93 }
94 InitObject(*this, obj);
95 return obj;
96 }
97
98 // Allow creating a PerformanceEntry object from JavaScript
New(const FunctionCallbackInfo<Value> & args)99 void PerformanceEntry::New(const FunctionCallbackInfo<Value>& args) {
100 Environment* env = Environment::GetCurrent(args);
101 Isolate* isolate = env->isolate();
102 Utf8Value name(isolate, args[0]);
103 Utf8Value type(isolate, args[1]);
104 uint64_t now = PERFORMANCE_NOW();
105 PerformanceEntry entry(env, *name, *type, now, now);
106 Local<Object> obj = args.This();
107 InitObject(entry, obj);
108 PerformanceEntry::Notify(env, entry.kind(), obj);
109 }
110
111 // Pass the PerformanceEntry object to the PerformanceObservers
Notify(Environment * env,PerformanceEntryType type,Local<Value> object)112 void PerformanceEntry::Notify(Environment* env,
113 PerformanceEntryType type,
114 Local<Value> object) {
115 Context::Scope scope(env->context());
116 AliasedUint32Array& observers = env->performance_state()->observers;
117 if (type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID &&
118 observers[type]) {
119 node::MakeCallback(env->isolate(),
120 object.As<Object>(),
121 env->performance_entry_callback(),
122 1, &object,
123 node::async_context{0, 0});
124 }
125 }
126
127 // Create a User Timing Mark
Mark(const FunctionCallbackInfo<Value> & args)128 void Mark(const FunctionCallbackInfo<Value>& args) {
129 Environment* env = Environment::GetCurrent(args);
130 HandleScope scope(env->isolate());
131 Utf8Value name(env->isolate(), args[0]);
132 uint64_t now = PERFORMANCE_NOW();
133 auto marks = env->performance_marks();
134 (*marks)[*name] = now;
135
136 TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(
137 TRACING_CATEGORY_NODE2(perf, usertiming),
138 *name, now / 1000);
139
140 PerformanceEntry entry(env, *name, "mark", now, now);
141 Local<Object> obj;
142 if (!entry.ToObject().ToLocal(&obj)) return;
143 PerformanceEntry::Notify(env, entry.kind(), obj);
144 args.GetReturnValue().Set(obj);
145 }
146
ClearMark(const FunctionCallbackInfo<Value> & args)147 void ClearMark(const FunctionCallbackInfo<Value>& args) {
148 Environment* env = Environment::GetCurrent(args);
149 auto marks = env->performance_marks();
150
151 if (args.Length() == 0) {
152 marks->clear();
153 } else {
154 Utf8Value name(env->isolate(), args[0]);
155 marks->erase(*name);
156 }
157 }
158
GetPerformanceMark(Environment * env,const std::string & name)159 inline uint64_t GetPerformanceMark(Environment* env, const std::string& name) {
160 auto marks = env->performance_marks();
161 auto res = marks->find(name);
162 return res != marks->end() ? res->second : 0;
163 }
164
165 // Create a User Timing Measure. A Measure is a PerformanceEntry that
166 // measures the duration between two distinct user timing marks
Measure(const FunctionCallbackInfo<Value> & args)167 void Measure(const FunctionCallbackInfo<Value>& args) {
168 Environment* env = Environment::GetCurrent(args);
169 HandleScope scope(env->isolate());
170 Utf8Value name(env->isolate(), args[0]);
171 Utf8Value startMark(env->isolate(), args[1]);
172
173 AliasedFloat64Array& milestones = env->performance_state()->milestones;
174
175 uint64_t startTimestamp = timeOrigin;
176 uint64_t start = GetPerformanceMark(env, *startMark);
177 if (start != 0) {
178 startTimestamp = start;
179 } else {
180 PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*startMark);
181 if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
182 startTimestamp = milestones[milestone];
183 }
184
185 uint64_t endTimestamp = 0;
186 if (args[2]->IsUndefined()) {
187 endTimestamp = PERFORMANCE_NOW();
188 } else {
189 Utf8Value endMark(env->isolate(), args[2]);
190 endTimestamp = GetPerformanceMark(env, *endMark);
191 if (endTimestamp == 0) {
192 PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*endMark);
193 if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
194 endTimestamp = milestones[milestone];
195 }
196 }
197
198 if (endTimestamp < startTimestamp)
199 endTimestamp = startTimestamp;
200
201 TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
202 TRACING_CATEGORY_NODE2(perf, usertiming),
203 *name, *name, startTimestamp / 1000);
204 TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
205 TRACING_CATEGORY_NODE2(perf, usertiming),
206 *name, *name, endTimestamp / 1000);
207
208 PerformanceEntry entry(env, *name, "measure", startTimestamp, endTimestamp);
209 Local<Object> obj;
210 if (!entry.ToObject().ToLocal(&obj)) return;
211 PerformanceEntry::Notify(env, entry.kind(), obj);
212 args.GetReturnValue().Set(obj);
213 }
214
215 // Allows specific Node.js lifecycle milestones to be set from JavaScript
MarkMilestone(const FunctionCallbackInfo<Value> & args)216 void MarkMilestone(const FunctionCallbackInfo<Value>& args) {
217 Environment* env = Environment::GetCurrent(args);
218 Local<Context> context = env->context();
219 PerformanceMilestone milestone =
220 static_cast<PerformanceMilestone>(
221 args[0]->Int32Value(context).ToChecked());
222 if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
223 env->performance_state()->Mark(milestone);
224 }
225
226
SetupPerformanceObservers(const FunctionCallbackInfo<Value> & args)227 void SetupPerformanceObservers(const FunctionCallbackInfo<Value>& args) {
228 Environment* env = Environment::GetCurrent(args);
229 CHECK(args[0]->IsFunction());
230 env->set_performance_entry_callback(args[0].As<Function>());
231 }
232
233 // Creates a GC Performance Entry and passes it to observers
PerformanceGCCallback(Environment * env,std::unique_ptr<GCPerformanceEntry> entry)234 void PerformanceGCCallback(Environment* env,
235 std::unique_ptr<GCPerformanceEntry> entry) {
236 HandleScope scope(env->isolate());
237 Local<Context> context = env->context();
238
239 AliasedUint32Array& observers = env->performance_state()->observers;
240 if (observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) {
241 Local<Object> obj;
242 if (!entry->ToObject().ToLocal(&obj)) return;
243 PropertyAttribute attr =
244 static_cast<PropertyAttribute>(ReadOnly | DontDelete);
245 obj->DefineOwnProperty(context,
246 env->kind_string(),
247 Integer::New(env->isolate(), entry->gckind()),
248 attr).Check();
249 obj->DefineOwnProperty(context,
250 env->flags_string(),
251 Integer::New(env->isolate(), entry->gcflags()),
252 attr).Check();
253 PerformanceEntry::Notify(env, entry->kind(), obj);
254 }
255 }
256
257 // Marks the start of a GC cycle
MarkGarbageCollectionStart(Isolate * isolate,GCType type,GCCallbackFlags flags,void * data)258 void MarkGarbageCollectionStart(Isolate* isolate,
259 GCType type,
260 GCCallbackFlags flags,
261 void* data) {
262 Environment* env = static_cast<Environment*>(data);
263 env->performance_state()->performance_last_gc_start_mark = PERFORMANCE_NOW();
264 }
265
266 // Marks the end of a GC cycle
MarkGarbageCollectionEnd(Isolate * isolate,GCType type,GCCallbackFlags flags,void * data)267 void MarkGarbageCollectionEnd(Isolate* isolate,
268 GCType type,
269 GCCallbackFlags flags,
270 void* data) {
271 Environment* env = static_cast<Environment*>(data);
272 PerformanceState* state = env->performance_state();
273 // If no one is listening to gc performance entries, do not create them.
274 if (!state->observers[NODE_PERFORMANCE_ENTRY_TYPE_GC])
275 return;
276 auto entry = std::make_unique<GCPerformanceEntry>(
277 env,
278 static_cast<PerformanceGCKind>(type),
279 static_cast<PerformanceGCFlags>(flags),
280 state->performance_last_gc_start_mark,
281 PERFORMANCE_NOW());
282 env->SetImmediate([entry = std::move(entry)](Environment* env) mutable {
283 PerformanceGCCallback(env, std::move(entry));
284 }, CallbackFlags::kUnrefed);
285 }
286
GarbageCollectionCleanupHook(void * data)287 void GarbageCollectionCleanupHook(void* data) {
288 Environment* env = static_cast<Environment*>(data);
289 env->isolate()->RemoveGCPrologueCallback(MarkGarbageCollectionStart, data);
290 env->isolate()->RemoveGCEpilogueCallback(MarkGarbageCollectionEnd, data);
291 }
292
InstallGarbageCollectionTracking(const FunctionCallbackInfo<Value> & args)293 static void InstallGarbageCollectionTracking(
294 const FunctionCallbackInfo<Value>& args) {
295 Environment* env = Environment::GetCurrent(args);
296
297 env->isolate()->AddGCPrologueCallback(MarkGarbageCollectionStart,
298 static_cast<void*>(env));
299 env->isolate()->AddGCEpilogueCallback(MarkGarbageCollectionEnd,
300 static_cast<void*>(env));
301 env->AddCleanupHook(GarbageCollectionCleanupHook, env);
302 }
303
RemoveGarbageCollectionTracking(const FunctionCallbackInfo<Value> & args)304 static void RemoveGarbageCollectionTracking(
305 const FunctionCallbackInfo<Value> &args) {
306 Environment* env = Environment::GetCurrent(args);
307
308 env->RemoveCleanupHook(GarbageCollectionCleanupHook, env);
309 GarbageCollectionCleanupHook(env);
310 }
311
312 // Gets the name of a function
GetName(Local<Function> fn)313 inline Local<Value> GetName(Local<Function> fn) {
314 Local<Value> val = fn->GetDebugName();
315 if (val.IsEmpty() || val->IsUndefined()) {
316 Local<Value> boundFunction = fn->GetBoundFunction();
317 if (!boundFunction.IsEmpty() && !boundFunction->IsUndefined()) {
318 val = GetName(boundFunction.As<Function>());
319 }
320 }
321 return val;
322 }
323
324 // Executes a wrapped Function and captures timing information, causing a
325 // Function PerformanceEntry to be emitted to PerformanceObservers after
326 // execution.
TimerFunctionCall(const FunctionCallbackInfo<Value> & args)327 void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
328 Isolate* isolate = args.GetIsolate();
329 Local<Context> context = isolate->GetCurrentContext();
330 Environment* env = Environment::GetCurrent(context);
331 CHECK_NOT_NULL(env);
332 Local<Function> fn = args.Data().As<Function>();
333 size_t count = args.Length();
334 size_t idx;
335 SlicedArguments call_args(args);
336 Utf8Value name(isolate, GetName(fn));
337 bool is_construct_call = args.IsConstructCall();
338
339 uint64_t start = PERFORMANCE_NOW();
340 TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
341 TRACING_CATEGORY_NODE2(perf, timerify),
342 *name, *name, start / 1000);
343 v8::MaybeLocal<Value> ret;
344
345 if (is_construct_call) {
346 ret = fn->NewInstance(context, call_args.length(), call_args.out())
347 .FromMaybe(Local<Object>());
348 } else {
349 ret = fn->Call(context, args.This(), call_args.length(), call_args.out());
350 }
351
352 uint64_t end = PERFORMANCE_NOW();
353 TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
354 TRACING_CATEGORY_NODE2(perf, timerify),
355 *name, *name, end / 1000);
356
357 if (ret.IsEmpty())
358 return;
359 args.GetReturnValue().Set(ret.ToLocalChecked());
360
361 AliasedUint32Array& observers = env->performance_state()->observers;
362 if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION])
363 return;
364
365 PerformanceEntry entry(env, *name, "function", start, end);
366 Local<Object> obj;
367 if (!entry.ToObject().ToLocal(&obj)) return;
368 for (idx = 0; idx < count; idx++)
369 obj->Set(context, idx, args[idx]).Check();
370 PerformanceEntry::Notify(env, entry.kind(), obj);
371 }
372
373 // Wraps a Function in a TimerFunctionCall
Timerify(const FunctionCallbackInfo<Value> & args)374 void Timerify(const FunctionCallbackInfo<Value>& args) {
375 Environment* env = Environment::GetCurrent(args);
376 Local<Context> context = env->context();
377 CHECK(args[0]->IsFunction());
378 CHECK(args[1]->IsNumber());
379 Local<Function> fn = args[0].As<Function>();
380 int length = args[1]->IntegerValue(context).ToChecked();
381 Local<Function> wrap =
382 Function::New(context, TimerFunctionCall, fn, length).ToLocalChecked();
383 args.GetReturnValue().Set(wrap);
384 }
385
386 // Notify a custom PerformanceEntry to observers
Notify(const FunctionCallbackInfo<Value> & args)387 void Notify(const FunctionCallbackInfo<Value>& args) {
388 Environment* env = Environment::GetCurrent(args);
389 Utf8Value type(env->isolate(), args[0]);
390 Local<Value> entry = args[1];
391 PerformanceEntryType entry_type = ToPerformanceEntryTypeEnum(*type);
392 AliasedUint32Array& observers = env->performance_state()->observers;
393 if (entry_type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID &&
394 observers[entry_type]) {
395 USE(env->performance_entry_callback()->
396 Call(env->context(), Undefined(env->isolate()), 1, &entry));
397 }
398 }
399
400 // Return idle time of the event loop
LoopIdleTime(const FunctionCallbackInfo<Value> & args)401 void LoopIdleTime(const FunctionCallbackInfo<Value>& args) {
402 Environment* env = Environment::GetCurrent(args);
403 uint64_t idle_time = uv_metrics_idle_time(env->event_loop());
404 args.GetReturnValue().Set(1.0 * idle_time / 1e6);
405 }
406
407
408 // Event Loop Timing Histogram
409 namespace {
ELDHistogramMin(const FunctionCallbackInfo<Value> & args)410 static void ELDHistogramMin(const FunctionCallbackInfo<Value>& args) {
411 ELDHistogram* histogram;
412 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
413 double value = static_cast<double>(histogram->Min());
414 args.GetReturnValue().Set(value);
415 }
416
ELDHistogramMax(const FunctionCallbackInfo<Value> & args)417 static void ELDHistogramMax(const FunctionCallbackInfo<Value>& args) {
418 ELDHistogram* histogram;
419 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
420 double value = static_cast<double>(histogram->Max());
421 args.GetReturnValue().Set(value);
422 }
423
ELDHistogramMean(const FunctionCallbackInfo<Value> & args)424 static void ELDHistogramMean(const FunctionCallbackInfo<Value>& args) {
425 ELDHistogram* histogram;
426 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
427 args.GetReturnValue().Set(histogram->Mean());
428 }
429
ELDHistogramExceeds(const FunctionCallbackInfo<Value> & args)430 static void ELDHistogramExceeds(const FunctionCallbackInfo<Value>& args) {
431 ELDHistogram* histogram;
432 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
433 double value = static_cast<double>(histogram->Exceeds());
434 args.GetReturnValue().Set(value);
435 }
436
ELDHistogramStddev(const FunctionCallbackInfo<Value> & args)437 static void ELDHistogramStddev(const FunctionCallbackInfo<Value>& args) {
438 ELDHistogram* histogram;
439 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
440 args.GetReturnValue().Set(histogram->Stddev());
441 }
442
ELDHistogramPercentile(const FunctionCallbackInfo<Value> & args)443 static void ELDHistogramPercentile(const FunctionCallbackInfo<Value>& args) {
444 ELDHistogram* histogram;
445 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
446 CHECK(args[0]->IsNumber());
447 double percentile = args[0].As<Number>()->Value();
448 args.GetReturnValue().Set(histogram->Percentile(percentile));
449 }
450
ELDHistogramPercentiles(const FunctionCallbackInfo<Value> & args)451 static void ELDHistogramPercentiles(const FunctionCallbackInfo<Value>& args) {
452 Environment* env = Environment::GetCurrent(args);
453 ELDHistogram* histogram;
454 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
455 CHECK(args[0]->IsMap());
456 Local<Map> map = args[0].As<Map>();
457 histogram->Percentiles([&](double key, double value) {
458 map->Set(env->context(),
459 Number::New(env->isolate(), key),
460 Number::New(env->isolate(), value)).IsEmpty();
461 });
462 }
463
ELDHistogramEnable(const FunctionCallbackInfo<Value> & args)464 static void ELDHistogramEnable(const FunctionCallbackInfo<Value>& args) {
465 ELDHistogram* histogram;
466 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
467 args.GetReturnValue().Set(histogram->Enable());
468 }
469
ELDHistogramDisable(const FunctionCallbackInfo<Value> & args)470 static void ELDHistogramDisable(const FunctionCallbackInfo<Value>& args) {
471 ELDHistogram* histogram;
472 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
473 args.GetReturnValue().Set(histogram->Disable());
474 }
475
ELDHistogramReset(const FunctionCallbackInfo<Value> & args)476 static void ELDHistogramReset(const FunctionCallbackInfo<Value>& args) {
477 ELDHistogram* histogram;
478 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
479 histogram->ResetState();
480 }
481
ELDHistogramNew(const FunctionCallbackInfo<Value> & args)482 static void ELDHistogramNew(const FunctionCallbackInfo<Value>& args) {
483 Environment* env = Environment::GetCurrent(args);
484 CHECK(args.IsConstructCall());
485 int32_t resolution = args[0]->IntegerValue(env->context()).FromJust();
486 CHECK_GT(resolution, 0);
487 new ELDHistogram(env, args.This(), resolution);
488 }
489 } // namespace
490
ELDHistogram(Environment * env,Local<Object> wrap,int32_t resolution)491 ELDHistogram::ELDHistogram(
492 Environment* env,
493 Local<Object> wrap,
494 int32_t resolution) : HandleWrap(env,
495 wrap,
496 reinterpret_cast<uv_handle_t*>(&timer_),
497 AsyncWrap::PROVIDER_ELDHISTOGRAM),
498 Histogram(1, 3.6e12),
499 resolution_(resolution) {
500 MakeWeak();
501 uv_timer_init(env->event_loop(), &timer_);
502 }
503
DelayIntervalCallback(uv_timer_t * req)504 void ELDHistogram::DelayIntervalCallback(uv_timer_t* req) {
505 ELDHistogram* histogram = ContainerOf(&ELDHistogram::timer_, req);
506 histogram->RecordDelta();
507 TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
508 "min", histogram->Min());
509 TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
510 "max", histogram->Max());
511 TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
512 "mean", histogram->Mean());
513 TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
514 "stddev", histogram->Stddev());
515 }
516
RecordDelta()517 bool ELDHistogram::RecordDelta() {
518 uint64_t time = uv_hrtime();
519 bool ret = true;
520 if (prev_ > 0) {
521 int64_t delta = time - prev_;
522 if (delta > 0) {
523 ret = Record(delta);
524 TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
525 "delay", delta);
526 if (!ret) {
527 if (exceeds_ < 0xFFFFFFFF)
528 exceeds_++;
529 ProcessEmitWarning(
530 env(),
531 "Event loop delay exceeded 1 hour: %" PRId64 " nanoseconds",
532 delta);
533 }
534 }
535 }
536 prev_ = time;
537 return ret;
538 }
539
Enable()540 bool ELDHistogram::Enable() {
541 if (enabled_ || IsHandleClosing()) return false;
542 enabled_ = true;
543 prev_ = 0;
544 uv_timer_start(&timer_,
545 DelayIntervalCallback,
546 resolution_,
547 resolution_);
548 uv_unref(reinterpret_cast<uv_handle_t*>(&timer_));
549 return true;
550 }
551
Disable()552 bool ELDHistogram::Disable() {
553 if (!enabled_ || IsHandleClosing()) return false;
554 enabled_ = false;
555 uv_timer_stop(&timer_);
556 return true;
557 }
558
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)559 void Initialize(Local<Object> target,
560 Local<Value> unused,
561 Local<Context> context,
562 void* priv) {
563 Environment* env = Environment::GetCurrent(context);
564 Isolate* isolate = env->isolate();
565 PerformanceState* state = env->performance_state();
566
567 target->Set(context,
568 FIXED_ONE_BYTE_STRING(isolate, "observerCounts"),
569 state->observers.GetJSArray()).Check();
570 target->Set(context,
571 FIXED_ONE_BYTE_STRING(isolate, "milestones"),
572 state->milestones.GetJSArray()).Check();
573
574 Local<String> performanceEntryString =
575 FIXED_ONE_BYTE_STRING(isolate, "PerformanceEntry");
576
577 Local<FunctionTemplate> pe = FunctionTemplate::New(isolate);
578 pe->SetClassName(performanceEntryString);
579 Local<Function> fn = pe->GetFunction(context).ToLocalChecked();
580 target->Set(context, performanceEntryString, fn).Check();
581 env->set_performance_entry_template(fn);
582
583 env->SetMethod(target, "clearMark", ClearMark);
584 env->SetMethod(target, "mark", Mark);
585 env->SetMethod(target, "measure", Measure);
586 env->SetMethod(target, "markMilestone", MarkMilestone);
587 env->SetMethod(target, "setupObservers", SetupPerformanceObservers);
588 env->SetMethod(target, "timerify", Timerify);
589 env->SetMethod(target,
590 "installGarbageCollectionTracking",
591 InstallGarbageCollectionTracking);
592 env->SetMethod(target,
593 "removeGarbageCollectionTracking",
594 RemoveGarbageCollectionTracking);
595 env->SetMethod(target, "notify", Notify);
596 env->SetMethod(target, "loopIdleTime", LoopIdleTime);
597
598 Local<Object> constants = Object::New(isolate);
599
600 NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MAJOR);
601 NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MINOR);
602 NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_INCREMENTAL);
603 NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_WEAKCB);
604
605 NODE_DEFINE_CONSTANT(
606 constants, NODE_PERFORMANCE_GC_FLAGS_NO);
607 NODE_DEFINE_CONSTANT(
608 constants, NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED);
609 NODE_DEFINE_CONSTANT(
610 constants, NODE_PERFORMANCE_GC_FLAGS_FORCED);
611 NODE_DEFINE_CONSTANT(
612 constants, NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING);
613 NODE_DEFINE_CONSTANT(
614 constants, NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE);
615 NODE_DEFINE_CONSTANT(
616 constants, NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY);
617 NODE_DEFINE_CONSTANT(
618 constants, NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE);
619
620 #define V(name, _) \
621 NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_ENTRY_TYPE_##name);
622 NODE_PERFORMANCE_ENTRY_TYPES(V)
623 #undef V
624
625 #define V(name, _) \
626 NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_MILESTONE_##name);
627 NODE_PERFORMANCE_MILESTONES(V)
628 #undef V
629
630 PropertyAttribute attr =
631 static_cast<PropertyAttribute>(ReadOnly | DontDelete);
632
633 target->DefineOwnProperty(context,
634 FIXED_ONE_BYTE_STRING(isolate, "timeOrigin"),
635 Number::New(isolate, timeOrigin / 1e6),
636 attr).ToChecked();
637
638 target->DefineOwnProperty(
639 context,
640 FIXED_ONE_BYTE_STRING(isolate, "timeOriginTimestamp"),
641 Number::New(isolate, timeOriginTimestamp / MICROS_PER_MILLIS),
642 attr).ToChecked();
643
644 target->DefineOwnProperty(context,
645 env->constants_string(),
646 constants,
647 attr).ToChecked();
648
649 Local<String> eldh_classname = FIXED_ONE_BYTE_STRING(isolate, "ELDHistogram");
650 Local<FunctionTemplate> eldh =
651 env->NewFunctionTemplate(ELDHistogramNew);
652 eldh->SetClassName(eldh_classname);
653 eldh->InstanceTemplate()->SetInternalFieldCount(
654 ELDHistogram::kInternalFieldCount);
655 eldh->Inherit(BaseObject::GetConstructorTemplate(env));
656 env->SetProtoMethod(eldh, "exceeds", ELDHistogramExceeds);
657 env->SetProtoMethod(eldh, "min", ELDHistogramMin);
658 env->SetProtoMethod(eldh, "max", ELDHistogramMax);
659 env->SetProtoMethod(eldh, "mean", ELDHistogramMean);
660 env->SetProtoMethod(eldh, "stddev", ELDHistogramStddev);
661 env->SetProtoMethod(eldh, "percentile", ELDHistogramPercentile);
662 env->SetProtoMethod(eldh, "percentiles", ELDHistogramPercentiles);
663 env->SetProtoMethod(eldh, "enable", ELDHistogramEnable);
664 env->SetProtoMethod(eldh, "disable", ELDHistogramDisable);
665 env->SetProtoMethod(eldh, "reset", ELDHistogramReset);
666 target->Set(context, eldh_classname,
667 eldh->GetFunction(env->context()).ToLocalChecked()).Check();
668 }
669
670 } // namespace performance
671 } // namespace node
672
673 NODE_MODULE_CONTEXT_AWARE_INTERNAL(performance, node::performance::Initialize)
674