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: 302 334 90.4 %
Date: 2019-02-26 22:23:30 Branches: 119 186 64.0 %

Line Branch Exec Source
1
#include "aliased_buffer.h"
2
#include "node_internals.h"
3
#include "node_perf.h"
4
#include "node_buffer.h"
5
#include "node_process.h"
6
7
#include <cinttypes>
8
9
#ifdef __POSIX__
10
#include <sys/time.h>  // gettimeofday
11
#endif
12
13
namespace node {
14
namespace performance {
15
16
using v8::Array;
17
using v8::Context;
18
using v8::DontDelete;
19
using v8::Function;
20
using v8::FunctionCallbackInfo;
21
using v8::FunctionTemplate;
22
using v8::GCCallbackFlags;
23
using v8::GCType;
24
using v8::HandleScope;
25
using v8::Integer;
26
using v8::Isolate;
27
using v8::Local;
28
using v8::Map;
29
using v8::MaybeLocal;
30
using v8::Name;
31
using v8::NewStringType;
32
using v8::Number;
33
using v8::Object;
34
using v8::PropertyAttribute;
35
using v8::ReadOnly;
36
using v8::String;
37
using v8::Uint32Array;
38
using v8::Value;
39
40
// Microseconds in a second, as a float.
41
#define MICROS_PER_SEC 1e6
42
// Microseconds in a millisecond, as a float.
43
#define MICROS_PER_MILLIS 1e3
44
45
// https://w3c.github.io/hr-time/#dfn-time-origin
46
4282
const uint64_t timeOrigin = PERFORMANCE_NOW();
47
// https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
48
4282
const double timeOriginTimestamp = GetCurrentTimeInMicroseconds();
49
uint64_t performance_v8_start;
50
51
25777
void performance_state::Mark(enum PerformanceMilestone milestone,
52
                             uint64_t ts) {
53
25777
  this->milestones[milestone] = ts;
54

51554
  TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
55
      TRACING_CATEGORY_NODE1(bootstrap),
56
      GetPerformanceMilestoneName(milestone),
57
      TRACE_EVENT_SCOPE_THREAD, ts / 1000);
58
25777
}
59
60
4282
double GetCurrentTimeInMicroseconds() {
61
#ifdef _WIN32
62
// The difference between the Unix Epoch and the Windows Epoch in 100-ns ticks.
63
#define TICKS_TO_UNIX_EPOCH 116444736000000000LL
64
  FILETIME ft;
65
  GetSystemTimeAsFileTime(&ft);
66
  uint64_t filetime_int = static_cast<uint64_t>(ft.dwHighDateTime) << 32 |
67
                          ft.dwLowDateTime;
68
  // FILETIME is measured in terms of 100 ns. Convert that to 1 us (1000 ns).
69
  return (filetime_int - TICKS_TO_UNIX_EPOCH) / 10.;
70
#else
71
  struct timeval tp;
72
4282
  gettimeofday(&tp, nullptr);
73
4282
  return MICROS_PER_SEC * tp.tv_sec + tp.tv_usec;
74
#endif
75
}
76
77
// Initialize the performance entry object properties
78
36
inline void InitObject(const PerformanceEntry& entry, Local<Object> obj) {
79
36
  Environment* env = entry.env();
80
36
  Isolate* isolate = env->isolate();
81
36
  Local<Context> context = env->context();
82
  PropertyAttribute attr =
83
36
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
84
  obj->DefineOwnProperty(context,
85
                         env->name_string(),
86
                         String::NewFromUtf8(isolate,
87
36
                                             entry.name().c_str(),
88
36
                                             NewStringType::kNormal)
89
                             .ToLocalChecked(),
90
144
                         attr)
91
72
      .FromJust();
92
  obj->DefineOwnProperty(context,
93
                         env->entry_type_string(),
94
                         String::NewFromUtf8(isolate,
95
36
                                             entry.type().c_str(),
96
36
                                             NewStringType::kNormal)
97
                             .ToLocalChecked(),
98
144
                         attr)
99
72
      .FromJust();
100
  obj->DefineOwnProperty(context,
101
                         env->start_time_string(),
102
                         Number::New(isolate, entry.startTime()),
103
144
                         attr).FromJust();
104
  obj->DefineOwnProperty(context,
105
                         env->duration_string(),
106
                         Number::New(isolate, entry.duration()),
107
144
                         attr).FromJust();
108
36
}
109
110
// Create a new PerformanceEntry object
111
36
MaybeLocal<Object> PerformanceEntry::ToObject() const {
112
  Local<Object> obj;
113
108
  if (!env_->performance_entry_template()
114
144
           ->NewInstance(env_->context())
115
108
           .ToLocal(&obj)) {
116
    return MaybeLocal<Object>();
117
  }
118
36
  InitObject(*this, obj);
119
36
  return obj;
120
}
121
122
// Allow creating a PerformanceEntry object from JavaScript
123
void PerformanceEntry::New(const FunctionCallbackInfo<Value>& args) {
124
  Environment* env = Environment::GetCurrent(args);
125
  Isolate* isolate = env->isolate();
126
  Utf8Value name(isolate, args[0]);
127
  Utf8Value type(isolate, args[1]);
128
  uint64_t now = PERFORMANCE_NOW();
129
  PerformanceEntry entry(env, *name, *type, now, now);
130
  Local<Object> obj = args.This();
131
  InitObject(entry, obj);
132
  PerformanceEntry::Notify(env, entry.kind(), obj);
133
}
134
135
// Pass the PerformanceEntry object to the PerformanceObservers
136
36
void PerformanceEntry::Notify(Environment* env,
137
                              PerformanceEntryType type,
138
                              Local<Value> object) {
139
36
  Context::Scope scope(env->context());
140
  AliasedBuffer<uint32_t, Uint32Array>& observers =
141
36
      env->performance_state()->observers;
142

144
  if (type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID &&
143
144
      observers[type]) {
144
    node::MakeCallback(env->isolate(),
145
                       object.As<Object>(),
146
                       env->performance_entry_callback(),
147
                       1, &object,
148
26
                       node::async_context{0, 0});
149
  }
150
36
}
151
152
// Create a User Timing Mark
153
19
void Mark(const FunctionCallbackInfo<Value>& args) {
154
19
  Environment* env = Environment::GetCurrent(args);
155
19
  HandleScope scope(env->isolate());
156
38
  Utf8Value name(env->isolate(), args[0]);
157
19
  uint64_t now = PERFORMANCE_NOW();
158
19
  auto marks = env->performance_marks();
159
19
  (*marks)[*name] = now;
160
161

38
  TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(
162
      TRACING_CATEGORY_NODE2(perf, usertiming),
163
      *name, now / 1000);
164
165
38
  PerformanceEntry entry(env, *name, "mark", now, now);
166
  Local<Object> obj;
167
57
  if (!entry.ToObject().ToLocal(&obj)) return;
168
19
  PerformanceEntry::Notify(env, entry.kind(), obj);
169
57
  args.GetReturnValue().Set(obj);
170
}
171
172
3
void ClearMark(const FunctionCallbackInfo<Value>& args) {
173
3
  Environment* env = Environment::GetCurrent(args);
174
3
  auto marks = env->performance_marks();
175
176
3
  if (args.Length() == 0) {
177
2
    marks->clear();
178
  } else {
179
1
    Utf8Value name(env->isolate(), args[0]);
180
1
    marks->erase(*name);
181
  }
182
3
}
183
184
20
inline uint64_t GetPerformanceMark(Environment* env, const std::string& name) {
185
20
  auto marks = env->performance_marks();
186
20
  auto res = marks->find(name);
187
20
  return res != marks->end() ? res->second : 0;
188
}
189
190
// Create a User Timing Measure. A Measure is a PerformanceEntry that
191
// measures the duration between two distinct user timing marks
192
10
void Measure(const FunctionCallbackInfo<Value>& args) {
193
10
  Environment* env = Environment::GetCurrent(args);
194
10
  HandleScope scope(env->isolate());
195
20
  Utf8Value name(env->isolate(), args[0]);
196
20
  Utf8Value startMark(env->isolate(), args[1]);
197
20
  Utf8Value endMark(env->isolate(), args[2]);
198
199
  AliasedBuffer<double, v8::Float64Array>& milestones =
200
10
      env->performance_state()->milestones;
201
202
10
  uint64_t startTimestamp = timeOrigin;
203
10
  uint64_t start = GetPerformanceMark(env, *startMark);
204
10
  if (start != 0) {
205
5
    startTimestamp = start;
206
  } else {
207
5
    PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*startMark);
208
5
    if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
209
      startTimestamp = milestones[milestone];
210
  }
211
212
10
  uint64_t endTimestamp = GetPerformanceMark(env, *endMark);
213
10
  if (endTimestamp == 0) {
214
    PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*endMark);
215
    if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
216
      endTimestamp = milestones[milestone];
217
  }
