GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_perf.cc Lines: 201 219 91.8 %
Date: 2019-01-07 12:15:22 Branches: 67 92 72.8 %

Line Branch Exec Source
1
#include "node_internals.h"
2
#include "node_perf.h"
3
4
#ifdef __POSIX__
5
#include <sys/time.h>  // gettimeofday
6
#endif
7
8
namespace node {
9
namespace performance {
10
11
using v8::Array;
12
using v8::Context;
13
using v8::DontDelete;
14
using v8::Function;
15
using v8::FunctionCallbackInfo;
16
using v8::FunctionTemplate;
17
using v8::GCCallbackFlags;
18
using v8::GCType;
19
using v8::HandleScope;
20
using v8::Integer;
21
using v8::Isolate;
22
using v8::Local;
23
using v8::Name;
24
using v8::NewStringType;
25
using v8::Number;
26
using v8::Object;
27
using v8::PropertyAttribute;
28
using v8::ReadOnly;
29
using v8::String;
30
using v8::Uint32Array;
31
using v8::Value;
32
33
// Microseconds in a second, as a float.
34
#define MICROS_PER_SEC 1e6
35
// Microseconds in a millisecond, as a float.
36
#define MICROS_PER_MILLIS 1e3
37
38
// https://w3c.github.io/hr-time/#dfn-time-origin
39
3597
const uint64_t timeOrigin = PERFORMANCE_NOW();
40
// https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
41
3597
const double timeOriginTimestamp = GetCurrentTimeInMicroseconds();
42
uint64_t performance_node_start;
43
uint64_t performance_v8_start;
44
45
21494
void performance_state::Mark(enum PerformanceMilestone milestone,
46
                             uint64_t ts) {
47
21494
  this->milestones[milestone] = ts;
48

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

132
  if (type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID &&
134
132
      observers[type]) {
135
    node::MakeCallback(env->isolate(),
136
                       object.As<Object>(),
137
                       env->performance_entry_callback(),
138
                       1, &object,
139
26
                       node::async_context{0, 0});
140
  }
141
33
}
142
143
// Create a User Timing Mark
144
17
void Mark(const FunctionCallbackInfo<Value>& args) {
145
17
  Environment* env = Environment::GetCurrent(args);
146
17
  HandleScope scope(env->isolate());
147
34
  Utf8Value name(env->isolate(), args[0]);
148
17
  uint64_t now = PERFORMANCE_NOW();
149
17
  auto marks = env->performance_marks();
150
17
  (*marks)[*name] = now;
151
152

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

9
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
213
      TRACING_CATEGORY_NODE2(perf, usertiming),
214
      *name, *name, startTimestamp / 1000);
215

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

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

6
  TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
331
      TRACING_CATEGORY_NODE2(perf, timerify),
332
      *name, *name, start / 1000);
333
  v8::MaybeLocal<Value> ret;
334
335
6
  if (is_construct_call) {
336
2
    ret = fn->NewInstance(context, call_args.size(), call_args.data())
337
1
        .FromMaybe(Local<Object>());
338
  } else {
339
10
    ret = fn->Call(context, args.This(), call_args.size(), call_args.data());
340
  }
341
342
6
  uint64_t end = PERFORMANCE_NOW();
343

6
  TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
344
      TRACING_CATEGORY_NODE2(perf, timerify),
345
      *name, *name, end / 1000);
346
347
6
  if (ret.IsEmpty())
348
1
    return;
349
10
  args.GetReturnValue().Set(ret.ToLocalChecked());
350
351
  AliasedBuffer<uint32_t, Uint32Array>& observers =
352
5
      env->performance_state()->observers;
353
5
  if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION])
354
3
    return;
355
356
4
  PerformanceEntry entry(env, *name, "function", start, end);
357
2
  Local<Object> obj = entry.ToObject();
358
4
  for (idx = 0; idx < count; idx++)
359
8
    obj->Set(context, idx, args[idx]).FromJust();
