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: 190 208 91.3 %
Date: 2021-05-29 04:12:01 Branches: 37 58 63.8 %

Line Branch Exec Source
1
#include "aliased_buffer.h"
2
#include "env-inl.h"
3
#include "histogram-inl.h"
4
#include "memory_tracker-inl.h"
5
#include "node_internals.h"
6
#include "node_perf.h"
7
#include "node_buffer.h"
8
#include "node_process-inl.h"
9
#include "util-inl.h"
10
11
#include <cinttypes>
12
13
namespace node {
14
namespace performance {
15
16
using v8::Context;
17
using v8::DontDelete;
18
using v8::Function;
19
using v8::FunctionCallbackInfo;
20
using v8::FunctionTemplate;
21
using v8::GCCallbackFlags;
22
using v8::GCType;
23
using v8::Int32;
24
using v8::Integer;
25
using v8::Isolate;
26
using v8::Local;
27
using v8::MaybeLocal;
28
using v8::Number;
29
using v8::Object;
30
using v8::PropertyAttribute;
31
using v8::ReadOnly;
32
using v8::String;
33
using v8::Value;
34
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
4840
const uint64_t timeOrigin = PERFORMANCE_NOW();
40
// https://w3c.github.io/hr-time/#dfn-time-origin-timestamp
41
4840
const double timeOriginTimestamp = GetCurrentTimeInMicroseconds();
42
uint64_t performance_v8_start;
43
44
5235
PerformanceState::PerformanceState(Isolate* isolate,
45
5235
                                   const PerformanceState::SerializeInfo* info)
46
    : root(isolate,
47
           sizeof(performance_state_internal),
48
           MAYBE_FIELD_PTR(info, root)),
49
      milestones(isolate,
50
                 offsetof(performance_state_internal, milestones),
51
                 NODE_PERFORMANCE_MILESTONE_INVALID,
52
                 root,
53
                 MAYBE_FIELD_PTR(info, milestones)),
54
      observers(isolate,
55
                offsetof(performance_state_internal, observers),
56
                NODE_PERFORMANCE_ENTRY_TYPE_INVALID,
57
                root,
58

5235
                MAYBE_FIELD_PTR(info, observers)) {
59
5235
  if (info == nullptr) {
60
469
    for (size_t i = 0; i < milestones.Length(); i++) milestones[i] = -1.;
61
  }
62
5235
}
63
64
8
PerformanceState::SerializeInfo PerformanceState::Serialize(
65
    v8::Local<v8::Context> context, v8::SnapshotCreator* creator) {
66
8
  SerializeInfo info{root.Serialize(context, creator),
67
8
                     milestones.Serialize(context, creator),
68
16
                     observers.Serialize(context, creator)};
69
8
  return info;
70
}
71
72
4766
void PerformanceState::Deserialize(v8::Local<v8::Context> context) {
73
4766
  root.Deserialize(context);
74
  // This is just done to set up the pointers, we will actually reset
75
  // all the milestones after deserialization.
76
4766
  milestones.Deserialize(context);
77
4766
  observers.Deserialize(context);
78
4766
}
79
80
8
std::ostream& operator<<(std::ostream& o,
81
                         const PerformanceState::SerializeInfo& i) {
82
  o << "{\n"
83
8
    << "  " << i.root << ",  // root\n"
84
16
    << "  " << i.milestones << ",  // milestones\n"
85
16
    << "  " << i.observers << ",  // observers\n"
86
8
    << "}";
87
8
  return o;
88
}
89
90
30512
void PerformanceState::Mark(PerformanceMilestone milestone, uint64_t ts) {
91
30512
  this->milestones[milestone] = static_cast<double>(ts);
92
  TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
93
30512
      TRACING_CATEGORY_NODE1(bootstrap),
94
      GetPerformanceMilestoneName(milestone),
95
4783
      TRACE_EVENT_SCOPE_THREAD, ts / 1000);
96
61024
}
97
46
98
// Allows specific Node.js lifecycle milestones to be set from JavaScript
99
46
void MarkMilestone(const FunctionCallbackInfo<Value>& args) {
100
  Environment* env = Environment::GetCurrent(args);
101
  PerformanceMilestone milestone =
102
      static_cast<PerformanceMilestone>(args[0].As<Int32>()->Value());
103
  if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
104
    env->performance_state()->Mark(milestone);
105
}
106
107
4162
void SetupPerformanceObservers(const FunctionCallbackInfo<Value>& args) {
108
4162
  Environment* env = Environment::GetCurrent(args);
109
8324
  CHECK(args[0]->IsFunction());
110
8324
  env->set_performance_entry_callback(args[0].As<Function>());
111
4162
}
112
113
// Marks the start of a GC cycle
114
1
void MarkGarbageCollectionStart(
115
    Isolate* isolate,
116
    GCType type,
117
    GCCallbackFlags flags,
118
    void* data) {
119
1
  Environment* env = static_cast<Environment*>(data);
120
1
  env->performance_state()->performance_last_gc_start_mark = PERFORMANCE_NOW();
121
1
}
122
123
1
MaybeLocal<Object> GCPerformanceEntryTraits::GetDetails(
124
    Environment* env,
125
    const GCPerformanceEntry& entry) {
126
1
  Local<Object> obj = Object::New(env->isolate());
127
128
3
  if (!obj->Set(
129
          env->context(),
130
          env->kind_string(),
131
          Integer::NewFromUnsigned(
132
              env->isolate(),
133
6
              entry.details.kind)).IsJust()) {
134
    return MaybeLocal<Object>();
135
  }
136
137
3
  if (!obj->Set(
138
          env->context(),
139
          env->flags_string(),
140
          Integer::NewFromUnsigned(
141
              env->isolate(),
142
6
              entry.details.flags)).IsJust()) {
143
    return MaybeLocal<Object>();
144
  }
145
146
1
  return obj;
147
}
148
149
// Marks the end of a GC cycle
150
1
void MarkGarbageCollectionEnd(
151
    Isolate* isolate,
152
    GCType type,
153
    GCCallbackFlags flags,
154
    void* data) {
155
1
  Environment* env = static_cast<Environment*>(data);
156
1
  PerformanceState* state = env->performance_state();
157
  // If no one is listening to gc performance entries, do not create them.
158
1
  if (LIKELY(!state->observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]))
159
    return;
160
161
1
  double start_time = state->performance_last_gc_start_mark / 1e6;
162
1
  double duration = (PERFORMANCE_NOW() / 1e6) - start_time;
163
164
  std::unique_ptr<GCPerformanceEntry> entry =
165
      std::make_unique<GCPerformanceEntry>(
166
          "gc",
167
          start_time,
168
          duration,
169
2
          GCPerformanceEntry::Details(
170
            static_cast<PerformanceGCKind>(type),
171
2
            static_cast<PerformanceGCFlags>(flags)));
172
173
6
  env->SetImmediate([entry = std::move(entry)](Environment* env) {
174
1
    entry->Notify(env);
175
2
  }, CallbackFlags::kUnrefed);
176
}
177
178
2
void GarbageCollectionCleanupHook(void* data) {
179
2
  Environment* env = static_cast<Environment*>(data);
180
2
  env->isolate()->RemoveGCPrologueCallback(MarkGarbageCollectionStart, data);
181
2
  env->isolate()->RemoveGCEpilogueCallback(MarkGarbageCollectionEnd, data);
182
2
}
183
184
2
static void InstallGarbageCollectionTracking(
185
    const FunctionCallbackInfo<Value>& args) {
186
2
  Environment* env = Environment::GetCurrent(args);
187
188
2
  env->isolate()->AddGCPrologueCallback(MarkGarbageCollectionStart,
189
2
                                        static_cast<void*>(env));
190
2
  env->isolate()->AddGCEpilogueCallback(MarkGarbageCollectionEnd,
191
2
                                        static_cast<void*>(env));
192
2
  env->AddCleanupHook(GarbageCollectionCleanupHook, env);
193
2
}
194
195
1
static void RemoveGarbageCollectionTracking(
196
  const FunctionCallbackInfo<Value> &args) {
197
1
  Environment* env = Environment::GetCurrent(args);
198
199
1
  env->RemoveCleanupHook(GarbageCollectionCleanupHook, env);
200
1
  GarbageCollectionCleanupHook(env);
201
1
}
202
203
// Gets the name of a function
204
inline Local<Value> GetName(Local<Function> fn) {
205
  Local<Value> val = fn->GetDebugName();
206
  if (val.IsEmpty() || val->IsUndefined()) {
207
    Local<Value> boundFunction = fn->GetBoundFunction();
208
    if (!boundFunction.IsEmpty() && !boundFunction->IsUndefined()) {
209
      val = GetName(boundFunction.As<Function>());
210
    }
211
  }
212
  return val;
213
}
214
215
// Notify a custom PerformanceEntry to observers
216
void Notify(const FunctionCallbackInfo<Value>& args) {
217
  Environment* env = Environment::GetCurrent(args);
218
  Utf8Value type(env->isolate(), args[0]);
219
  Local<Value> entry = args[1];
220
  PerformanceEntryType entry_type = ToPerformanceEntryTypeEnum(*type);
221
  AliasedUint32Array& observers = env->performance_state()->observers;
222
  if (entry_type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID &&
223
      observers[entry_type]) {
224
    USE(env->performance_entry_callback()->
225
      Call(env->context(), Undefined(env->isolate()), 1, &entry));
226
  }
227
}
228
229
// Return idle time of the event loop
230
48
void LoopIdleTime(const FunctionCallbackInfo<Value>& args) {
231
48
  Environment* env = Environment::GetCurrent(args);
232
48
  uint64_t idle_time = uv_metrics_idle_time(env->event_loop());
233
144
  args.GetReturnValue().Set(1.0 * idle_time / 1e6);
234
48
}
235
236
// Event Loop Timing Histogram
237
3
void ELDHistogram::New(const FunctionCallbackInfo<Value>& args) {
238
3
  Environment* env = Environment::GetCurrent(args);
239
3
  CHECK(args.IsConstructCall());
240
9
  int64_t resolution = args[0].As<Integer>()->Value();
241
3
  CHECK_GT(resolution, 0);
242
3
  new ELDHistogram(env, args.This(), resolution);
243
3
}
244
245
4469
void ELDHistogram::Initialize(Environment* env, Local<Object> target) {
246
4469
  Local<FunctionTemplate> tmpl = env->NewFunctionTemplate(New);
247
8938
  tmpl->Inherit(IntervalHistogram::GetConstructorTemplate(env));
248
13407
  tmpl->InstanceTemplate()->SetInternalFieldCount(
249
4469
      ELDHistogram::kInternalFieldCount);
250
4469
  env->SetConstructorFunction(target, "ELDHistogram", tmpl);
251
4469
}
252
253
3
ELDHistogram::ELDHistogram(
254
    Environment* env,
255
    Local<Object> wrap,
256
3
    int64_t interval)
