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: 209 219 95.4 %
Date: 2017-11-19 Branches: 48 78 61.5 %

Line Branch Exec Source
1
#include "node_internals.h"
2
#include "node_perf.h"
3
4
#include <vector>
5
6
namespace node {
7
namespace performance {
8
9
using v8::Array;
10
using v8::ArrayBuffer;
11
using v8::Context;
12
using v8::Function;
13
using v8::FunctionCallbackInfo;
14
using v8::FunctionTemplate;
15
using v8::HandleScope;
16
using v8::Integer;
17
using v8::Isolate;
18
using v8::Local;
19
using v8::Name;
20
using v8::Object;
21
using v8::ObjectTemplate;
22
using v8::PropertyCallbackInfo;
23
using v8::String;
24
using v8::Value;
25
26
3333
const uint64_t timeOrigin = PERFORMANCE_NOW();
27
uint64_t performance_node_start;
28
uint64_t performance_v8_start;
29
30
uint64_t performance_last_gc_start_mark_ = 0;
31
v8::GCType performance_last_gc_type_ = v8::GCType::kGCTypeAll;
32
33
20
void PerformanceEntry::New(const FunctionCallbackInfo<Value>& args) {
34
20
  Environment* env = Environment::GetCurrent(args);
35
20
  Isolate* isolate = env->isolate();
36
20
  Utf8Value name(isolate, args[0]);
37
40
  Utf8Value type(isolate, args[1]);
38
20
  uint64_t now = PERFORMANCE_NOW();
39
40
  new PerformanceEntry(env, args.This(), *name, *type, now, now);
40
20
}
41
42
40
void PerformanceEntry::NotifyObservers(Environment* env,
43
                                       PerformanceEntry* entry) {
44
40
  uint32_t* observers = env->performance_state()->observers;
45
40
  PerformanceEntryType type = ToPerformanceEntryTypeEnum(entry->type().c_str());
46

40
  if (observers == nullptr ||
47
20
      type == NODE_PERFORMANCE_ENTRY_TYPE_INVALID ||
48
20
      !observers[type]) {
49
60
    return;
50
  }
51
20
  Local<Context> context = env->context();
52
20
  Isolate* isolate = env->isolate();
53
20
  Local<Value> argv = entry->object();
54
  env->performance_entry_callback()->Call(context,
55
                                          v8::Undefined(isolate),
56
60
                                          1, &argv).ToLocalChecked();
57
}
58
59
10
void Mark(const FunctionCallbackInfo<Value>& args) {
60
10
  Environment* env = Environment::GetCurrent(args);
61
10
  Local<Context> context = env->context();
62
10
  Isolate* isolate = env->isolate();
63
10
  Utf8Value name(isolate, args[0]);
64
10
  uint64_t now = PERFORMANCE_NOW();
65
10
  auto marks = env->performance_marks();
66
10
  (*marks)[*name] = now;
67
68
  // TODO(jasnell): Once Tracing API is fully implemented, this should
69
  // record a trace event also.
70
71
10
  Local<Function> fn = env->performance_entry_template();
72
20
  Local<Object> obj = fn->NewInstance(context).ToLocalChecked();
73
10
  new PerformanceEntry(env, obj, *name, "mark", now, now);
74
20
  args.GetReturnValue().Set(obj);
75
10
}
76
77
14
inline uint64_t GetPerformanceMark(Environment* env, std::string name) {
78
14
  auto marks = env->performance_marks();
79
14
  auto res = marks->find(name);
80
14
  return res != marks->end() ? res->second : 0;
81
}
82
83
7
void Measure(const FunctionCallbackInfo<Value>& args) {
84
7
  Environment* env = Environment::GetCurrent(args);
85
7
  Local<Context> context = env->context();
86
7
  Isolate* isolate = env->isolate();
87
7
  Utf8Value name(isolate, args[0]);
88
14
  Utf8Value startMark(isolate, args[1]);
89
14
  Utf8Value endMark(isolate, args[2]);
90
91
7
  double* milestones = env->performance_state()->milestones;
92
93
7
  uint64_t startTimestamp = timeOrigin;
94
7
  uint64_t start = GetPerformanceMark(env, *startMark);
95
7
  if (start != 0) {
96
2
    startTimestamp = start;
97
  } else {
98
5
    PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*startMark);
99
5
    if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
100
      startTimestamp = milestones[milestone];
101
  }
102
103
7
  uint64_t endTimestamp = GetPerformanceMark(env, *endMark);
104
7
  if (endTimestamp == 0) {
105
    PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*endMark);
106
    if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
107
      endTimestamp = milestones[milestone];
108
  }
109
110
7
  if (endTimestamp < startTimestamp)
111
    endTimestamp = startTimestamp;
112
113
  // TODO(jasnell): Once Tracing API is fully implemented, this should
114
  // record a trace event also.
115
116
7
  Local<Function> fn = env->performance_entry_template();
117
14
  Local<Object> obj = fn->NewInstance(context).ToLocalChecked();
118
  new PerformanceEntry(env, obj, *name, "measure",
119
7
                       startTimestamp, endTimestamp);
120
21
  args.GetReturnValue().Set(obj);
121
7
}
122
123
28
void GetPerformanceEntryName(const Local<String> prop,
124
                             const PropertyCallbackInfo<Value>& info) {
125
28
  Isolate* isolate = info.GetIsolate();
126
  PerformanceEntry* entry;
127
56
  ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
128
  info.GetReturnValue().Set(
129
84
    String::NewFromUtf8(isolate, entry->name().c_str(), String::kNormalString));
130
}
131
132
56
void GetPerformanceEntryType(const Local<String> prop,
133
                             const PropertyCallbackInfo<Value>& info) {
134
56
  Isolate* isolate = info.GetIsolate();
135
  PerformanceEntry* entry;
136
112
  ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
137
  info.GetReturnValue().Set(
138
168
    String::NewFromUtf8(isolate, entry->type().c_str(), String::kNormalString));
139
}
140
141
28
void GetPerformanceEntryStartTime(const Local<String> prop,
142
                                  const PropertyCallbackInfo<Value>& info) {
143
  PerformanceEntry* entry;
144
56
  ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
145
84
  info.GetReturnValue().Set(entry->startTime());
146
}
147
148
3
void GetPerformanceEntryDuration(const Local<String> prop,
149
                                 const PropertyCallbackInfo<Value>& info) {
150
  PerformanceEntry* entry;
151
6
  ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
152
9
  info.GetReturnValue().Set(entry->duration());
153
}
154
155
16345
void MarkMilestone(const FunctionCallbackInfo<Value>& args) {
156
16345
  Environment* env = Environment::GetCurrent(args);
157
16345
  Local<Context> context = env->context();
158
16345
  double* milestones = env->performance_state()->milestones;
159
  PerformanceMilestone milestone =
160
      static_cast<PerformanceMilestone>(
161
49035
          args[0]->Int32Value(context).ToChecked());
162
16345
  if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID) {
163
16345
    milestones[milestone] = PERFORMANCE_NOW();
164
  }