360
4
  PerformanceEntry::Notify(env, entry.kind(), obj);
361
}
362
363
// Wraps a Function in a TimerFunctionCall
364
7
void Timerify(const FunctionCallbackInfo<Value>& args) {
365
7
  Environment* env = Environment::GetCurrent(args);
366
7
  Local<Context> context = env->context();
367
14
  CHECK(args[0]->IsFunction());
368
14
  CHECK(args[1]->IsNumber());
369
14
  Local<Function> fn = args[0].As<Function>();
370
21
  int length = args[1]->IntegerValue(context).ToChecked();
371
  Local<Function> wrap =
372
14
      Function::New(context, TimerFunctionCall, fn, length).ToLocalChecked();
373
14
  args.GetReturnValue().Set(wrap);
374
7
}
375
376
377
3659
void Initialize(Local<Object> target,
378
                Local<Value> unused,
379
                Local<Context> context,
380
                void* priv) {
381
3659
  Environment* env = Environment::GetCurrent(context);
382
3659
  Isolate* isolate = env->isolate();
383
3659
  performance_state* state = env->performance_state();
384
385
  target->Set(context,
386
              FIXED_ONE_BYTE_STRING(isolate, "observerCounts"),
387
14636
              state->observers.GetJSArray()).FromJust();
388
  target->Set(context,
389
              FIXED_ONE_BYTE_STRING(isolate, "milestones"),
390
14636
              state->milestones.GetJSArray()).FromJust();
391
392
  Local<String> performanceEntryString =
393
3659
      FIXED_ONE_BYTE_STRING(isolate, "PerformanceEntry");
394
395
3659
  Local<FunctionTemplate> pe = FunctionTemplate::New(isolate);
396
3659
  pe->SetClassName(performanceEntryString);
397
7318
  Local<Function> fn = pe->GetFunction(context).ToLocalChecked();
398
7318
  target->Set(context, performanceEntryString, fn).FromJust();
399
3659
  env->set_performance_entry_template(fn);
400
401
3659
  env->SetMethod(target, "clearMark", ClearMark);
402
3659
  env->SetMethod(target, "mark", Mark);
403
3659
  env->SetMethod(target, "measure", Measure);
404
3659
  env->SetMethod(target, "markMilestone", MarkMilestone);
405
3659
  env->SetMethod(target, "setupObservers", SetupPerformanceObservers);
406
3659
  env->SetMethod(target, "timerify", Timerify);
407
408
3659
  Local<Object> constants = Object::New(isolate);
409
410
14636
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MAJOR);
411
14636
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MINOR);
412
14636
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_INCREMENTAL);
413
14636
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_WEAKCB);
414
415
#define V(name, _)                                                            \
416
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_ENTRY_TYPE_##name);
417
87816
  NODE_PERFORMANCE_ENTRY_TYPES(V)
418
#undef V
419
420
#define V(name, _)                                                            \
421
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_MILESTONE_##name);
422
87816
  NODE_PERFORMANCE_MILESTONES(V)
423
#undef V
424
425
  PropertyAttribute attr =
426
3659
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
427
428
  target->DefineOwnProperty(context,
429
                            FIXED_ONE_BYTE_STRING(isolate, "timeOrigin"),
430
                            Number::New(isolate, timeOrigin / 1e6),
431
14636
                            attr).ToChecked();
432
433
  target->DefineOwnProperty(
434
      context,
435
      FIXED_ONE_BYTE_STRING(isolate, "timeOriginTimestamp"),
436
      Number::New(isolate, timeOriginTimestamp / MICROS_PER_MILLIS),
437
14636
      attr).ToChecked();
438
439
  target->DefineOwnProperty(context,
440
                            env->constants_string(),
441
                            constants,
442
10977
                            attr).ToChecked();
443
444
3659
  SetupGarbageCollectionTracking(env);
445
3659
}
446
447
}  // namespace performance
448
}  // namespace node
449
450

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