257
    : IntervalHistogram(
258
          env,
259
          wrap,
260
          AsyncWrap::PROVIDER_ELDHISTOGRAM,
261
3
          interval, 1, 3.6e12, 3) {}
262
263
1769
void ELDHistogram::OnInterval() {
264
1769
  uint64_t delta = histogram()->RecordDelta();
265
1769
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
266
                  "delay", delta);
267
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
268
1771
                 "min", histogram()->Min());
269
3540
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
270
3540
                 "max", histogram()->Max());
271
3540
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
272
3540
                 "mean", histogram()->Mean());
273
3540
  TRACE_COUNTER1(TRACING_CATEGORY_NODE2(perf, event_loop),
274
3540
                 "stddev", histogram()->Stddev());
275
5309
}
276
1771
277
8009
void Initialize(Local<Object> target,
278
1769
                Local<Value> unused,
279
                Local<Context> context,
280
                void* priv) {
281
4469
  Environment* env = Environment::GetCurrent(context);
282
4469
  Isolate* isolate = env->isolate();
283
4469
  PerformanceState* state = env->performance_state();
284
285
8938
  target->Set(context,
286
              FIXED_ONE_BYTE_STRING(isolate, "observerCounts"),
287
17876
              state->observers.GetJSArray()).Check();
288
8938
  target->Set(context,
289
              FIXED_ONE_BYTE_STRING(isolate, "milestones"),
290
17876
              state->milestones.GetJSArray()).Check();
291
292
  Local<String> performanceEntryString =
293
4469
      FIXED_ONE_BYTE_STRING(isolate, "PerformanceEntry");
294
295
4469
  Local<FunctionTemplate> pe = FunctionTemplate::New(isolate);
296
4469
  pe->SetClassName(performanceEntryString);
297
8938
  Local<Function> fn = pe->GetFunction(context).ToLocalChecked();
298
8938
  target->Set(context, performanceEntryString, fn).Check();
299
4469
  env->set_performance_entry_template(fn);
300
301
4469
  env->SetMethod(target, "markMilestone", MarkMilestone);
302
4469
  env->SetMethod(target, "setupObservers", SetupPerformanceObservers);
303
  env->SetMethod(target,
304
                 "installGarbageCollectionTracking",
305
4469
                 InstallGarbageCollectionTracking);
306
  env->SetMethod(target,
307
                 "removeGarbageCollectionTracking",
308
4469
                 RemoveGarbageCollectionTracking);
309
4469
  env->SetMethod(target, "notify", Notify);
310
4469
  env->SetMethod(target, "loopIdleTime", LoopIdleTime);
311
312
4469
  Local<Object> constants = Object::New(isolate);
313
314
4469
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MAJOR);
315
13407
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MINOR);
316
22345
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_INCREMENTAL);
317
26814
  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_WEAKCB);