218
219
10
  if (endTimestamp < startTimestamp)
220
    endTimestamp = startTimestamp;
221
222

20
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
223
      TRACING_CATEGORY_NODE2(perf, usertiming),
224
      *name, *name, startTimestamp / 1000);
225

20
  TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
226
      TRACING_CATEGORY_NODE2(perf, usertiming),
227
      *name, *name, endTimestamp / 1000);
228
229
20
  PerformanceEntry entry(env, *name, "measure", startTimestamp, endTimestamp);
230
  Local<Object> obj;
231
30
  if (!entry.ToObject().ToLocal(&obj)) return;
232
10
  PerformanceEntry::Notify(env, entry.kind(), obj);
233
30
  args.GetReturnValue().Set(obj);
234
}
235
236
// Allows specific Node.js lifecycle milestones to be set from JavaScript
237
void MarkMilestone(const FunctionCallbackInfo<Value>& args) {
238
  Environment* env = Environment::GetCurrent(args);
239
  Local<Context> context = env->context();
240
  PerformanceMilestone milestone =
241
      static_cast<PerformanceMilestone>(
242
          args[0]->Int32Value(context).ToChecked());
243
  if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
244
    env->performance_state()->Mark(milestone);
245
}
246
247
248
13
void SetupPerformanceObservers(const FunctionCallbackInfo<Value>& args) {
249
13
  Environment* env = Environment::GetCurrent(args);
250
26
  CHECK(args[0]->IsFunction());
251
26
  env->set_performance_entry_callback(args[0].As<Function>());
252
13
}
253
254
// Creates a GC Performance Entry and passes it to observers
255
1
void PerformanceGCCallback(Environment* env, void* ptr) {
256
  std::unique_ptr<GCPerformanceEntry> entry{
257
1
      static_cast<GCPerformanceEntry*>(ptr)};
258
2
  HandleScope scope(env->isolate());
259
1
  Local<Context> context = env->context();
260
261
  AliasedBuffer<uint32_t, Uint32Array>& observers =
262
1
      env->performance_state()->observers;
263
1
  if (observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) {
264
    Local<Object> obj;
265
3
    if (!entry->ToObject().ToLocal(&obj)) return;
266
    PropertyAttribute attr =
267
1
        static_cast<PropertyAttribute>(ReadOnly | DontDelete);
268
    obj->DefineOwnProperty(context,
269
                           env->kind_string(),
270
1
                           Integer::New(env->isolate(), entry->gckind()),
271
4
                           attr).FromJust();
272
1
    PerformanceEntry::Notify(env, entry->kind(), obj);
273
1
  }
274
}
275
276
// Marks the start of a GC cycle
277
2
void MarkGarbageCollectionStart(Isolate* isolate,
278
                                GCType type,
279
                                GCCallbackFlags flags,
280
                                void* data) {
281
2
  Environment* env = static_cast<Environment*>(data);
282
2
  env->performance_state()->performance_last_gc_start_mark = PERFORMANCE_NOW();
283
2
}
284
285
// Marks the end of a GC cycle
286
2
void MarkGarbageCollectionEnd(Isolate* isolate,
287
                              GCType type,
288
                              GCCallbackFlags flags,
289
                              void* data) {
290
2
  Environment* env = static_cast<Environment*>(data);
291
2
  performance_state* state = env->performance_state();
292
  // If no one is listening to gc performance entries, do not create them.
293
2
  if (!state->observers[NODE_PERFORMANCE_ENTRY_TYPE_GC])
294
3
    return;
295
  GCPerformanceEntry* entry =
296
      new GCPerformanceEntry(env,
297
                             static_cast<PerformanceGCKind>(type),
298
                             state->performance_last_gc_start_mark,
299
1
                             PERFORMANCE_NOW());
300
  env->SetUnrefImmediate(PerformanceGCCallback,
301
1
                         entry);
302
}
303
304
1
static void SetupGarbageCollectionTracking(
305
    const FunctionCallbackInfo<Value>& args) {
306
1
  Environment* env = Environment::GetCurrent(args);
307
308
  env->isolate()->AddGCPrologueCallback(MarkGarbageCollectionStart,
309
1
                                        static_cast<void*>(env));
310
  env->isolate()->AddGCEpilogueCallback(MarkGarbageCollectionEnd,
311
1
                                        static_cast<void*>(env));
312
3
  env->AddCleanupHook([](void* data) {
313
1
    Environment* env = static_cast<Environment*>(data);
314
1
    env->isolate()->RemoveGCPrologueCallback(MarkGarbageCollectionStart, data);
315
1
    env->isolate()->RemoveGCEpilogueCallback(MarkGarbageCollectionEnd, data);
316
4
  }, env);
317
1
}
318
319
// Gets the name of a function
320
7
inline Local<Value> GetName(Local<Function> fn) {
321
7
  Local<Value> val = fn->GetDebugName();
322

21
  if (val.IsEmpty() || val->IsUndefined()) {
323
    Local<Value> boundFunction = fn->GetBoundFunction();
324
    if (!boundFunction.IsEmpty() && !boundFunction->IsUndefined()) {
325
      val = GetName(boundFunction.As<Function>());
326
    }
327
  }
328
7
  return val;
329
}
330
331
// Executes a wrapped Function and captures timing information, causing a
332
// Function PerformanceEntry to be emitted to PerformanceObservers after
333
// execution.
334
7
void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
335
7
  Isolate* isolate = args.GetIsolate();
