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: 367 400 91.8 %
Date: 2020-09-03 22:13:26 Branches: 133 202 65.8 %

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::Number;
28
using v8::Object;
29
using v8::PropertyAttribute;
30
using v8::ReadOnly;
31
using v8::String;
32
using v8::Value;
33
34
// Microseconds in a millisecond, as a float.
35
#define MICROS_PER_MILLIS 1e3
36
37
// https://w3c.github.io/hr-time/#dfn-time-origin
38
4472
const uint64_t timeOrigin = PERFORMANCE_NOW();
39
// https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
40
4472
const double timeOriginTimestamp = GetCurrentTimeInMicroseconds();
41
uint64_t performance_v8_start;
42
43
4852
PerformanceState::PerformanceState(Isolate* isolate,
44
4852
                                   const PerformanceState::SerializeInfo* info)
45
    : root(isolate,
46
           sizeof(performance_state_internal),
47
           MAYBE_FIELD_PTR(info, root)),
48
      milestones(isolate,
49
                 offsetof(performance_state_internal, milestones),
50
                 NODE_PERFORMANCE_MILESTONE_INVALID,
51
                 root,
52
                 MAYBE_FIELD_PTR(info, milestones)),
53
      observers(isolate,
54
                offsetof(performance_state_internal, observers),
55
                NODE_PERFORMANCE_ENTRY_TYPE_INVALID,
56
                root,
57

4852
                MAYBE_FIELD_PTR(info, observers)) {
58
4853
  if (info == nullptr) {
59
452
    for (size_t i = 0; i < milestones.Length(); i++) milestones[i] = -1.;
60
  }
61
4853
}
62
63
1
PerformanceState::SerializeInfo PerformanceState::Serialize(
64
    v8::Local<v8::Context> context, v8::SnapshotCreator* creator) {
65
1
  SerializeInfo info{root.Serialize(context, creator),
66
1
                     milestones.Serialize(context, creator),
67
2
                     observers.Serialize(context, creator)};
68
1
  return info;
69
}
70
71
4401
void PerformanceState::Deserialize(v8::Local<v8::Context> context) {
72
4401
  root.Deserialize(context);
73
  // This is just done to set up the pointers, we will actually reset
74
  // all the milestones after deserialization.
75
4401
  milestones.Deserialize(context);
76
4401
  observers.Deserialize(context);
77
4401
}
78
79
1
std::ostream& operator<<(std::ostream& o,
80
                         const PerformanceState::SerializeInfo& i) {
81
  o << "{\n"
82
1
    << "  " << i.root << ",  // root\n"
83
2
    << "  " << i.milestones << ",  // milestones\n"
84
2
    << "  " << i.observers << ",  // observers\n"
85
1
    << "}";
86
1
  return o;
87
}
88
89
28234
void PerformanceState::Mark(enum PerformanceMilestone milestone,
90
                             uint64_t ts) {
91
28234
  this->milestones[milestone] = ts;
92

56472
  TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
93
      TRACING_CATEGORY_NODE1(bootstrap),
94
      GetPerformanceMilestoneName(milestone),
95
      TRACE_EVENT_SCOPE_THREAD, ts / 1000);
