GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_perf.cc Lines: 341 374 91.2 %
Date: 2020-06-24 22:13:30 Branches: 122 190 64.2 %

Line Branch Exec Source
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
4399
const uint64_t timeOrigin = PERFORMANCE_NOW();
40
// https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
41
4399
const double timeOriginTimestamp = GetCurrentTimeInMicroseconds();
42
uint64_t performance_v8_start;
43
44
27333
void PerformanceState::Mark(enum PerformanceMilestone milestone,
45
                             uint64_t ts) {
46
27333
  this->milestones[milestone] = ts;
47

54668
  TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
48
      TRACING_CATEGORY_NODE1(bootstrap),
49
      GetPerformanceMilestoneName(milestone),
50
      TRACE_EVENT_SCOPE_THREAD, ts / 1000);
51
27334
}
52
53
// Initialize the performance entry object properties
54
42
inline void InitObject(const PerformanceEntry& entry, Local<Object> obj) {
55
42
  Environment* env = entry.env();
56
42
  Isolate* isolate = env->isolate();
57
42
  Local<Context> context = env->context();
58
  PropertyAttribute attr =
59
42
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
60
84
  obj->DefineOwnProperty(context,
61
                         env->name_string(),
62
84
                         String::NewFromUtf8(isolate,
63
42
                                             entry.name().c_str(),
64
42
                                             NewStringType::kNormal)
65
                             .ToLocalChecked(),
66
126
                         attr)
67
      .Check();
68
84
  obj->DefineOwnProperty(context,
69
                         env->entry_type_string(),
70
84
                         String::NewFromUtf8(isolate,
71
42
                                             entry.type().c_str(),
72
42
                                             NewStringType::kNormal)
73
                             .ToLocalChecked(),
74
126
                         attr)
75
      .Check();
76
84
  obj->DefineOwnProperty(context,
77
                         env->start_time_string(),
78
                         Number::New(isolate, entry.startTime()),
79
168
                         attr).Check();
80
84
  obj->DefineOwnProperty(context,
81
                         env->duration_string(),
82
                         Number::New(isolate, entry.duration()),
83
168
                         attr).Check();
84
42
}
85
86
// Create a new PerformanceEntry object
87
42
MaybeLocal<Object> PerformanceEntry::ToObject() const {
88
  Local<Object> obj;
89
126
  if (!env_->performance_entry_template()
90
126
           ->NewInstance(env_->context())
91
42
           .ToLocal(&obj)) {
92
    return MaybeLocal<Object>();
93
  }
94
42
  InitObject(*this, obj);
95
42
  return obj;
96
}
97
98
// Allow creating a PerformanceEntry object from JavaScript
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
112
42
void PerformanceEntry::Notify(Environment* env,
113
                              PerformanceEntryType type,
114
                              Local<Value> object) {
115
42
  Context::Scope scope(env->context());
116
42
  AliasedUint32Array& observers = env->performance_state()->observers;
117

126
  if (type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID &&
118
84
      observers[type]) {
119
    node::MakeCallback(env->isolate(),
120
                       object.As<Object>(),
121
                       env->performance_entry_callback(),
122
                       1, &object,
123
32
                       node::async_context{0, 0});
124
  }
125
42
}
126
127
// Create a User Timing Mark
128
22
void Mark(const FunctionCallbackInfo<Value>& args) {
129
22
  Environment* env = Environment::GetCurrent(args);
130
44
  HandleScope scope(env->isolate());
131
44
  Utf8Value name(env->isolate(), args[0]);
132
22
  uint64_t now = PERFORMANCE_NOW();
133
22
  auto marks = env->performance_marks();
134
22
  (*marks)[*name] = now;
135
136

44
  TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(
137
      TRACING_CATEGORY_NODE2(perf, usertiming),
138
      *name, now / 1000);
139
140
44
  PerformanceEntry entry(env, *name, "mark", now, now);
141
  Local<Object> obj;
142
44
  if (!entry.ToObject().ToLocal(&obj)) return;
143
22
  PerformanceEntry::Notify(env, entry.kind(), obj);
144
44
  args.GetReturnValue().Set(obj);
145
}
146
147
3
void ClearMark(const FunctionCallbackInfo<Value>& args) {
148
3
  Environment* env = Environment::GetCurrent(args);
149
3
  auto marks = env->performance_marks();
150
151
3
  if (args.Length() == 0) {
152
2
    marks->clear();
153
  } else {
154
2
    Utf8Value name(env->isolate(), args[0]);
155
1
    marks->erase(*name);
156
  }
157
3
}
158
159
24
inline uint64_t GetPerformanceMark(Environment* env, const std::string& name) {
160
24
  auto marks = env->performance_marks();
161
24
  auto res = marks->find(name);
162
24
  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
167
13
void Measure(const FunctionCallbackInfo<Value>& args) {
168
13
  Environment* env = Environment::GetCurrent(args);
169
26
  HandleScope scope(env->isolate());
170
26
  Utf8Value name(env->isolate(), args[0]);
171
26
  Utf8Value startMark(env->isolate(), args[1]);
172
173
13
  AliasedFloat64Array& milestones = env->performance_state()->milestones;
174
175
13
  uint64_t startTimestamp = timeOrigin;
176
13
  uint64_t start = GetPerformanceMark(env, *startMark);
177
13
  if (start != 0) {
178
7
    startTimestamp = start;
179
  } else {
180
6
    PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*startMark);
181
6
    if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
182
      startTimestamp = milestones[milestone];
183
  }
184
185
13
  uint64_t endTimestamp = 0;
186
39
  if (args[2]->IsUndefined()) {
187
2
    endTimestamp = PERFORMANCE_NOW();
188
  } else {
189
22
    Utf8Value endMark(env->isolate(), args[2]);
190
11
    endTimestamp = GetPerformanceMark(env, *endMark);
191
11
    if (endTimestamp == 0) {
192
      PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*endMark);
193
      if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
194
        endTimestamp = milestones[milestone];
195
    }
196
  }