336
7
  HandleScope scope(isolate);
337
7
  Environment* env = Environment::GetCurrent(isolate);
338
7
  CHECK_NOT_NULL(env);
339
7
  Local<Context> context = env->context();
340
14
  Local<Function> fn = args.Data().As<Function>();
341
7
  size_t count = args.Length();
342
  size_t idx;
343
9
  SlicedArguments call_args(args);
344
9
  Utf8Value name(isolate, GetName(fn));
345
7
  bool is_construct_call = args.IsConstructCall();
346
347
7
  uint64_t start = PERFORMANCE_NOW();
348

14
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
349
      TRACING_CATEGORY_NODE2(perf, timerify),
350
      *name, *name, start / 1000);
351
  v8::MaybeLocal<Value> ret;
352
353
7
  if (is_construct_call) {
354
2
    ret = fn->NewInstance(context, call_args.length(), call_args.out())
355
2
        .FromMaybe(Local<Object>());
356
  } else {
357
12
    ret = fn->Call(context, args.This(), call_args.length(), call_args.out());
358
  }
359
360
7
  uint64_t end = PERFORMANCE_NOW();
361

14
  TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
362
      TRACING_CATEGORY_NODE2(perf, timerify),
363
      *name, *name, end / 1000);
364
365
7
  if (ret.IsEmpty())