96
28236
}
97
98
// Initialize the performance entry object properties
99
53
inline void InitObject(const PerformanceEntry& entry, Local<Object> obj) {
100
53
  Environment* env = entry.env();
101
53
  Isolate* isolate = env->isolate();
102
53
  Local<Context> context = env->context();
103
  PropertyAttribute attr =
104
53
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
105
106
  obj->DefineOwnProperty(context,
106
                         env->name_string(),
107
106
                         String::NewFromUtf8(isolate,
108
53
                                             entry.name().c_str())
109
                             .ToLocalChecked(),
110
159
                         attr)
111
      .Check();
112
106
  obj->DefineOwnProperty(context,
113
                         env->entry_type_string(),
114
106
                         String::NewFromUtf8(isolate,
115
53
                                             entry.type().c_str())
116
                             .ToLocalChecked(),
117
159
                         attr)
118
      .Check();
119
106
  obj->DefineOwnProperty(context,
120
                         env->start_time_string(),
121
                         Number::New(isolate, entry.startTime()),
122
212
                         attr).Check();
123
106
  obj->DefineOwnProperty(context,
124
                         env->duration_string(),
125
                         Number::New(isolate, entry.duration()),
126
212
                         attr).Check();
127
53
}
128
129
// Create a new PerformanceEntry object
130
53
MaybeLocal<Object> PerformanceEntry::ToObject() const {
131
  Local<Object> obj;
132
159
  if (!env_->performance_entry_template()
133
159
           ->NewInstance(env_->context())
134
53
           .ToLocal(&obj)) {
135
    return MaybeLocal<Object>();
136
  }
137
53
  InitObject(*this, obj);
138
53
  return obj;
139
}
140
141
// Allow creating a PerformanceEntry object from JavaScript
142
void PerformanceEntry::New(const FunctionCallbackInfo<Value>& args) {
143
  Environment* env = Environment::GetCurrent(args);
144
  Isolate* isolate = env->isolate();
145
  Utf8Value name(isolate, args[0]);
146
  Utf8Value type(isolate, args[1]);
147
  uint64_t now = PERFORMANCE_NOW();
148
  PerformanceEntry entry(env, *name, *type, now, now);
149
  Local<Object> obj = args.This();
150
  InitObject(entry, obj);
151
  PerformanceEntry::Notify(env, entry.kind(), obj);
152
}
153
154
// Pass the PerformanceEntry object to the PerformanceObservers
155
53
void PerformanceEntry::Notify(Environment* env,
156
                              PerformanceEntryType type,
157
                              Local<Value> object) {
158
53
  Context::Scope scope(env->context());
159
53
  AliasedUint32Array& observers = env->performance_state()->observers;
160

265
  if (!env->performance_entry_callback().IsEmpty() &&
161

159
      type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID && observers[type]) {
162
    node::MakeCallback(env->isolate(),
163
                       object.As<Object>(),
164
                       env->performance_entry_callback(),
165
                       1, &object,
166
54
                       node::async_context{0, 0});
167
  }
168
53
}
169
170
// Create a User Timing Mark
171
22
void Mark(const FunctionCallbackInfo<Value>& args) {
172
22
  Environment* env = Environment::GetCurrent(args);
173
44
  HandleScope scope(env->isolate());
174
44
  Utf8Value name(env->isolate(), args[0]);
175
22
  uint64_t now = PERFORMANCE_NOW();
176
22
  auto marks = env->performance_marks();
177
22
  (*marks)[*name] = now;
178
179

44
  TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(
180
      TRACING_CATEGORY_NODE2(perf, usertiming),
181
      *name, now / 1000);
182
183
44
  PerformanceEntry entry(env, *name, "mark", now, now);
184
  Local<Object> obj;
185
44
  if (!entry.ToObject().ToLocal(&obj)) return;
186
22
  PerformanceEntry::Notify(env, entry.kind(), obj);
187
44
  args.GetReturnValue().Set(obj);
188
}
189
190
3
void ClearMark(const FunctionCallbackInfo<Value>& args) {
191
3
  Environment* env = Environment::GetCurrent(args);
192
3
  auto marks = env->performance_marks();
193
194
3
  if (args.Length() == 0) {
195
2
    marks->clear();
196
  } else {
197
2
    Utf8Value name(env->isolate(), args[0]);
198
1
    marks->erase(*name);
199
  }
200
3
}
201
202
24
inline uint64_t GetPerformanceMark(Environment* env, const std::string& name) {
203
24
  auto marks = env->performance_marks();
204
24
  auto res = marks->find(name);
205
24
  return res != marks->end() ? res->second : 0;
206
}
207
208
// Create a User Timing Measure. A Measure is a PerformanceEntry that
209
// measures the duration between two distinct user timing marks
210
13
void Measure(const FunctionCallbackInfo<Value>& args) {
211
13
  Environment* env = Environment::GetCurrent(args);
212
26
  HandleScope scope(env->isolate());
213
26
  Utf8Value name(env->isolate(), args[0]);
214
26
  Utf8Value startMark(env->isolate(), args[1]);
215
216
13
  AliasedFloat64Array& milestones = env->performance_state()->milestones;
217
218
13
  uint64_t startTimestamp = timeOrigin;
219
13
  uint64_t start = GetPerformanceMark(env, *startMark);
220
13
  if (start != 0) {
221
7
    startTimestamp = start;
222
  } else {
223
6
    PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*startMark);
224
6
    if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
225
      startTimestamp = milestones[milestone];
226
  }
227
228
13
  uint64_t endTimestamp = 0;
