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-13 22:28:58 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
4314
const uint64_t timeOrigin = PERFORMANCE_NOW();
47
// https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
48
4314
const double timeOriginTimestamp = GetCurrentTimeInMicroseconds();
49
uint64_t performance_node_start;
50
uint64_t performance_v8_start;
51
52
25867
void performance_state::Mark(enum PerformanceMilestone milestone,
53
                             uint64_t ts) {
54
25867
  this->milestones[milestone] = ts;
55

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

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

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

9
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
224
      TRACING_CATEGORY_NODE2(perf, usertiming),
225
      *name, *name, startTimestamp / 1000);
226

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

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

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

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

1885
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
509
                 "min", histogram->Min());
510

1885
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
511
                 "max", histogram->Max());
512

1885
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
513
                 "mean", histogram->Mean());
514

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

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

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