366
1
    return;
367
12
  args.GetReturnValue().Set(ret.ToLocalChecked());
368
369
  AliasedBuffer<uint32_t, Uint32Array>& observers =
370
6
      env->performance_state()->observers;
371
6
  if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION])
372
4
    return;
373
374
4
  PerformanceEntry entry(env, *name, "function", start, end);
375
  Local<Object> obj;
376
4
  if (!entry.ToObject().ToLocal(&obj)) return;
377
4
  for (idx = 0; idx < count; idx++)
378
8
    obj->Set(context, idx, args[idx]).FromJust();
379
4
  PerformanceEntry::Notify(env, entry.kind(), obj);
380
}
381
382
// Wraps a Function in a TimerFunctionCall
383
8
void Timerify(const FunctionCallbackInfo<Value>& args) {
384
8
  Environment* env = Environment::GetCurrent(args);
385
8
  Local<Context> context = env->context();
386
16
  CHECK(args[0]->IsFunction());
387
16
  CHECK(args[1]->IsNumber());
388
16
  Local<Function> fn = args[0].As<Function>();
389
24
  int length = args[1]->IntegerValue(context).ToChecked();
390
  Local<Function> wrap =
391
16
      Function::New(context, TimerFunctionCall, fn, length).ToLocalChecked();
392
16
  args.GetReturnValue().Set(wrap);
393
8
}
394
395
// Event Loop Timing Histogram
396
namespace {
397
2
static void ELDHistogramMin(const FunctionCallbackInfo<Value>& args) {
398
  ELDHistogram* histogram;
399
4
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
400
2
  double value = static_cast<double>(histogram->Min());
401
4
  args.GetReturnValue().Set(value);
402
}
403
404
2
static void ELDHistogramMax(const FunctionCallbackInfo<Value>& args) {
405
  ELDHistogram* histogram;
406
4
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
407
2
  double value = static_cast<double>(histogram->Max());
408
4
  args.GetReturnValue().Set(value);
409
}
410
411
2
static void ELDHistogramMean(const FunctionCallbackInfo<Value>& args) {
412
  ELDHistogram* histogram;
413
4
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
414
6
  args.GetReturnValue().Set(histogram->Mean());
415
}
416
417
static void ELDHistogramExceeds(const FunctionCallbackInfo<Value>& args) {
418
  ELDHistogram* histogram;
419
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
420
  double value = static_cast<double>(histogram->Exceeds());
421
  args.GetReturnValue().Set(value);
422
}
423
424
2
static void ELDHistogramStddev(const FunctionCallbackInfo<Value>& args) {
425
  ELDHistogram* histogram;
426
4
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
427
6
  args.GetReturnValue().Set(histogram->Stddev());
428
}
429
430
991
static void ELDHistogramPercentile(const FunctionCallbackInfo<Value>& args) {
431
  ELDHistogram* histogram;
432
1982
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
433
1982
  CHECK(args[0]->IsNumber());
434
2973
  double percentile = args[0].As<Number>()->Value();
435
2973
  args.GetReturnValue().Set(histogram->Percentile(percentile));
436
}
437
438
2
static void ELDHistogramPercentiles(const FunctionCallbackInfo<Value>& args) {
439
2
  Environment* env = Environment::GetCurrent(args);
440
  ELDHistogram* histogram;
441
4
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
442
4
  CHECK(args[0]->IsMap());
443
4
  Local<Map> map = args[0].As<Map>();
444
14
  histogram->Percentiles([&](double key, double value) {
445
    map->Set(env->context(),
446
             Number::New(env->isolate(), key),
447
70
             Number::New(env->isolate(), value)).IsEmpty();
448
16
  });
449
}
450
451
3
static void ELDHistogramEnable(const FunctionCallbackInfo<Value>& args) {
452
  ELDHistogram* histogram;
453
6
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
454
9
  args.GetReturnValue().Set(histogram->Enable());
455
}
456
457
3
static void ELDHistogramDisable(const FunctionCallbackInfo<Value>& args) {
458
  ELDHistogram* histogram;
459
6
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
460
9
  args.GetReturnValue().Set(histogram->Disable());
461
}
462
463
2
static void ELDHistogramReset(const FunctionCallbackInfo<Value>& args) {
464
  ELDHistogram* histogram;
465
4
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
466
2
  histogram->ResetState();
467
}
468
469
2
static void ELDHistogramNew(const FunctionCallbackInfo<Value>& args) {
470
2
  Environment* env = Environment::GetCurrent(args);
471
2
  CHECK(args.IsConstructCall());
472
8
  int32_t resolution = args[0]->IntegerValue(env->context()).FromJust();
473
2
  CHECK_GT(resolution, 0);
474
2
  new ELDHistogram(env, args.This(), resolution);
475
2
}
476
}  // namespace
477
478
2
ELDHistogram::ELDHistogram(
479
    Environment* env,
480
    Local<Object> wrap,
481
    int32_t resolution) : BaseObject(env, wrap),