229
39
  if (args[2]->IsUndefined()) {
230
2
    endTimestamp = PERFORMANCE_NOW();
231
  } else {
232
22
    Utf8Value endMark(env->isolate(), args[2]);
233
11
    endTimestamp = GetPerformanceMark(env, *endMark);
234
11
    if (endTimestamp == 0) {
235
      PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*endMark);
236
      if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
237
        endTimestamp = milestones[milestone];
238
    }
239
  }
240
241
13
  if (endTimestamp < startTimestamp)
242
    endTimestamp = startTimestamp;
243
244

26
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
245
      TRACING_CATEGORY_NODE2(perf, usertiming),
246
      *name, *name, startTimestamp / 1000);
247

26
  TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
248
      TRACING_CATEGORY_NODE2(perf, usertiming),
249
      *name, *name, endTimestamp / 1000);
250
251
26
  PerformanceEntry entry(env, *name, "measure", startTimestamp, endTimestamp);
252
  Local<Object> obj;
253
26
  if (!entry.ToObject().ToLocal(&obj)) return;
254
13
  PerformanceEntry::Notify(env, entry.kind(), obj);
255
26
  args.GetReturnValue().Set(obj);
256
}
257
258
// Allows specific Node.js lifecycle milestones to be set from JavaScript
259
void MarkMilestone(const FunctionCallbackInfo<Value>& args) {
260
  Environment* env = Environment::GetCurrent(args);
261
  Local<Context> context = env->context();
262
  PerformanceMilestone milestone =
263
      static_cast<PerformanceMilestone>(
264
          args[0]->Int32Value(context).ToChecked());
265
  if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
266
    env->performance_state()->Mark(milestone);
267
}
268
269
270
218
void SetupPerformanceObservers(const FunctionCallbackInfo<Value>& args) {
271
218
  Environment* env = Environment::GetCurrent(args);
272
436
  CHECK(args[0]->IsFunction());
273
436
  env->set_performance_entry_callback(args[0].As<Function>());
274
218
}
275
276
// Creates a GC Performance Entry and passes it to observers
277
1
void PerformanceGCCallback(Environment* env,
278
                           std::unique_ptr<GCPerformanceEntry> entry) {
279
2
  HandleScope scope(env->isolate());
280
1
  Local<Context> context = env->context();
281
282
1
  AliasedUint32Array& observers = env->performance_state()->observers;
283
1
  if (observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) {
284
    Local<Object> obj;
285
2
    if (!entry->ToObject().ToLocal(&obj)) return;
286
    PropertyAttribute attr =
287
1
        static_cast<PropertyAttribute>(ReadOnly | DontDelete);
288
2
    obj->DefineOwnProperty(context,
289
                           env->kind_string(),
290
1
                           Integer::New(env->isolate(), entry->gckind()),
291
4
                           attr).Check();
292
2
    obj->DefineOwnProperty(context,
293
                           env->flags_string(),
294
1
                           Integer::New(env->isolate(), entry->gcflags()),
295
4
                           attr).Check();
296
1
    PerformanceEntry::Notify(env, entry->kind(), obj);
297
  }
298
}
299
300
// Marks the start of a GC cycle
301
1
void MarkGarbageCollectionStart(Isolate* isolate,
302
                                GCType type,
303
                                GCCallbackFlags flags,
304
                                void* data) {
305
1
  Environment* env = static_cast<Environment*>(data);
306
1
  env->performance_state()->performance_last_gc_start_mark = PERFORMANCE_NOW();
307
1
}
308
309
// Marks the end of a GC cycle
310
1
void MarkGarbageCollectionEnd(Isolate* isolate,
311
                              GCType type,
312
                              GCCallbackFlags flags,
313
                              void* data) {
314
1
  Environment* env = static_cast<Environment*>(data);
315
1
  PerformanceState* state = env->performance_state();
316
  // If no one is listening to gc performance entries, do not create them.
317
1
  if (!state->observers[NODE_PERFORMANCE_ENTRY_TYPE_GC])
318
    return;
319
  auto entry = std::make_unique<GCPerformanceEntry>(
320
      env,
321
2
      static_cast<PerformanceGCKind>(type),
322
2
      static_cast<PerformanceGCFlags>(flags),
323
      state->performance_last_gc_start_mark,
324
4
      PERFORMANCE_NOW());
325
6
  env->SetImmediate([entry = std::move(entry)](Environment* env) mutable {
326
1
    PerformanceGCCallback(env, std::move(entry));
327
2
  }, CallbackFlags::kUnrefed);
328
}
329
330
1
void GarbageCollectionCleanupHook(void* data) {
331
1
  Environment* env = static_cast<Environment*>(data);
332
1
  env->isolate()->RemoveGCPrologueCallback(MarkGarbageCollectionStart, data);
333
1
  env->isolate()->RemoveGCEpilogueCallback(MarkGarbageCollectionEnd, data);
334
1
}
335
336
1
static void InstallGarbageCollectionTracking(
337
    const FunctionCallbackInfo<Value>& args) {
338
1
  Environment* env = Environment::GetCurrent(args);
339
340
1
  env->isolate()->AddGCPrologueCallback(MarkGarbageCollectionStart,
341
1
                                        static_cast<void*>(env));
342
1
  env->isolate()->AddGCEpilogueCallback(MarkGarbageCollectionEnd,
343
1
                                        static_cast<void*>(env));
344
1
  env->AddCleanupHook(GarbageCollectionCleanupHook, env);
345
1
}
346
347
1
static void RemoveGarbageCollectionTracking(
348
  const FunctionCallbackInfo<Value> &args) {
349
1
  Environment* env = Environment::GetCurrent(args);
350
351
1
  env->RemoveCleanupHook(GarbageCollectionCleanupHook, env);
352
1
  GarbageCollectionCleanupHook(env);
353
1
}
354
355
// Gets the name of a function
356
7
inline Local<Value> GetName(Local<Function> fn) {
357
7
  Local<Value> val = fn->GetDebugName();
358

21
  if (val.IsEmpty() || val->IsUndefined()) {
359
    Local<Value> boundFunction = fn->GetBoundFunction();
360
    if (!boundFunction.IsEmpty() && !boundFunction->IsUndefined()) {
361
      val = GetName(boundFunction.As<Function>());
362
    }
363
  }
364
7
  return val;
365
}
366
367
// Executes a wrapped Function and captures timing information, causing a
368
// Function PerformanceEntry to be emitted to PerformanceObservers after
369
// execution.
370
7
void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
371
7
  Isolate* isolate = args.GetIsolate();