197
198
13
  if (endTimestamp < startTimestamp)
199
    endTimestamp = startTimestamp;
200
201

26
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
202
      TRACING_CATEGORY_NODE2(perf, usertiming),
203
      *name, *name, startTimestamp / 1000);
204

26
  TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
205
      TRACING_CATEGORY_NODE2(perf, usertiming),
206
      *name, *name, endTimestamp / 1000);
207
208
26
  PerformanceEntry entry(env, *name, "measure", startTimestamp, endTimestamp);
209
  Local<Object> obj;
210
26
  if (!entry.ToObject().ToLocal(&obj)) return;
211
13
  PerformanceEntry::Notify(env, entry.kind(), obj);
212
26
  args.GetReturnValue().Set(obj);
213
}
214
215
// Allows specific Node.js lifecycle milestones to be set from JavaScript
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
227
23
void SetupPerformanceObservers(const FunctionCallbackInfo<Value>& args) {
228
23
  Environment* env = Environment::GetCurrent(args);
229
46
  CHECK(args[0]->IsFunction());
230
46
  env->set_performance_entry_callback(args[0].As<Function>());
231
23
}
232
233
// Creates a GC Performance Entry and passes it to observers
234
1
void PerformanceGCCallback(Environment* env,
235
                           std::unique_ptr<GCPerformanceEntry> entry) {
236
2
  HandleScope scope(env->isolate());
237
1
  Local<Context> context = env->context();
238
239
1
  AliasedUint32Array& observers = env->performance_state()->observers;
240
1
  if (observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) {
241
    Local<Object> obj;
242
2
    if (!entry->ToObject().ToLocal(&obj)) return;
243
    PropertyAttribute attr =
244
1
        static_cast<PropertyAttribute>(ReadOnly | DontDelete);
245
2
    obj->DefineOwnProperty(context,
246
                           env->kind_string(),
247
1
                           Integer::New(env->isolate(), entry->gckind()),
248
4
                           attr).Check();
249
2
    obj->DefineOwnProperty(context,
250
                           env->flags_string(),
251
1
                           Integer::New(env->isolate(), entry->gcflags()),
252
4
                           attr).Check();
253
1
    PerformanceEntry::Notify(env, entry->kind(), obj);
254
  }
255
}
256
257
// Marks the start of a GC cycle
258
1
void MarkGarbageCollectionStart(Isolate* isolate,
259
                                GCType type,
260
                                GCCallbackFlags flags,
261
                                void* data) {
262
1
  Environment* env = static_cast<Environment*>(data);
263
1
  env->performance_state()->performance_last_gc_start_mark = PERFORMANCE_NOW();
264
1
}
265
266
// Marks the end of a GC cycle
267
1
void MarkGarbageCollectionEnd(Isolate* isolate,
268
                              GCType type,
269
                              GCCallbackFlags flags,
270
                              void* data) {
271
1
  Environment* env = static_cast<Environment*>(data);
272
1
  PerformanceState* state = env->performance_state();
273
  // If no one is listening to gc performance entries, do not create them.
274
1
  if (!state->observers[NODE_PERFORMANCE_ENTRY_TYPE_GC])
275
    return;
276
  auto entry = std::make_unique<GCPerformanceEntry>(
277
      env,
278
2
      static_cast<PerformanceGCKind>(type),
279
2
      static_cast<PerformanceGCFlags>(flags),
280
      state->performance_last_gc_start_mark,
281
4
      PERFORMANCE_NOW());
282
6
  env->SetImmediate([entry = std::move(entry)](Environment* env) mutable {
283
1
    PerformanceGCCallback(env, std::move(entry));
284
2
  }, CallbackFlags::kUnrefed);
285
}
286
287
1
void GarbageCollectionCleanupHook(void* data) {
288
1
  Environment* env = static_cast<Environment*>(data);
289
1
  env->isolate()->RemoveGCPrologueCallback(MarkGarbageCollectionStart, data);
290
1
  env->isolate()->RemoveGCEpilogueCallback(MarkGarbageCollectionEnd, data);
291
1
}
292
293
1
static void InstallGarbageCollectionTracking(
294
    const FunctionCallbackInfo<Value>& args) {
295
1
  Environment* env = Environment::GetCurrent(args);
296
297
1
  env->isolate()->AddGCPrologueCallback(MarkGarbageCollectionStart,
298
1
                                        static_cast<void*>(env));
299
1
  env->isolate()->AddGCEpilogueCallback(MarkGarbageCollectionEnd,
300
1
                                        static_cast<void*>(env));
301
1
  env->AddCleanupHook(GarbageCollectionCleanupHook, env);
302
1
}
303
304
1
static void RemoveGarbageCollectionTracking(
305
  const FunctionCallbackInfo<Value> &args) {
306
1
  Environment* env = Environment::GetCurrent(args);
307
308
1
  env->RemoveCleanupHook(GarbageCollectionCleanupHook, env);
309
1
  GarbageCollectionCleanupHook(env);
310
1
}
311
312
// Gets the name of a function
313
7
inline Local<Value> GetName(Local<Function> fn) {
314
7
  Local<Value> val = fn->GetDebugName();
315

21
  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
7
  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.
327
7
void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
328
7
  Isolate* isolate = args.GetIsolate();
329
7
  Local<Context> context = isolate->GetCurrentContext();
330
7
  Environment* env = Environment::GetCurrent(context);
331
7
  CHECK_NOT_NULL(env);
332
14
  Local<Function> fn = args.Data().As<Function>();
333
7
  size_t count = args.Length();
334
  size_t idx;
335
9
  SlicedArguments call_args(args);
336
9
  Utf8Value name(isolate, GetName(fn));
337
7
  bool is_construct_call = args.IsConstructCall();
338
339
7
  uint64_t start = PERFORMANCE_NOW();
340

14
  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
7
  if (is_construct_call) {
346
4
    ret = fn->NewInstance(context, call_args.length(), call_args.out())
347
2
        .FromMaybe(Local<Object>());
348
  } else {
349
12
    ret = fn->Call(context, args.This(), call_args.length(), call_args.out());
350
  }
351
352
7
  uint64_t end = PERFORMANCE_NOW();
353

14
  TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
354
      TRACING_CATEGORY_NODE2(perf, timerify),
355
      *name, *name, end / 1000);