482
                          Histogram(1, 3.6e12),
483
2
                          resolution_(resolution) {
484
2
  MakeWeak();
485
2
  timer_ = new uv_timer_t();
486
2
  uv_timer_init(env->event_loop(), timer_);
487
2
  timer_->data = this;
488
2
}
489
490
2
void ELDHistogram::CloseTimer() {
491
2
  if (timer_ == nullptr)
492
2
    return;
493
494
4
  env()->CloseHandle(timer_, [](uv_timer_t* handle) { delete handle; });
495
2
  timer_ = nullptr;
496
}
497
498
6
ELDHistogram::~ELDHistogram() {
499
2
  Disable();
500
2
  CloseTimer();
501
4
}
502
503
1885
void ELDHistogramDelayInterval(uv_timer_t* req) {
504
  ELDHistogram* histogram =
505
1885
    reinterpret_cast<ELDHistogram*>(req->data);
506
1885
  histogram->RecordDelta();
507

3770
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
508
                 "min", histogram->Min());
509

3770
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
510
                 "max", histogram->Max());
511

3770
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
512
                 "mean", histogram->Mean());
513

3770
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
514
                 "stddev", histogram->Stddev());
515
1885
}
516
517
1885
bool ELDHistogram::RecordDelta() {
518
1885
  uint64_t time = uv_hrtime();
519
1885
  bool ret = true;
520
1885
  if (prev_ > 0) {
521
1884
    int64_t delta = time - prev_;
522
1884
    if (delta > 0) {
523
1884
      ret = Record(delta);
524

3768
      TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
525
                     "delay", delta);
526
1884
      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
1885
  prev_ = time;
537
1885
  return ret;
538
}
539
540
3
bool ELDHistogram::Enable() {
541
3
  if (enabled_) return false;
542
2
  enabled_ = true;
543
  uv_timer_start(timer_,
544
                 ELDHistogramDelayInterval,
545
                 resolution_,
546
2
                 resolution_);
547
2
  uv_unref(reinterpret_cast<uv_handle_t*>(timer_));
548
2
  return true;
549
}
550
551
5
bool ELDHistogram::Disable() {
552
5
  if (!enabled_) return false;
553
2
  enabled_ = false;
554
2
  uv_timer_stop(timer_);
555
2
  return true;
556
}
557
558
13
void Initialize(Local<Object> target,
559
                Local<Value> unused,
560
                Local<Context> context,
561
                void* priv) {
562
13
  Environment* env = Environment::GetCurrent(context);
563
13
  Isolate* isolate = env->isolate();
564
13
  performance_state* state = env->performance_state();
565
566
  target->Set(context,
567
              FIXED_ONE_BYTE_STRING(isolate, "observerCounts"),
568
52
              state->observers.GetJSArray()).FromJust();
569
  target->Set(context,
570
              FIXED_ONE_BYTE_STRING(isolate, "milestones"),
571
52
              state->milestones.GetJSArray()).FromJust();
572
573
  Local<String> performanceEntryString =
574
13
      FIXED_ONE_BYTE_STRING(isolate, "PerformanceEntry");
575
576
13
  Local<FunctionTemplate> pe = FunctionTemplate::New(isolate);
577
13
  pe->SetClassName(performanceEntryString);
578
26
  Local<Function> fn = pe->GetFunction(context).ToLocalChecked();
579
26
  target->Set(context, performanceEntryString, fn).FromJust();
580
13
  env->set_performance_entry_template(fn);
581
582
13
  env->SetMethod(target, "clearMark", ClearMark);
583
13
  env->SetMethod(target, "mark", Mark);
584
13
  env->SetMethod(target, "measure", Measure);
585
13
  env->SetMethod(target, "markMilestone", MarkMilestone);
586
13
  env->SetMethod(target, "setupObservers", SetupPerformanceObservers);
587
13
  env->SetMethod(target, "timerify", Timerify);
588
  env->SetMethod(
589
13
      target, "setupGarbageCollectionTracking", SetupGarbageCollectionTracking);
590
591
13
  Local<Object> constants = Object::New(isolate);
592
593
52
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MAJOR);
594
52
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MINOR);
595
52
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_INCREMENTAL);
596
52
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_WEAKCB);
597
598
#define V(name, _)                                                            \
599
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_ENTRY_TYPE_##name);
600
312
  NODE_PERFORMANCE_ENTRY_TYPES(V)