372
7
  Local<Context> context = isolate->GetCurrentContext();
373
7
  Environment* env = Environment::GetCurrent(context);
374
7
  CHECK_NOT_NULL(env);
375
14
  Local<Function> fn = args.Data().As<Function>();
376
7
  size_t count = args.Length();
377
  size_t idx;
378
9
  SlicedArguments call_args(args);
379
9
  Utf8Value name(isolate, GetName(fn));
380
7
  bool is_construct_call = args.IsConstructCall();
381
382
7
  uint64_t start = PERFORMANCE_NOW();
383

14
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
384
      TRACING_CATEGORY_NODE2(perf, timerify),
385
      *name, *name, start / 1000);
386
  v8::MaybeLocal<Value> ret;
387
388
7
  if (is_construct_call) {
389
4
    ret = fn->NewInstance(context, call_args.length(), call_args.out())
390
2
        .FromMaybe(Local<Object>());
391
  } else {
392
12
    ret = fn->Call(context, args.This(), call_args.length(), call_args.out());
393
  }
394
395
7
  uint64_t end = PERFORMANCE_NOW();
396

14
  TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
397
      TRACING_CATEGORY_NODE2(perf, timerify),
398
      *name, *name, end / 1000);
399
400
7
  if (ret.IsEmpty())
401
1
    return;
402
12
  args.GetReturnValue().Set(ret.ToLocalChecked());
403
404
6
  AliasedUint32Array& observers = env->performance_state()->observers;
405
6
  if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION])
406
4
    return;
407
408
4
  PerformanceEntry entry(env, *name, "function", start, end);
409
  Local<Object> obj;
410
4
  if (!entry.ToObject().ToLocal(&obj)) return;
411
4
  for (idx = 0; idx < count; idx++)
412
8
    obj->Set(context, idx, args[idx]).Check();
413
2
  PerformanceEntry::Notify(env, entry.kind(), obj);