356
357
7
  if (ret.IsEmpty())
358
1
    return;
359
12
  args.GetReturnValue().Set(ret.ToLocalChecked());
360
361
6
  AliasedUint32Array& observers = env->performance_state()->observers;
362
6
  if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION])
363
4
    return;
364
365
4
  PerformanceEntry entry(env, *name, "function", start, end);
366
  Local<Object> obj;
367
4
  if (!entry.ToObject().ToLocal(&obj)) return;
368
4
  for (idx = 0; idx < count; idx++)
369
8
    obj->Set(context, idx, args[idx]).Check();
370
2
  PerformanceEntry::Notify(env, entry.kind(), obj);
371
}
372
373
// Wraps a Function in a TimerFunctionCall
374
8
void Timerify(const FunctionCallbackInfo<Value>& args) {
375
8
  Environment* env = Environment::GetCurrent(args);
376
8
  Local<Context> context = env->context();
377
16
  CHECK(args[0]->IsFunction());
378
16
  CHECK(args[1]->IsNumber());
379
16
  Local<Function> fn = args[0].As<Function>();
380
24
  int length = args[1]->IntegerValue(context).ToChecked();
381
  Local<Function> wrap =
382
16
      Function::New(context, TimerFunctionCall, fn, length).ToLocalChecked();
383
16
  args.GetReturnValue().Set(wrap);
384
8
}
385
386
// Notify a custom PerformanceEntry to observers
387
2
void Notify(const FunctionCallbackInfo<Value>& args) {
388
2
  Environment* env = Environment::GetCurrent(args);
389
4
  Utf8Value type(env->isolate(), args[0]);
390
2
  Local<Value> entry = args[1];
391
2
  PerformanceEntryType entry_type = ToPerformanceEntryTypeEnum(*type);
392
2
  AliasedUint32Array& observers = env->performance_state()->observers;
393

6
  if (entry_type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID &&
394
4
      observers[entry_type]) {
395
4
    USE(env->performance_entry_callback()->
396
8
      Call(env->context(), Undefined(env->isolate()), 1, &entry));
397
  }
398
2
}
399
400
401
// Event Loop Timing Histogram
402
namespace {
403
2
static void ELDHistogramMin(const FunctionCallbackInfo<Value>& args) {
404
  ELDHistogram* histogram;
405
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
406
2
  double value = static_cast<double>(histogram->Min());
407
4
  args.GetReturnValue().Set(value);
408
}
409
410
2
static void ELDHistogramMax(const FunctionCallbackInfo<Value>& args) {
411
  ELDHistogram* histogram;
412
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
413
2
  double value = static_cast<double>(histogram->Max());
414
4
  args.GetReturnValue().Set(value);
415
}
416
417
2
static void ELDHistogramMean(const FunctionCallbackInfo<Value>& args) {
418
  ELDHistogram* histogram;
419
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
420
6
  args.GetReturnValue().Set(histogram->Mean());
421
}
422
423
static void ELDHistogramExceeds(const FunctionCallbackInfo<Value>& args) {
424
  ELDHistogram* histogram;
425
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
426
  double value = static_cast<double>(histogram->Exceeds());
427
  args.GetReturnValue().Set(value);
428
}
429
430
2
static void ELDHistogramStddev(const FunctionCallbackInfo<Value>& args) {
431
  ELDHistogram* histogram;
432
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
433
6
  args.GetReturnValue().Set(histogram->Stddev());
434
}
435
436
991
static void ELDHistogramPercentile(const FunctionCallbackInfo<Value>& args) {
437
  ELDHistogram* histogram;
438
991
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
439
1982
  CHECK(args[0]->IsNumber());
440
2973
  double percentile = args[0].As<Number>()->Value();
441
2973
  args.GetReturnValue().Set(histogram->Percentile(percentile));
442
}
443
444
2
static void ELDHistogramPercentiles(const FunctionCallbackInfo<Value>& args) {
445
2
  Environment* env = Environment::GetCurrent(args);
446
  ELDHistogram* histogram;
447
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
448
4
  CHECK(args[0]->IsMap());
449
4
  Local<Map> map = args[0].As<Map>();
450
18
  histogram->Percentiles([&](double key, double value) {
451
84
    map->Set(env->context(),
452
             Number::New(env->isolate(), key),
453
70
             Number::New(env->isolate(), value)).IsEmpty();
454
16
  });
455
}
456
457
3
static void ELDHistogramEnable(const FunctionCallbackInfo<Value>& args) {
458
  ELDHistogram* histogram;
459
3
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
460
9
  args.GetReturnValue().Set(histogram->Enable());
461
}
462
463
3
static void ELDHistogramDisable(const FunctionCallbackInfo<Value>& args) {
464
  ELDHistogram* histogram;
465
3
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
466
9
  args.GetReturnValue().Set(histogram->Disable());
467
}
468
469
2
static void ELDHistogramReset(const FunctionCallbackInfo<Value>& args) {
470
  ELDHistogram* histogram;
471
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
472
2
  histogram->ResetState();
473
}
474
475
2
static void ELDHistogramNew(const FunctionCallbackInfo<Value>& args) {
476
2
  Environment* env = Environment::GetCurrent(args);
477
2
  CHECK(args.IsConstructCall());
478
8
  int32_t resolution = args[0]->IntegerValue(env->context()).FromJust();
479
2
  CHECK_GT(resolution, 0);
480
2
  new ELDHistogram(env, args.This(), resolution);
481
2
}
482
}  // namespace
483
484
2
ELDHistogram::ELDHistogram(
485
    Environment* env,
486
    Local<Object> wrap,
487
2
    int32_t resolution) : HandleWrap(env,
488
                                     wrap,
489
2
                                     reinterpret_cast<uv_handle_t*>(&timer_),
490
                                     AsyncWrap::PROVIDER_ELDHISTOGRAM),