601
#undef V
602
603
#define V(name, _)                                                            \
604
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_MILESTONE_##name);
605
312
  NODE_PERFORMANCE_MILESTONES(V)
606
#undef V
607
608
  PropertyAttribute attr =
609
13
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
610
611
  target->DefineOwnProperty(context,
612
                            FIXED_ONE_BYTE_STRING(isolate, "timeOrigin"),
613
                            Number::New(isolate, timeOrigin / 1e6),
614
52
                            attr).ToChecked();
615
616
  target->DefineOwnProperty(
617
      context,
618
      FIXED_ONE_BYTE_STRING(isolate, "timeOriginTimestamp"),
619
      Number::New(isolate, timeOriginTimestamp / MICROS_PER_MILLIS),
620
52
      attr).ToChecked();
621
622
  target->DefineOwnProperty(context,
623
                            env->constants_string(),
624
                            constants,
625
39
                            attr).ToChecked();
626
627
13
  Local<String> eldh_classname = FIXED_ONE_BYTE_STRING(isolate, "ELDHistogram");
628
  Local<FunctionTemplate> eldh =
629
13
      env->NewFunctionTemplate(ELDHistogramNew);
630
13
  eldh->SetClassName(eldh_classname);
631
26
  eldh->InstanceTemplate()->SetInternalFieldCount(1);
632
13
  env->SetProtoMethod(eldh, "exceeds", ELDHistogramExceeds);
633
13
  env->SetProtoMethod(eldh, "min", ELDHistogramMin);
634
13
  env->SetProtoMethod(eldh, "max", ELDHistogramMax);
635
13
  env->SetProtoMethod(eldh, "mean", ELDHistogramMean);
636
13
  env->SetProtoMethod(eldh, "stddev", ELDHistogramStddev);
637
13
  env->SetProtoMethod(eldh, "percentile", ELDHistogramPercentile);
638
13
  env->SetProtoMethod(eldh, "percentiles", ELDHistogramPercentiles);
639
13
  env->SetProtoMethod(eldh, "enable", ELDHistogramEnable);
640
13
  env->SetProtoMethod(eldh, "disable", ELDHistogramDisable);
641
13
  env->SetProtoMethod(eldh, "reset", ELDHistogramReset);
642
  target->Set(context, eldh_classname,
643
52
              eldh->GetFunction(env->context()).ToLocalChecked()).FromJust();
644
13
}
645
646
}  // namespace performance
647
}  // namespace node
648
649

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