414
}
415
416
// Wraps a Function in a TimerFunctionCall
417
8
void Timerify(const FunctionCallbackInfo<Value>& args) {
418
8
  Environment* env = Environment::GetCurrent(args);
419
8
  Local<Context> context = env->context();
420
16
  CHECK(args[0]->IsFunction());
421
16
  CHECK(args[1]->IsNumber());
422
16
  Local<Function> fn = args[0].As<Function>();
423
24
  int length = args[1]->IntegerValue(context).ToChecked();
424
  Local<Function> wrap =
425
16
      Function::New(context, TimerFunctionCall, fn, length).ToLocalChecked();
426
16
  args.GetReturnValue().Set(wrap);
427
8
}
428
429
// Notify a custom PerformanceEntry to observers
430
2
void Notify(const FunctionCallbackInfo<Value>& args) {
431
2
  Environment* env = Environment::GetCurrent(args);
432
4
  Utf8Value type(env->isolate(), args[0]);
433
2
  Local<Value> entry = args[1];
434
2
  PerformanceEntryType entry_type = ToPerformanceEntryTypeEnum(*type);
435
2
  AliasedUint32Array& observers = env->performance_state()->observers;
436

6
  if (entry_type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID &&
437
4
      observers[entry_type]) {
438
4
    USE(env->performance_entry_callback()->
439
8
      Call(env->context(), Undefined(env->isolate()), 1, &entry));
440
  }
441
2
}
442
443
// Return idle time of the event loop
444
17
void LoopIdleTime(const FunctionCallbackInfo<Value>& args) {
445
17
  Environment* env = Environment::GetCurrent(args);
446
17
  uint64_t idle_time = uv_metrics_idle_time(env->event_loop());
447
51
  args.GetReturnValue().Set(1.0 * idle_time / 1e6);
448
17
}
449
450
451
// Event Loop Timing Histogram
452
namespace {
453
2
static void ELDHistogramMin(const FunctionCallbackInfo<Value>& args) {
454
  ELDHistogram* histogram;
455
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
456
2
  double value = static_cast<double>(histogram->Min());
457
4
  args.GetReturnValue().Set(value);
458
}
459
460
2
static void ELDHistogramMax(const FunctionCallbackInfo<Value>& args) {
461
  ELDHistogram* histogram;
462
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
463
2
  double value = static_cast<double>(histogram->Max());
464
4
  args.GetReturnValue().Set(value);
465
}
466
467
2
static void ELDHistogramMean(const FunctionCallbackInfo<Value>& args) {
468
  ELDHistogram* histogram;
469
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
470
6
  args.GetReturnValue().Set(histogram->Mean());
471
}
472
473
static void ELDHistogramExceeds(const FunctionCallbackInfo<Value>& args) {
474
  ELDHistogram* histogram;
475
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
476
  double value = static_cast<double>(histogram->Exceeds());
477
  args.GetReturnValue().Set(value);
478
}
479
480
2
static void ELDHistogramStddev(const FunctionCallbackInfo<Value>& args) {
481
  ELDHistogram* histogram;
482
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
483
6
  args.GetReturnValue().Set(histogram->Stddev());
484
}
485
486
991
static void ELDHistogramPercentile(const FunctionCallbackInfo<Value>& args) {
487
  ELDHistogram* histogram;
488
991
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
489
1982
  CHECK(args[0]->IsNumber());
490
2973
  double percentile = args[0].As<Number>()->Value();
491
2973
  args.GetReturnValue().Set(histogram->Percentile(percentile));
492
}
493
494
2
static void ELDHistogramPercentiles(const FunctionCallbackInfo<Value>& args) {
495
2
  Environment* env = Environment::GetCurrent(args);
496
  ELDHistogram* histogram;
497
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
498
4
  CHECK(args[0]->IsMap());
499
4
  Local<Map> map = args[0].As<Map>();
500
18
  histogram->Percentiles([&](double key, double value) {
501
84
    map->Set(env->context(),
502
             Number::New(env->isolate(), key),
503
70
             Number::New(env->isolate(), value)).IsEmpty();
504
16
  });
505
}
506
507
3
static void ELDHistogramEnable(const FunctionCallbackInfo<Value>& args) {
508
  ELDHistogram* histogram;
509
3
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
510
9
  args.GetReturnValue().Set(histogram->Enable());
511
}
512
513
3
static void ELDHistogramDisable(const FunctionCallbackInfo<Value>& args) {
514
  ELDHistogram* histogram;
515
3
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
516
9
  args.GetReturnValue().Set(histogram->Disable());
517
}
518
519
2
static void ELDHistogramReset(const FunctionCallbackInfo<Value>& args) {
520
  ELDHistogram* histogram;
521
2
  ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
522
2
  histogram->ResetState();
523
}
524
525
2
static void ELDHistogramNew(const FunctionCallbackInfo<Value>& args) {
526
2
  Environment* env = Environment::GetCurrent(args);
527
2
  CHECK(args.IsConstructCall());
528
8
  int32_t resolution = args[0]->IntegerValue(env->context()).FromJust();
529
2
  CHECK_GT(resolution, 0);
530
2
  new ELDHistogram(env, args.This(), resolution);
531
2
}
532
}  // namespace
533
534
2
ELDHistogram::ELDHistogram(
535
    Environment* env,
536
    Local<Object> wrap,
537
2
    int32_t resolution) : HandleWrap(env,
538
                                     wrap,
539
2
                                     reinterpret_cast<uv_handle_t*>(&timer_),
540
                                     AsyncWrap::PROVIDER_ELDHISTOGRAM),