165
16345
}
166
167
3287
void SetupPerformanceObservers(const FunctionCallbackInfo<Value>& args) {
168
3287
  Environment* env = Environment::GetCurrent(args);
169
6574
  CHECK(args[0]->IsFunction());
170
6574
  env->set_performance_entry_callback(args[0].As<Function>());
171
3287
}
172
173
8704
void PerformanceGCCallback(uv_async_t* handle) {
174
  PerformanceEntry::Data* data =
175
8704
      static_cast<PerformanceEntry::Data*>(handle->data);
176
8704
  Environment* env = data->env();
177
8704
  Isolate* isolate = env->isolate();
178
8704
  HandleScope scope(isolate);
179
8704
  Local<Context> context = env->context();
180
  Context::Scope context_scope(context);
181
  Local<Function> fn;
182
  Local<Object> obj;
183
8704
  PerformanceGCKind kind = static_cast<PerformanceGCKind>(data->data());
184
185
8704
  uint32_t* observers = env->performance_state()->observers;
186
8704
  if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) {
187
8703
    goto cleanup;
188
  }
189
190
1
  fn = env->performance_entry_template();
191
2
  obj = fn->NewInstance(context).ToLocalChecked();
192
  obj->Set(context,
193
           FIXED_ONE_BYTE_STRING(isolate, "kind"),
194
4
           Integer::New(isolate, kind)).FromJust();
195
1
  new PerformanceEntry(env, obj, data);
196
197
 cleanup:
198
8704
  delete data;
199
25912
  auto closeCB = [](uv_handle_t* handle) {
200
8604
    delete reinterpret_cast<uv_async_t*>(handle);
201
25912
  };
202
17408
  uv_close(reinterpret_cast<uv_handle_t*>(handle), closeCB);
