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: 308 340 90.6 %
Date: 2019-10-06 22:30:00 Branches: 123 194 63.4 %

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
5059
const uint64_t timeOrigin = PERFORMANCE_NOW();
43
// https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
44
5059
const double timeOriginTimestamp = GetCurrentTimeInMicroseconds();
45
uint64_t performance_v8_start;
46
47
30571
void performance_state::Mark(enum PerformanceMilestone milestone,
48
                             uint64_t ts) {
49
30571
  this->milestones[milestone] = ts;
50

61142
  TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
51
      TRACING_CATEGORY_NODE1(bootstrap),
52
      GetPerformanceMilestoneName(milestone),
53
      TRACE_EVENT_SCOPE_THREAD, ts / 1000);
54
30571
}
55
56
// Initialize the performance entry object properties
57
37
inline void InitObject(const PerformanceEntry& entry, Local<Object> obj) {
58
37
  Environment* env = entry.env();
59
37
  Isolate* isolate = env->isolate();
60
37
  Local<Context> context = env->context();
61
  PropertyAttribute attr =
62
37
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
63
  obj->DefineOwnProperty(context,
64
                         env->name_string(),
65
                         String::NewFromUtf8(isolate,
66
37
                                             entry.name().c_str(),
67
37
                                             NewStringType::kNormal)
68
                             .ToLocalChecked(),
69
148
                         attr)
70
74
      .Check();
71
  obj->DefineOwnProperty(context,
72
                         env->entry_type_string(),
73
                         String::NewFromUtf8(isolate,
74
37
                                             entry.type().c_str(),
75
37
                                             NewStringType::kNormal)
76
                             .ToLocalChecked(),
77
148
                         attr)
78
74
      .Check();
79
  obj->DefineOwnProperty(context,
80
                         env->start_time_string(),
81
                         Number::New(isolate, entry.startTime()),
82
148
                         attr).Check();
83
  obj->DefineOwnProperty(context,
84
                         env->duration_string(),
85
                         Number::New(isolate, entry.duration()),
86
148
                         attr).Check();
87
37
}
88
89
// Create a new PerformanceEntry object
90
37
MaybeLocal<Object> PerformanceEntry::ToObject() const {
91
  Local<Object> obj;
92
111
  if (!env_->performance_entry_template()
93
148
           ->NewInstance(env_->context())
94
111
           .ToLocal(&obj)) {
95
    return MaybeLocal<Object>();
96
  }
97
37
  InitObject(*this, obj);
98
37
  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
37
void PerformanceEntry::Notify(Environment* env,
116
                              PerformanceEntryType type,
117
                              Local<Value> object) {
118
37
  Context::Scope scope(env->context());
119
37
  AliasedUint32Array& observers = env->performance_state()->observers;
120

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

40
  TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(
140
      TRACING_CATEGORY_NODE2(perf, usertiming),
141
      *name, now / 1000);
142
143
40
  PerformanceEntry entry(env, *name, "mark", now, now);
144
  Local<Object> obj;
145
60
  if (!entry.ToObject().ToLocal(&obj)) return;
146
20
  PerformanceEntry::Notify(env, entry.kind(), obj);
147
60
  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
1
    Utf8Value name(env->isolate(), args[0]);
158
1
    marks->erase(*name);
159
  }
160
3
}
161
162
20
inline uint64_t GetPerformanceMark(Environment* env, const std::string& name) {
163
20
  auto marks = env->performance_marks();
164
20
  auto res = marks->find(name);
165
20
  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
10
void Measure(const FunctionCallbackInfo<Value>& args) {
171
10
  Environment* env = Environment::GetCurrent(args);
172
10
  HandleScope scope(env->isolate());
173
20
  Utf8Value name(env->isolate(), args[0]);
174
20
  Utf8Value startMark(env->isolate(), args[1]);
175
20
  Utf8Value endMark(env->isolate(), args[2]);
176
177
10
  AliasedFloat64Array& milestones = env->performance_state()->milestones;
178
179
10
  uint64_t startTimestamp = timeOrigin;
180
10
  uint64_t start = GetPerformanceMark(env, *startMark);
181
10
  if (start != 0) {
182
5
    startTimestamp = start;
183
  } else {
184
5
    PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*startMark);
185
5
    if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
186
      startTimestamp = milestones[milestone];
187
  }
188
189
10
  uint64_t endTimestamp = GetPerformanceMark(env, *endMark);
190
10
  if (endTimestamp == 0) {
191
    PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*endMark);
192
    if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
193
      endTimestamp = milestones[milestone];
194
  }
195
196
10
  if (endTimestamp < startTimestamp)
197
    endTimestamp = startTimestamp;
198
199

20
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
200
      TRACING_CATEGORY_NODE2(perf, usertiming),
201
      *name, *name, startTimestamp / 1000);
202

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

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

14
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
334
      TRACING_CATEGORY_NODE2(perf, timerify),
335
      *name, *name, start / 1000);
336
  v8::MaybeLocal<Value> ret;
337
338
7
  if (is_construct_call) {
339
2
    ret = fn->NewInstance(context, call_args.length(), call_args.out())
340
2
        .FromMaybe(Local<Object>());
341
  } else {
342
12
    ret = fn->Call(context, args.This(), call_args.length(), call_args.out());
343
  }
344
345
7
  uint64_t end = PERFORMANCE_NOW();
346

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

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

3724
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
494
                 "min", histogram->Min());
495

3724
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
496
                 "max", histogram->Max());
497

3724
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
498
                 "mean", histogram->Mean());
499

3724
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
500
                 "stddev", histogram->Stddev());
501
1862
}
502
503
1862
bool ELDHistogram::RecordDelta() {
504
1862
  uint64_t time = uv_hrtime();
505
1862
  bool ret = true;
506
1862
  if (prev_ > 0) {
507
1861
    int64_t delta = time - prev_;
508
1861
    if (delta > 0) {
509
1861
      ret = Record(delta);
510

3722
      TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
511
                     "delay", delta);
512
1861
      if (!ret) {
513
        if (exceeds_ < 0xFFFFFFFF)
514
          exceeds_++;
515
        ProcessEmitWarning(
516
            env(),
517
            "Event loop delay exceeded 1 hour: %" PRId64 " nanoseconds",
518
            delta);
519
      }
520
    }
521
  }
522
1862
  prev_ = time;
523
1862
  return ret;
524
}
525
526
3
bool ELDHistogram::Enable() {
527

3
  if (enabled_ || IsHandleClosing()) return false;
528
2
  enabled_ = true;
529
2
  prev_ = 0;
530
  uv_timer_start(&timer_,
531
                 DelayIntervalCallback,
532
                 resolution_,
533
2
                 resolution_);
534
2
  uv_unref(reinterpret_cast<uv_handle_t*>(&timer_));
535
2
  return true;
536
}
537
538
3
bool ELDHistogram::Disable() {
539

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

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