491
                          Histogram(1, 3.6e12),
492
2
                          resolution_(resolution) {
493
2
  MakeWeak();
494
2
  uv_timer_init(env->event_loop(), &timer_);
495
2
}
496
497
1852
void ELDHistogram::DelayIntervalCallback(uv_timer_t* req) {
498
1852
  ELDHistogram* histogram = ContainerOf(&ELDHistogram::timer_, req);
499
1852
  histogram->RecordDelta();
500

3704
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
501
                 "min", histogram->Min());
502

3704
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
503
                 "max", histogram->Max());
504

3704
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
505
                 "mean", histogram->Mean());
506

3704
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
507
                 "stddev", histogram->Stddev());
508
1852
}
509
510
1852
bool ELDHistogram::RecordDelta() {
511
1852
  uint64_t time = uv_hrtime();
512
1852
  bool ret = true;
513
1852
  if (prev_ > 0) {
514
1851
    int64_t delta = time - prev_;
515
1851
    if (delta > 0) {
516
1851
      ret = Record(delta);
517

3702
      TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
518
                     "delay", delta);
519
1851
      if (!ret) {
520
        if (exceeds_ < 0xFFFFFFFF)
521
          exceeds_++;
522
        ProcessEmitWarning(
523
            env(),
524
            "Event loop delay exceeded 1 hour: %" PRId64 " nanoseconds",
525
            delta);
526
      }
527
    }
528
  }
