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: 340 373 91.2 %
Date: 2020-05-27 22:15:15 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::Array;
15
using v8::Context;
16
using v8::DontDelete;
17
using v8::Function;
18
using v8::FunctionCallbackInfo;
19
using v8::FunctionTemplate;
20
using v8::GCCallbackFlags;
21
using v8::GCType;
22
using v8::HandleScope;
23
using v8::Integer;
24
using v8::Isolate;
25
using v8::Local;
26
using v8::Map;
27
using v8::MaybeLocal;
28
using v8::Name;
29
using v8::NewStringType;
30
using v8::Number;
31
using v8::Object;
32
using v8::PropertyAttribute;
33
using v8::ReadOnly;
34
using v8::String;
35
using v8::Uint32Array;
36
using v8::Value;
37
38
// Microseconds in a millisecond, as a float.
39
#define MICROS_PER_MILLIS 1e3
40
41
// https://w3c.github.io/hr-time/#dfn-time-origin
42
4326
const uint64_t timeOrigin = PERFORMANCE_NOW();
43
// https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
44
4326
const double timeOriginTimestamp = GetCurrentTimeInMicroseconds();
45
uint64_t performance_v8_start;
46
47
26752
void PerformanceState::Mark(enum PerformanceMilestone milestone,
48
                             uint64_t ts) {
49
26752
  this->milestones[milestone] = ts;
50

53502
  TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
51
      TRACING_CATEGORY_NODE1(bootstrap),
52
      GetPerformanceMilestoneName(milestone),
53
      TRACE_EVENT_SCOPE_THREAD, ts / 1000);
54
26751
}
55
56
// Initialize the performance entry object properties
57
42
inline void InitObject(const PerformanceEntry& entry, Local<Object> obj) {
58
42
  Environment* env = entry.env();
59
42
  Isolate* isolate = env->isolate();
60
42
  Local<Context> context = env->context();
61
  PropertyAttribute attr =
62
42
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
63
84
  obj->DefineOwnProperty(context,
64
                         env->name_string(),
65
84
                         String::NewFromUtf8(isolate,
66
42
                                             entry.name().c_str(),
67
42
                                             NewStringType::kNormal)
68
                             .ToLocalChecked(),
69
126
                         attr)
70
      .Check();
71
84
  obj->DefineOwnProperty(context,
72
                         env->entry_type_string(),
73
84
                         String::NewFromUtf8(isolate,
74
42
                                             entry.type().c_str(),
75
42
                                             NewStringType::kNormal)
76
                             .ToLocalChecked(),
77
126
                         attr)
78
      .Check();
79
84
  obj->DefineOwnProperty(context,
80
                         env->start_time_string(),
81
                         Number::New(isolate, entry.startTime()),
82
168
                         attr).Check();
83
84
  obj->DefineOwnProperty(context,
84
                         env->duration_string(),
85
                         Number::New(isolate, entry.duration()),
86
168
                         attr).Check();
87
42
}
88
89
// Create a new PerformanceEntry object
90
42
MaybeLocal<Object> PerformanceEntry::ToObject() const {
91
  Local<Object> obj;
92
126
  if (!env_->performance_entry_template()
93
126
           ->NewInstance(env_->context())
94
42
           .ToLocal(&obj)) {
95
    return MaybeLocal<Object>();
96
  }
97
42
  InitObject(*this, obj);
98
42
  return obj;
99
}
100
101
// Allow creating a PerformanceEntry object from JavaScript
102
void PerformanceEntry::New(const FunctionCallbackInfo<Value>& args) {
103
  Environment* env = Environment::GetCurrent(args);
104
  Isolate* isolate = env->isolate();
105
  Utf8Value name(isolate, args[0]);
106
  Utf8Value type(isolate, args[1]);
107
  uint64_t now = PERFORMANCE_NOW();
108
  PerformanceEntry entry(env, *name, *type, now, now);
109
  Local<Object> obj = args.This();
110
  InitObject(entry, obj);
111
  PerformanceEntry::Notify(env, entry.kind(), obj);
112
}
113
114
// Pass the PerformanceEntry object to the PerformanceObservers
115
42
void PerformanceEntry::Notify(Environment* env,
116
                              PerformanceEntryType type,
117
                              Local<Value> object) {
118
42
  Context::Scope scope(env->context());
119
42
  AliasedUint32Array& observers = env->performance_state()->observers;
120

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

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

26
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
205
      TRACING_CATEGORY_NODE2(perf, usertiming),
206
      *name, *name, startTimestamp / 1000);
207

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

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

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

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

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

3704
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
504
                 "min", histogram->Min());
505

3704
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
506
                 "max", histogram->Max());
507

3704
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
508
                 "mean", histogram->Mean());
509

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

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

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

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

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