541
                          Histogram(1, 3.6e12),
542
2
                          resolution_(resolution) {
543
2
  MakeWeak();
544
2
  uv_timer_init(env->event_loop(), &timer_);
545
2
}
546
547
1838
void ELDHistogram::DelayIntervalCallback(uv_timer_t* req) {
548
1838
  ELDHistogram* histogram = ContainerOf(&ELDHistogram::timer_, req);
549
1838
  histogram->RecordDelta();
550

3676
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
551
                 "min", histogram->Min());
552

3676
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
553
                 "max", histogram->Max());
554

3676
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
555
                 "mean", histogram->Mean());
556

3676
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
557
                 "stddev", histogram->Stddev());
558
1838
}
559
560
1838
bool ELDHistogram::RecordDelta() {
561
1838
  uint64_t time = uv_hrtime();
562
1838
  bool ret = true;
563
1838
  if (prev_ > 0) {
564
1837
    int64_t delta = time - prev_;
565
1837
    if (delta > 0) {
566
1837
      ret = Record(delta);
567

3674
      TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
568
                     "delay", delta);
569
1837
      if (!ret) {
570
        if (exceeds_ < 0xFFFFFFFF)
571
          exceeds_++;
572
        ProcessEmitWarning(
573
            env(),
574
            "Event loop delay exceeded 1 hour: %" PRId64 " nanoseconds",
575
            delta);
576
      }
577
    }
578
  }
579
1838
  prev_ = time;
580
1838
  return ret;
581
}
582
583
3
bool ELDHistogram::Enable() {
584

3
  if (enabled_ || IsHandleClosing()) return false;
585
2
  enabled_ = true;
586
2
  prev_ = 0;
587
4
  uv_timer_start(&timer_,
588
                 DelayIntervalCallback,
589
2
                 resolution_,
590
4
                 resolution_);
591
2
  uv_unref(reinterpret_cast<uv_handle_t*>(&timer_));
592
2
  return true;
593
}
594
595
3
bool ELDHistogram::Disable() {
596

3
  if (!enabled_ || IsHandleClosing()) return false;
597
2
  enabled_ = false;
598
2
  uv_timer_stop(&timer_);
599
2
  return true;
600
}
601
602
907
void Initialize(Local<Object> target,
603
                Local<Value> unused,
604
                Local<Context> context,
605
                void* priv) {
606
907
  Environment* env = Environment::GetCurrent(context);
607
907
  Isolate* isolate = env->isolate();
608
907
  PerformanceState* state = env->performance_state();
609
610
1814
  target->Set(context,
611
              FIXED_ONE_BYTE_STRING(isolate, "observerCounts"),
612
3628
              state->observers.GetJSArray()).Check();
613
1814
  target->Set(context,
614
              FIXED_ONE_BYTE_STRING(isolate, "milestones"),
615
3628
              state->milestones.GetJSArray()).Check();
616
617
  Local<String> performanceEntryString =
618
907
      FIXED_ONE_BYTE_STRING(isolate, "PerformanceEntry");
619
620
907
  Local<FunctionTemplate> pe = FunctionTemplate::New(isolate);
621
907
  pe->SetClassName(performanceEntryString);
622
1814
  Local<Function> fn = pe->GetFunction(context).ToLocalChecked();
623
1814
  target->Set(context, performanceEntryString, fn).Check();
624
907
  env->set_performance_entry_template(fn);
625
626
907
  env->SetMethod(target, "clearMark", ClearMark);
627
907
  env->SetMethod(target, "mark", Mark);
628
907
  env->SetMethod(target, "measure", Measure);
629
907
  env->SetMethod(target, "markMilestone", MarkMilestone);
630
907
  env->SetMethod(target, "setupObservers", SetupPerformanceObservers);
631
907
  env->SetMethod(target, "timerify", Timerify);
632
  env->SetMethod(target,
633
                 "installGarbageCollectionTracking",
634
907
                 InstallGarbageCollectionTracking);
635
  env->SetMethod(target,
636
                 "removeGarbageCollectionTracking",
637
907
                 RemoveGarbageCollectionTracking);
638
907
  env->SetMethod(target, "notify", Notify);
639
907
  env->SetMethod(target, "loopIdleTime", LoopIdleTime);
640
641
907
  Local<Object> constants = Object::New(isolate);
642
643
3628
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MAJOR);
644
3628
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MINOR);
645
3628
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_INCREMENTAL);
646
3628
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_WEAKCB);
647
648
3628
  NODE_DEFINE_CONSTANT(
649
    constants, NODE_PERFORMANCE_GC_FLAGS_NO);