529
1852
  prev_ = time;
530
1852
  return ret;
531
}
532
533
3
bool ELDHistogram::Enable() {
534

3
  if (enabled_ || IsHandleClosing()) return false;
535
2
  enabled_ = true;
536
2
  prev_ = 0;
537
4
  uv_timer_start(&timer_,
538
                 DelayIntervalCallback,
539
2
                 resolution_,
540
4
                 resolution_);
541
2
  uv_unref(reinterpret_cast<uv_handle_t*>(&timer_));
542
2
  return true;
543
}
544
545
3
bool ELDHistogram::Disable() {
546

3
  if (!enabled_ || IsHandleClosing()) return false;
547
2
  enabled_ = false;
548
2
  uv_timer_stop(&timer_);
549
2
  return true;
550
}
551
552
705
void Initialize(Local<Object> target,
553
                Local<Value> unused,
554
                Local<Context> context,
555
                void* priv) {
556
705
  Environment* env = Environment::GetCurrent(context);
557
705
  Isolate* isolate = env->isolate();
558
705
  PerformanceState* state = env->performance_state();
559
560
1410
  target->Set(context,
561
              FIXED_ONE_BYTE_STRING(isolate, "observerCounts"),
562
2820
              state->observers.GetJSArray()).Check();
563
1410
  target->Set(context,
564
              FIXED_ONE_BYTE_STRING(isolate, "milestones"),
565
2820
              state->milestones.GetJSArray()).Check();
566
567
  Local<String> performanceEntryString =
568
705
      FIXED_ONE_BYTE_STRING(isolate, "PerformanceEntry");
569
570
705
  Local<FunctionTemplate> pe = FunctionTemplate::New(isolate);
571
705
  pe->SetClassName(performanceEntryString);
572
1410
  Local<Function> fn = pe->GetFunction(context).ToLocalChecked();
573
1410
  target->Set(context, performanceEntryString, fn).Check();
574
705
  env->set_performance_entry_template(fn);
575
576
705
  env->SetMethod(target, "clearMark", ClearMark);
577
705
  env->SetMethod(target, "mark", Mark);
578
705
  env->SetMethod(target, "measure", Measure);
579
705
  env->SetMethod(target, "markMilestone", MarkMilestone);
580
705
  env->SetMethod(target, "setupObservers", SetupPerformanceObservers);
581
705
  env->SetMethod(target, "timerify", Timerify);
582
  env->SetMethod(target,
583
                 "installGarbageCollectionTracking",
584
705
                 InstallGarbageCollectionTracking);
585
  env->SetMethod(target,
586
                 "removeGarbageCollectionTracking",
587
705
                 RemoveGarbageCollectionTracking);
588
705
  env->SetMethod(target, "notify", Notify);
589
590
705
  Local<Object> constants = Object::New(isolate);
591
592
2820
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MAJOR);
593
2820
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MINOR);
594
2820
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_INCREMENTAL);
595
2820
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_WEAKCB);
596
597
2820
  NODE_DEFINE_CONSTANT(
598
    constants, NODE_PERFORMANCE_GC_FLAGS_NO);