203
8704
}
204
205
17664
void MarkGarbageCollectionStart(Isolate* isolate,
206
                                v8::GCType type,
207
                                v8::GCCallbackFlags flags) {
208
17664
  performance_last_gc_start_mark_ = PERFORMANCE_NOW();
209
17664
  performance_last_gc_type_ = type;
210
17664
}
211
212
17664
void MarkGarbageCollectionEnd(Isolate* isolate,
213
                              v8::GCType type,
214
                              v8::GCCallbackFlags flags,
215
                              void* data) {
216
17664
  Environment* env = static_cast<Environment*>(data);
217
17664
  uv_async_t* async = new uv_async_t();  // coverity[leaked_storage]
218
17664
  if (uv_async_init(env->event_loop(), async, PerformanceGCCallback))
219
17664
    return delete async;
220
17664
  uv_unref(reinterpret_cast<uv_handle_t*>(async));
221
  async->data =
222
      new PerformanceEntry::Data(env, "gc", "gc",
223
                                 performance_last_gc_start_mark_,
224
17664
                                 PERFORMANCE_NOW(), type);
225
17664
  CHECK_EQ(0, uv_async_send(async));
226
}
227
228
3287
inline void SetupGarbageCollectionTracking(Environment* env) {
229
3287
  env->isolate()->AddGCPrologueCallback(MarkGarbageCollectionStart);
230
  env->isolate()->AddGCEpilogueCallback(MarkGarbageCollectionEnd,
231
3287
                                        static_cast<void*>(env));
232
3287
}
233
234
5
inline Local<Value> GetName(Local<Function> fn) {
235
5
  Local<Value> val = fn->GetDebugName();
236

15
  if (val.IsEmpty() || val->IsUndefined()) {
237
    Local<Value> boundFunction = fn->GetBoundFunction();
238
    if (!boundFunction.IsEmpty() && !boundFunction->IsUndefined()) {
239
      val = GetName(boundFunction.As<Function>());
240
    }
241
  }
242
5
  return val;
243
}
244
245
5
void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
246
5
  Isolate* isolate = args.GetIsolate();
247
5
  HandleScope scope(isolate);
248
5
  Environment* env = Environment::GetCurrent(isolate);
249
5
  Local<Context> context = env->context();
250
10
  Local<Function> fn = args.Data().As<Function>();
251
5
  size_t count = args.Length();
252
  size_t idx;
253
7
  std::vector<Local<Value>> call_args;
254
7
  for (size_t i = 0; i < count; ++i) {
255
4
    call_args.push_back(args[i]);
256
  }
257
258
7
  Utf8Value name(isolate, GetName(fn));
259
260
  uint64_t start;
261
  uint64_t end;
262
7
  v8::TryCatch try_catch(isolate);
263
5
  if (args.IsConstructCall()) {
264
2
    start = PERFORMANCE_NOW();
265
    v8::MaybeLocal<Object> ret = fn->NewInstance(context,
266
2
                                                 call_args.size(),
267
6
                                                 call_args.data());
268
2
    end = PERFORMANCE_NOW();
269
2
    if (ret.IsEmpty()) {
270
      try_catch.ReThrow();
271
      return;
272
    }
273
4
    args.GetReturnValue().Set(ret.ToLocalChecked());
274
  } else {
275
3
    start = PERFORMANCE_NOW();
276
    v8::MaybeLocal<Value> ret = fn->Call(context,
277
                                         args.This(),
278
3
                                         call_args.size(),
279
9
                                         call_args.data());
280
3
    end = PERFORMANCE_NOW();
281
3
    if (ret.IsEmpty()) {
282
1
      try_catch.ReThrow();
283
1
      return;
284
    }
285
4
    args.GetReturnValue().Set(ret.ToLocalChecked());
286
  }
287
288
289
4
  uint32_t* observers = env->performance_state()->observers;
290
4
  if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION])
291
2
    return;
292
293
2
  Local<Function> ctor = env->performance_entry_template();
294
2
  v8::MaybeLocal<Object> instance = ctor->NewInstance(context);
295
2
  Local<Object> obj = instance.ToLocalChecked();
296
4
  for (idx = 0; idx < count; idx++) {
297
8
    obj->Set(context, idx, args[idx]).ToChecked();
298
  }
299
4
  new PerformanceEntry(env, obj, *name, "function", start, end);