650
3628
  NODE_DEFINE_CONSTANT(
651
    constants, NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED);
652
3628
  NODE_DEFINE_CONSTANT(
653
    constants, NODE_PERFORMANCE_GC_FLAGS_FORCED);
654
3628
  NODE_DEFINE_CONSTANT(
655
    constants, NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING);
656
3628
  NODE_DEFINE_CONSTANT(
657
    constants, NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE);
658
3628
  NODE_DEFINE_CONSTANT(
659
    constants, NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY);
660
3628
  NODE_DEFINE_CONSTANT(
661
    constants, NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE);
662
663
#define V(name, _)                                                            \
664
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_ENTRY_TYPE_##name);
665
25396
  NODE_PERFORMANCE_ENTRY_TYPES(V)
666
#undef V
667
668
#define V(name, _)                                                            \
669
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_MILESTONE_##name);
670
21768
  NODE_PERFORMANCE_MILESTONES(V)
671
#undef V
672
673
  PropertyAttribute attr =
674
907
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
675
676
1814
  target->DefineOwnProperty(context,
677
                            FIXED_ONE_BYTE_STRING(isolate, "timeOrigin"),
678
                            Number::New(isolate, timeOrigin / 1e6),
679
3628
                            attr).ToChecked();
680
681
1814
  target->DefineOwnProperty(
682
      context,
683
      FIXED_ONE_BYTE_STRING(isolate, "timeOriginTimestamp"),
684
      Number::New(isolate, timeOriginTimestamp / MICROS_PER_MILLIS),
685
3628
      attr).ToChecked();
686
687
1814
  target->DefineOwnProperty(context,
688
                            env->constants_string(),
689
                            constants,
690
2721
                            attr).ToChecked();
691
692
907
  Local<String> eldh_classname = FIXED_ONE_BYTE_STRING(isolate, "ELDHistogram");
693
  Local<FunctionTemplate> eldh =
694
907
      env->NewFunctionTemplate(ELDHistogramNew);
695
907
  eldh->SetClassName(eldh_classname);
696
2721
  eldh->InstanceTemplate()->SetInternalFieldCount(
697
907
      ELDHistogram::kInternalFieldCount);
698
1814
  eldh->Inherit(BaseObject::GetConstructorTemplate(env));
699
907
  env->SetProtoMethod(eldh, "exceeds", ELDHistogramExceeds);
700
907
  env->SetProtoMethod(eldh, "min", ELDHistogramMin);
701
907
  env->SetProtoMethod(eldh, "max", ELDHistogramMax);
702
907
  env->SetProtoMethod(eldh, "mean", ELDHistogramMean);
703
907
  env->SetProtoMethod(eldh, "stddev", ELDHistogramStddev);
704
907
  env->SetProtoMethod(eldh, "percentile", ELDHistogramPercentile);
705
907
  env->SetProtoMethod(eldh, "percentiles", ELDHistogramPercentiles);
706
907
  env->SetProtoMethod(eldh, "enable", ELDHistogramEnable);
707
907
  env->SetProtoMethod(eldh, "disable", ELDHistogramDisable);
708
907
  env->SetProtoMethod(eldh, "reset", ELDHistogramReset);
709
1814
  target->Set(context, eldh_classname,
710
3628
              eldh->GetFunction(env->context()).ToLocalChecked()).Check();
711
907
}
712
713
}  // namespace performance
714
}  // namespace node
715
716

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