599
2820
  NODE_DEFINE_CONSTANT(
600
    constants, NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED);
601
2820
  NODE_DEFINE_CONSTANT(
602
    constants, NODE_PERFORMANCE_GC_FLAGS_FORCED);
603
2820
  NODE_DEFINE_CONSTANT(
604
    constants, NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING);
605
2820
  NODE_DEFINE_CONSTANT(
606
    constants, NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE);
607
2820
  NODE_DEFINE_CONSTANT(
608
    constants, NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY);
609
2820
  NODE_DEFINE_CONSTANT(
610
    constants, NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE);
611
612
#define V(name, _)                                                            \
613
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_ENTRY_TYPE_##name);
614
19740
  NODE_PERFORMANCE_ENTRY_TYPES(V)
615
#undef V
616
617
#define V(name, _)                                                            \
618
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_MILESTONE_##name);
619
16920
  NODE_PERFORMANCE_MILESTONES(V)
620
#undef V
621
622
  PropertyAttribute attr =
623
705
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
624
625
1410
  target->DefineOwnProperty(context,
626
                            FIXED_ONE_BYTE_STRING(isolate, "timeOrigin"),
627
                            Number::New(isolate, timeOrigin / 1e6),
628
2820
                            attr).ToChecked();
629
630
1410
  target->DefineOwnProperty(
631
      context,
632
      FIXED_ONE_BYTE_STRING(isolate, "timeOriginTimestamp"),
633
      Number::New(isolate, timeOriginTimestamp / MICROS_PER_MILLIS),
634
2820
      attr).ToChecked();
635
636
1410
  target->DefineOwnProperty(context,
637
                            env->constants_string(),
638
                            constants,
639
2115
                            attr).ToChecked();
640
641
705
  Local<String> eldh_classname = FIXED_ONE_BYTE_STRING(isolate, "ELDHistogram");
642
  Local<FunctionTemplate> eldh =
643
705
      env->NewFunctionTemplate(ELDHistogramNew);
644
705
  eldh->SetClassName(eldh_classname);
645
2115
  eldh->InstanceTemplate()->SetInternalFieldCount(
646
705
      ELDHistogram::kInternalFieldCount);
647
1410
  eldh->Inherit(BaseObject::GetConstructorTemplate(env));
648
705
  env->SetProtoMethod(eldh, "exceeds", ELDHistogramExceeds);
649
705
  env->SetProtoMethod(eldh, "min", ELDHistogramMin);
650
705
  env->SetProtoMethod(eldh, "max", ELDHistogramMax);
651
705
  env->SetProtoMethod(eldh, "mean", ELDHistogramMean);
652
705
  env->SetProtoMethod(eldh, "stddev", ELDHistogramStddev);
653
705
  env->SetProtoMethod(eldh, "percentile", ELDHistogramPercentile);
654
705
  env->SetProtoMethod(eldh, "percentiles", ELDHistogramPercentiles);
655
705
  env->SetProtoMethod(eldh, "enable", ELDHistogramEnable);
656
705
  env->SetProtoMethod(eldh, "disable", ELDHistogramDisable);
657
705
  env->SetProtoMethod(eldh, "reset", ELDHistogramReset);
658
1410
  target->Set(context, eldh_classname,
659
2820
              eldh->GetFunction(env->context()).ToLocalChecked()).Check();
660
705
}
661
662
}  // namespace performance
663
}  // namespace node
664
665

17595
NODE_MODULE_CONTEXT_AWARE_INTERNAL(performance, node::performance::Initialize)