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: 416 448 92.9 %
Date: 2021-02-11 04:11:15 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
4699
const uint64_t timeOrigin = PERFORMANCE_NOW();
39
// https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
40
4699
const double timeOriginTimestamp = GetCurrentTimeInMicroseconds();
41
uint64_t performance_v8_start;
42
43
5057
PerformanceState::PerformanceState(Isolate* isolate,
44
5057
                                   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

5057
                MAYBE_FIELD_PTR(info, observers)) {
58
5057
  if (info == nullptr) {
59
444
    for (size_t i = 0; i < milestones.Length(); i++) milestones[i] = -1.;
60
  }
61
5057
}
62
63
8
PerformanceState::SerializeInfo PerformanceState::Serialize(
64
    v8::Local<v8::Context> context, v8::SnapshotCreator* creator) {
65
8
  SerializeInfo info{root.Serialize(context, creator),
66
8
                     milestones.Serialize(context, creator),
67
16
                     observers.Serialize(context, creator)};
68
8
  return info;
69
}
70
71
4613
void PerformanceState::Deserialize(v8::Local<v8::Context> context) {
72
4613
  root.Deserialize(context);
73
  // This is just done to set up the pointers, we will actually reset
74
  // all the milestones after deserialization.
75
4613
  milestones.Deserialize(context);
76
4613
  observers.Deserialize(context);
77
4613
}
78
79
8
std::ostream& operator<<(std::ostream& o,
80
                         const PerformanceState::SerializeInfo& i) {
81
  o << "{\n"
82
8
    << "  " << i.root << ",  // root\n"
83
16
    << "  " << i.milestones << ",  // milestones\n"
84
16
    << "  " << i.observers << ",  // observers\n"
85
8
    << "}";
86
8
  return o;
87
}
88
89
29524
void PerformanceState::Mark(enum PerformanceMilestone milestone,
90
                             uint64_t ts) {
91
29524
  this->milestones[milestone] = static_cast<double>(ts);
92
  TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
93
29524
      TRACING_CATEGORY_NODE1(bootstrap),
94
      GetPerformanceMilestoneName(milestone),
95
4630
      TRACE_EVENT_SCOPE_THREAD, ts / 1000);
96
59048
}
97
46
98
// Initialize the performance entry object properties
99
100
inline void InitObject(const PerformanceEntry& entry, Local<Object> obj) {
100
54
  Environment* env = entry.env();
101
54
  Isolate* isolate = env->isolate();
102
54
  Local<Context> context = env->context();
103
  PropertyAttribute attr =
104
54
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
105
108
  obj->DefineOwnProperty(context,
106
                         env->name_string(),
107
108
                         String::NewFromUtf8(isolate,
108
54
                                             entry.name().c_str())
109
                             .ToLocalChecked(),
110
162
                         attr)
111
      .Check();
112
108
  obj->DefineOwnProperty(context,
113
                         env->entry_type_string(),
114
108
                         String::NewFromUtf8(isolate,
115
54
                                             entry.type().c_str())
116
                             .ToLocalChecked(),
117
162
                         attr)
118
      .Check();
119
108
  obj->DefineOwnProperty(context,
120
                         env->start_time_string(),
121
                         Number::New(isolate, entry.startTime()),
122
216
                         attr).Check();
123
108
  obj->DefineOwnProperty(context,
124
                         env->duration_string(),
125
                         Number::New(isolate, entry.duration()),
126
216
                         attr).Check();
127
54
}
128
129
// Create a new PerformanceEntry object
130
54
MaybeLocal<Object> PerformanceEntry::ToObject() const {
131
  Local<Object> obj;
132
162
  if (!env_->performance_entry_template()
133
162
           ->NewInstance(env_->context())
134
54
           .ToLocal(&obj)) {
135
    return MaybeLocal<Object>();
136
  }
137
54
  InitObject(*this, obj);
138
54
  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
54
void PerformanceEntry::Notify(Environment* env,
156
                              PerformanceEntryType type,
157
                              Local<Value> object) {
158
54
  Context::Scope scope(env->context());
159
54
  AliasedUint32Array& observers = env->performance_state()->observers;
160

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

162
      type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID && observers[type]) {
162
    node::MakeSyncCallback(env->isolate(),
163
                           object.As<Object>(),
164
                           env->performance_entry_callback(),
165
56
                           1, &object);
166
  }
167
54
}
168
169
// Create a User Timing Mark
170
23
void Mark(const FunctionCallbackInfo<Value>& args) {
171
23
  Environment* env = Environment::GetCurrent(args);
172
46
  HandleScope scope(env->isolate());
173
46
  Utf8Value name(env->isolate(), args[0]);
174
23
  uint64_t now = PERFORMANCE_NOW();
175
23
  auto marks = env->performance_marks();
176
23
  (*marks)[*name] = now;
177
178
  TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(
179
23
      TRACING_CATEGORY_NODE2(perf, usertiming),
180
      *name, now / 1000);
181
8
182

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

45
      TRACING_CATEGORY_NODE2(perf, usertiming),
248
13
      *name, *name, endTimestamp / 1000);
249
9
250

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

21
  if (val.IsEmpty() || val->IsUndefined()) {
358
    Local<Value> boundFunction = fn->GetBoundFunction();
359
    if (!boundFunction.IsEmpty() && !boundFunction->IsUndefined()) {
360
      val = GetName(boundFunction.As<Function>());
361
    }
362
  }
363
7
  return val;
364
}
365
366
// Executes a wrapped Function and captures timing information, causing a
367
// Function PerformanceEntry to be emitted to PerformanceObservers after
368
// execution.
369
7
void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
370
7
  Isolate* isolate = args.GetIsolate();
371
7
  Local<Context> context = isolate->GetCurrentContext();
372
7
  Environment* env = Environment::GetCurrent(context);
373
7
  CHECK_NOT_NULL(env);
374
14
  Local<Function> fn = args.Data().As<Function>();
375
7
  size_t count = args.Length();
376
  size_t idx;
377
9
  SlicedArguments call_args(args);
378
9
  Utf8Value name(isolate, GetName(fn));
379
7
  bool is_construct_call = args.IsConstructCall();
380
381
7
  uint64_t start = PERFORMANCE_NOW();
382
7
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
383
      TRACING_CATEGORY_NODE2(perf, timerify),
384
      *name, *name, start / 1000);
385
5
  v8::MaybeLocal<Value> ret;
386
19
387
14
  if (is_construct_call) {
388
7
    ret = fn->NewInstance(context, call_args.length(), call_args.out())
389
11
        .FromMaybe(Local<Object>());
390
9
  } else {
391
12
    ret = fn->Call(context, args.This(), call_args.length(), call_args.out());
392
  }
393
394
7
  uint64_t end = PERFORMANCE_NOW();
395
  TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
396
7
      TRACING_CATEGORY_NODE2(perf, timerify),
397
      *name, *name, end / 1000);
398
5
399

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

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

3522
      if (!ret) {
569
1
        if (exceeds_ < 0xFFFFFFFF)
570
3523
          exceeds_++;
571
1761
        ProcessEmitWarning(
572
            env(),
573
            "Event loop delay exceeded 1 hour: %" PRId64 " nanoseconds",
574
            delta);
575
      }
576
    }
577
  }
578
1762
  prev_ = time;
579
1762
  return ret;
580
}
581
582
3
bool ELDHistogram::Enable() {
583

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

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

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