318
26814
319
26814
  NODE_DEFINE_CONSTANT(
320
22345
    constants, NODE_PERFORMANCE_GC_FLAGS_NO);
321
17876
  NODE_DEFINE_CONSTANT(
322
13407
    constants, NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED);
323
17876
  NODE_DEFINE_CONSTANT(
324
13407
    constants, NODE_PERFORMANCE_GC_FLAGS_FORCED);
325
22345
  NODE_DEFINE_CONSTANT(
326
13407
    constants, NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING);
327
17876
  NODE_DEFINE_CONSTANT(
328
13407
    constants, NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE);
329
22345
  NODE_DEFINE_CONSTANT(
330
22345
    constants, NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY);
331
22345
  NODE_DEFINE_CONSTANT(
332
13407
    constants, NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE);
333
17876
334
4469
#define V(name, _)                                                            \
335
13407
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_ENTRY_TYPE_##name);
336
4469
  NODE_PERFORMANCE_ENTRY_TYPES(V)
337
8938
#undef V
338
4469
339
4469
#define V(name, _)                                                            \
340
13407
  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_MILESTONE_##name);
341
8938
  NODE_PERFORMANCE_MILESTONES(V)
342
17876
#undef V
343
8938
344
8938
  PropertyAttribute attr =
345
31283
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
346
8938
347
26814
  target->DefineOwnProperty(context,
348
8938
                            FIXED_ONE_BYTE_STRING(isolate, "timeOrigin"),
349
8938
                            Number::New(isolate, timeOrigin / 1e6),
350
44690
                            attr).ToChecked();
351
4469
352
17876
  target->DefineOwnProperty(
353
4469
      context,
354
4469
      FIXED_ONE_BYTE_STRING(isolate, "timeOriginTimestamp"),
355
13407
      Number::New(isolate, timeOriginTimestamp / MICROS_PER_MILLIS),
356
22345
      attr).ToChecked();
357
8938
358
13407
  target->DefineOwnProperty(context,
359
4469
                            env->constants_string(),
360
13407
                            constants,
361
26814
                            attr).ToChecked();
362
8938
363
8938
  HistogramBase::Initialize(env, target);
364
8938
  ELDHistogram::Initialize(env, target);
365
17876
}
366
13407
367
8938
}  // namespace performance
368
4469
}  // namespace node
369
4469
370

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