300
}
301
302
4
void Timerify(const FunctionCallbackInfo<Value>& args) {
303
4
  Environment* env = Environment::GetCurrent(args);
304
4
  Local<Context> context = env->context();
305
8
  CHECK(args[0]->IsFunction());
306
8
  CHECK(args[1]->IsNumber());
307
8
  Local<Function> fn = args[0].As<Function>();
308
12
  int length = args[1]->IntegerValue(context).ToChecked();
309
  Local<Function> wrap =
310
8
      Function::New(context, TimerFunctionCall, fn, length).ToLocalChecked();
311
8
  args.GetReturnValue().Set(wrap);
312
4
}
313
314
3287
void Init(Local<Object> target,
315
          Local<Value> unused,
316
          Local<Context> context) {
317
3287
  Environment* env = Environment::GetCurrent(context);
318
3287
  Isolate* isolate = env->isolate();
319
3287
  performance_state* state = env->performance_state();
320
3287
  auto state_ab = ArrayBuffer::New(isolate, state, sizeof(*state));
321
322
  #define SET_STATE_TYPEDARRAY(name, type, field)                         \
323
    target->Set(context,                                                  \
324
                FIXED_ONE_BYTE_STRING(isolate, (name)),                   \
325
                type::New(state_ab,                                       \
326
                          offsetof(performance_state, field),             \
327
                          arraysize(state->field)))                       \
328
                                    .FromJust()
329
13148
    SET_STATE_TYPEDARRAY("observerCounts", v8::Uint32Array, observers);
330
13148
    SET_STATE_TYPEDARRAY("milestones", v8::Float64Array, milestones);
331
  #undef SET_STATE_TYPEDARRAY
332
333
  Local<String> performanceEntryString =
334
3287
      FIXED_ONE_BYTE_STRING(isolate, "PerformanceEntry");
335
336
3287
  Local<FunctionTemplate> pe = env->NewFunctionTemplate(PerformanceEntry::New);
337
6574
  pe->InstanceTemplate()->SetInternalFieldCount(1);
338
3287
  pe->SetClassName(performanceEntryString);
339
3287
  Local<ObjectTemplate> ot = pe->InstanceTemplate();
340
6574
  ot->SetAccessor(env->name_string(), GetPerformanceEntryName);
341
  ot->SetAccessor(FIXED_ONE_BYTE_STRING(isolate, "entryType"),
342
6574
                  GetPerformanceEntryType);
343
  ot->SetAccessor(FIXED_ONE_BYTE_STRING(isolate, "startTime"),
344
6574
                  GetPerformanceEntryStartTime);
345
  ot->SetAccessor(FIXED_ONE_BYTE_STRING(isolate, "duration"),
346
6574
                  GetPerformanceEntryDuration);
347
3287
  Local<Function> fn = pe->GetFunction();
348
3287
  target->Set(performanceEntryString, fn);
349
3287
  env->set_performance_entry_template(fn);
350
351
3287
  env->SetMethod(target, "mark", Mark);
352
3287
  env->SetMethod(target, "measure", Measure);
353
3287
  env->SetMethod(target, "markMilestone", MarkMilestone);
354
3287
  env->SetMethod(target, "setupObservers", SetupPerformanceObservers);
355
3287
  env->SetMethod(target, "timerify", Timerify);
356
357
3287
  Local<Object> constants = Object::New(isolate);
358
359
9861
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MAJOR);
360
9861
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MINOR);
361
9861
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_INCREMENTAL);
362
9861
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_WEAKCB);
363
364
#define V(name, _)                                                            \
365
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_ENTRY_TYPE_##name);
366
65740
  NODE_PERFORMANCE_ENTRY_TYPES(V)
367
#undef V
368
369
#define V(name, _)                                                            \
370
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_MILESTONE_##name);
371
184072
  NODE_PERFORMANCE_MILESTONES(V)
372
#undef V
373
374
  v8::PropertyAttribute attr =
375
3287
      static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
376
377
  target->DefineOwnProperty(context,
378
                            FIXED_ONE_BYTE_STRING(isolate, "timeOrigin"),
379
                            v8::Number::New(isolate, timeOrigin / 1e6),
380
13148
                            attr).ToChecked();
381
382
  target->DefineOwnProperty(context,
383
                            env->constants_string(),
384
                            constants,
385
9861
                            attr).ToChecked();
386
387
3287
  SetupGarbageCollectionTracking(env);
388
3287
}
389
390
}  // namespace performance
391
}  // namespace node
392
393

13331
NODE_BUILTIN_MODULE_CONTEXT_AWARE(performance, node::performance::Init)