Node.js  v8.x
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine
node_perf.cc
Go to the documentation of this file.
1 #include "node.h"
2 #include "v8.h"
3 #include "env.h"
4 #include "env-inl.h"
5 #include "node_perf.h"
6 #include "uv.h"
7 
8 #include <vector>
9 
10 namespace node {
11 namespace performance {
12 
13 using v8::Array;
14 using v8::ArrayBuffer;
15 using v8::Context;
16 using v8::Function;
17 using v8::FunctionCallbackInfo;
18 using v8::FunctionTemplate;
19 using v8::HandleScope;
20 using v8::Integer;
21 using v8::Isolate;
22 using v8::Local;
23 using v8::Name;
24 using v8::Object;
25 using v8::ObjectTemplate;
26 using v8::PropertyCallbackInfo;
27 using v8::String;
28 using v8::Value;
29 
30 const uint64_t timeOrigin = PERFORMANCE_NOW();
33 
35 v8::GCType performance_last_gc_type_ = v8::GCType::kGCTypeAll;
36 
37 void PerformanceEntry::New(const FunctionCallbackInfo<Value>& args) {
38  Environment* env = Environment::GetCurrent(args);
39  Isolate* isolate = env->isolate();
40  Utf8Value name(isolate, args[0]);
41  Utf8Value type(isolate, args[1]);
42  uint64_t now = PERFORMANCE_NOW();
43  new PerformanceEntry(env, args.This(), *name, *type, now, now);
44 }
45 
46 void PerformanceEntry::NotifyObservers(Environment* env,
47  PerformanceEntry* entry) {
48  uint32_t* observers = env->performance_state()->observers;
49  PerformanceEntryType type = ToPerformanceEntryTypeEnum(entry->type().c_str());
50  if (observers == nullptr ||
52  !observers[type]) {
53  return;
54  }
55  Local<Context> context = env->context();
56  Isolate* isolate = env->isolate();
57  Local<Value> argv = entry->object();
58  env->performance_entry_callback()->Call(context,
59  v8::Undefined(isolate),
60  1, &argv).ToLocalChecked();
61 }
62 
63 void Mark(const FunctionCallbackInfo<Value>& args) {
64  Environment* env = Environment::GetCurrent(args);
65  Local<Context> context = env->context();
66  Isolate* isolate = env->isolate();
67  Utf8Value name(isolate, args[0]);
68  uint64_t now = PERFORMANCE_NOW();
69  auto marks = env->performance_marks();
70  (*marks)[*name] = now;
71 
72  // TODO(jasnell): Once Tracing API is fully implemented, this should
73  // record a trace event also.
74 
75  Local<Function> fn = env->performance_entry_template();
76  Local<Object> obj = fn->NewInstance(context).ToLocalChecked();
77  new PerformanceEntry(env, obj, *name, "mark", now, now);
78  args.GetReturnValue().Set(obj);
79 }
80 
81 inline uint64_t GetPerformanceMark(Environment* env, std::string name) {
82  auto marks = env->performance_marks();
83  auto res = marks->find(name);
84  return res != marks->end() ? res->second : 0;
85 }
86 
87 void Measure(const FunctionCallbackInfo<Value>& args) {
88  Environment* env = Environment::GetCurrent(args);
89  Local<Context> context = env->context();
90  Isolate* isolate = env->isolate();
91  Utf8Value name(isolate, args[0]);
92  Utf8Value startMark(isolate, args[1]);
93  Utf8Value endMark(isolate, args[2]);
94 
95  double* milestones = env->performance_state()->milestones;
96 
97  uint64_t startTimestamp = timeOrigin;
98  uint64_t start = GetPerformanceMark(env, *startMark);
99  if (start != 0) {
100  startTimestamp = start;
101  } else {
102  PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*startMark);
103  if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
104  startTimestamp = milestones[milestone];
105  }
106 
107  uint64_t endTimestamp = GetPerformanceMark(env, *endMark);
108  if (endTimestamp == 0) {
109  PerformanceMilestone milestone = ToPerformanceMilestoneEnum(*endMark);
110  if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID)
111  endTimestamp = milestones[milestone];
112  }
113 
114  if (endTimestamp < startTimestamp)
115  endTimestamp = startTimestamp;
116 
117  // TODO(jasnell): Once Tracing API is fully implemented, this should
118  // record a trace event also.
119 
120  Local<Function> fn = env->performance_entry_template();
121  Local<Object> obj = fn->NewInstance(context).ToLocalChecked();
122  new PerformanceEntry(env, obj, *name, "measure",
123  startTimestamp, endTimestamp);
124  args.GetReturnValue().Set(obj);
125 }
126 
127 void GetPerformanceEntryName(const Local<String> prop,
128  const PropertyCallbackInfo<Value>& info) {
129  Isolate* isolate = info.GetIsolate();
130  PerformanceEntry* entry;
131  ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
132  info.GetReturnValue().Set(
133  String::NewFromUtf8(isolate, entry->name().c_str(), String::kNormalString));
134 }
135 
136 void GetPerformanceEntryType(const Local<String> prop,
137  const PropertyCallbackInfo<Value>& info) {
138  Isolate* isolate = info.GetIsolate();
139  PerformanceEntry* entry;
140  ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
141  info.GetReturnValue().Set(
142  String::NewFromUtf8(isolate, entry->type().c_str(), String::kNormalString));
143 }
144 
145 void GetPerformanceEntryStartTime(const Local<String> prop,
146  const PropertyCallbackInfo<Value>& info) {
147  PerformanceEntry* entry;
148  ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
149  info.GetReturnValue().Set(entry->startTime());
150 }
151 
152 void GetPerformanceEntryDuration(const Local<String> prop,
153  const PropertyCallbackInfo<Value>& info) {
154  PerformanceEntry* entry;
155  ASSIGN_OR_RETURN_UNWRAP(&entry, info.Holder());
156  info.GetReturnValue().Set(entry->duration());
157 }
158 
159 void MarkMilestone(const FunctionCallbackInfo<Value>& args) {
160  Environment* env = Environment::GetCurrent(args);
161  Local<Context> context = env->context();
162  double* milestones = env->performance_state()->milestones;
163  PerformanceMilestone milestone =
164  static_cast<PerformanceMilestone>(
165  args[0]->Int32Value(context).ToChecked());
166  if (milestone != NODE_PERFORMANCE_MILESTONE_INVALID) {
167  milestones[milestone] = PERFORMANCE_NOW();
168  }
169 }
170 
171 void SetupPerformanceObservers(const FunctionCallbackInfo<Value>& args) {
172  Environment* env = Environment::GetCurrent(args);
173  CHECK(args[0]->IsFunction());
174  env->set_performance_entry_callback(args[0].As<Function>());
175 }
176 
177 inline void PerformanceGCCallback(uv_async_t* handle) {
179  static_cast<PerformanceEntry::Data*>(handle->data);
180  Isolate* isolate = Isolate::GetCurrent();
181  HandleScope scope(isolate);
182  Environment* env = Environment::GetCurrent(isolate);
183  Local<Context> context = env->context();
184  Local<Function> fn;
185  Local<Object> obj;
186  PerformanceGCKind kind = static_cast<PerformanceGCKind>(data->data());
187 
188  uint32_t* observers = env->performance_state()->observers;
189  if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) {
190  goto cleanup;
191  }
192 
193  fn = env->performance_entry_template();
194  obj = fn->NewInstance(context).ToLocalChecked();
195  obj->Set(context,
196  FIXED_ONE_BYTE_STRING(isolate, "kind"),
197  Integer::New(isolate, kind)).FromJust();
198  new PerformanceEntry(env, obj, data);
199 
200  cleanup:
201  delete data;
202  auto closeCB = [](uv_handle_t* handle) { delete handle; };
203  uv_close(reinterpret_cast<uv_handle_t*>(handle), closeCB);
204 }
205 
206 inline void MarkGarbageCollectionStart(Isolate* isolate,
207  v8::GCType type,
208  v8::GCCallbackFlags flags) {
209  performance_last_gc_start_mark_ = PERFORMANCE_NOW();
210  performance_last_gc_type_ = type;
211 }
212 
213 inline void MarkGarbageCollectionEnd(Isolate* isolate,
214  v8::GCType type,
215  v8::GCCallbackFlags flags) {
216  uv_async_t *async = new uv_async_t;
217  async->data =
218  new PerformanceEntry::Data("gc", "gc",
219  performance_last_gc_start_mark_,
220  PERFORMANCE_NOW(), type);
221  uv_async_init(uv_default_loop(), async, PerformanceGCCallback);
222  uv_async_send(async);
223 }
224 
225 inline void SetupGarbageCollectionTracking(Isolate* isolate) {
226  isolate->AddGCPrologueCallback(MarkGarbageCollectionStart);
227  isolate->AddGCEpilogueCallback(MarkGarbageCollectionEnd);
228 }
229 
230 inline Local<Value> GetName(Local<Function> fn) {
231  Local<Value> val = fn->GetDebugName();
232  if (val.IsEmpty() || val->IsUndefined()) {
233  Local<Value> boundFunction = fn->GetBoundFunction();
234  if (!boundFunction.IsEmpty() && !boundFunction->IsUndefined()) {
235  val = GetName(boundFunction.As<Function>());
236  }
237  }
238  return val;
239 }
240 
241 void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
242  Isolate* isolate = args.GetIsolate();
243  HandleScope scope(isolate);
244  Environment* env = Environment::GetCurrent(isolate);
245  Local<Context> context = env->context();
246  Local<Function> fn = args.Data().As<Function>();
247  size_t count = args.Length();
248  size_t idx;
249  std::vector<Local<Value>> call_args;
250  for (size_t i = 0; i < count; ++i) {
251  call_args.push_back(args[i]);
252  }
253 
254  Utf8Value name(isolate, GetName(fn));
255 
256  uint64_t start;
257  uint64_t end;
258  v8::TryCatch try_catch(isolate);
259  if (args.IsConstructCall()) {
260  start = PERFORMANCE_NOW();
261  v8::MaybeLocal<Object> ret = fn->NewInstance(context,
262  call_args.size(),
263  call_args.data());
264  end = PERFORMANCE_NOW();
265  if (ret.IsEmpty()) {
266  try_catch.ReThrow();
267  return;
268  }
269  args.GetReturnValue().Set(ret.ToLocalChecked());
270  } else {
271  start = PERFORMANCE_NOW();
272  v8::MaybeLocal<Value> ret = fn->Call(context,
273  args.This(),
274  call_args.size(),
275  call_args.data());
276  end = PERFORMANCE_NOW();
277  if (ret.IsEmpty()) {
278  try_catch.ReThrow();
279  return;
280  }
281  args.GetReturnValue().Set(ret.ToLocalChecked());
282  }
283 
284 
285  uint32_t* observers = env->performance_state()->observers;
286  if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION])
287  return;
288 
289  Local<Function> ctor = env->performance_entry_template();
290  v8::MaybeLocal<Object> instance = ctor->NewInstance(context);
291  Local<Object> obj = instance.ToLocalChecked();
292  for (idx = 0; idx < count; idx++) {
293  obj->Set(context, idx, args[idx]).ToChecked();
294  }
295  new PerformanceEntry(env, obj, *name, "function", start, end);
296 }
297 
298 void Timerify(const FunctionCallbackInfo<Value>& args) {
299  Environment* env = Environment::GetCurrent(args);
300  Local<Context> context = env->context();
301  CHECK(args[0]->IsFunction());
302  CHECK(args[1]->IsNumber());
303  Local<Function> fn = args[0].As<Function>();
304  int length = args[1]->IntegerValue(context).ToChecked();
305  Local<Function> wrap =
306  Function::New(context, TimerFunctionCall, fn, length).ToLocalChecked();
307  args.GetReturnValue().Set(wrap);
308 }
309 
310 void Init(Local<Object> target,
311  Local<Value> unused,
312  Local<Context> context) {
313  Environment* env = Environment::GetCurrent(context);
314  Isolate* isolate = env->isolate();
315  performance_state* state = env->performance_state();
316  auto state_ab = ArrayBuffer::New(isolate, state, sizeof(*state));
317 
318  #define SET_STATE_TYPEDARRAY(name, type, field) \
319  target->Set(context, \
320  FIXED_ONE_BYTE_STRING(isolate, (name)), \
321  type::New(state_ab, \
322  offsetof(performance_state, field), \
323  arraysize(state->field))) \
324  .FromJust()
325  SET_STATE_TYPEDARRAY("observerCounts", v8::Uint32Array, observers);
326  SET_STATE_TYPEDARRAY("milestones", v8::Float64Array, milestones);
327  #undef SET_STATE_TYPEDARRAY
328 
329  Local<String> performanceEntryString =
330  FIXED_ONE_BYTE_STRING(isolate, "PerformanceEntry");
331 
332  Local<FunctionTemplate> pe = env->NewFunctionTemplate(PerformanceEntry::New);
333  pe->InstanceTemplate()->SetInternalFieldCount(1);
334  pe->SetClassName(performanceEntryString);
335  Local<ObjectTemplate> ot = pe->InstanceTemplate();
336  ot->SetAccessor(env->name_string(), GetPerformanceEntryName);
337  ot->SetAccessor(FIXED_ONE_BYTE_STRING(isolate, "entryType"),
339  ot->SetAccessor(FIXED_ONE_BYTE_STRING(isolate, "startTime"),
341  ot->SetAccessor(FIXED_ONE_BYTE_STRING(isolate, "duration"),
343  Local<Function> fn = pe->GetFunction();
344  target->Set(performanceEntryString, fn);
345  env->set_performance_entry_template(fn);
346 
347  env->SetMethod(target, "mark", Mark);
348  env->SetMethod(target, "measure", Measure);
349  env->SetMethod(target, "markMilestone", MarkMilestone);
350  env->SetMethod(target, "setupObservers", SetupPerformanceObservers);
351  env->SetMethod(target, "timerify", Timerify);
352 
353  Local<Object> constants = Object::New(isolate);
354 
355  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MAJOR);
356  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_MINOR);
357  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_INCREMENTAL);
358  NODE_DEFINE_CONSTANT(constants, NODE_PERFORMANCE_GC_WEAKCB);
359 
360 #define V(name, _) \
361  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_ENTRY_TYPE_##name);
363 #undef V
364 
365 #define V(name, _) \
366  NODE_DEFINE_HIDDEN_CONSTANT(constants, NODE_PERFORMANCE_MILESTONE_##name);
368 #undef V
369 
370  v8::PropertyAttribute attr =
371  static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
372 
373  target->DefineOwnProperty(context,
374  FIXED_ONE_BYTE_STRING(isolate, "timeOrigin"),
375  v8::Number::New(isolate, timeOrigin / 1e6),
376  attr).ToChecked();
377 
378  target->DefineOwnProperty(context,
379  env->constants_string(),
380  constants,
381  attr).ToChecked();
382 
384 }
385 
386 } // namespace performance
387 } // namespace node
388 
void MarkGarbageCollectionStart(Isolate *isolate, v8::GCType type, v8::GCCallbackFlags flags)
Definition: node_perf.cc:206
void GetPerformanceEntryStartTime(const Local< String > prop, const PropertyCallbackInfo< Value > &info)
Definition: node_perf.cc:145
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
void GetPerformanceEntryName(const Local< String > prop, const PropertyCallbackInfo< Value > &info)
Definition: node_perf.cc:127
#define V(name, _)
void Init(Local< Object > target, Local< Value > unused, Local< Context > context)
Definition: node_perf.cc:310
void Mark(const FunctionCallbackInfo< Value > &args)
Definition: node_perf.cc:63
const uint64_t timeOrigin
Definition: node_perf.cc:30
#define SET_STATE_TYPEDARRAY(name, type, field)
QueryWrap * wrap
Definition: cares_wrap.cc:478
uint64_t performance_v8_start
Definition: node_perf.cc:32
#define PERFORMANCE_NOW()
void Timerify(const FunctionCallbackInfo< Value > &args)
Definition: node_perf.cc:298
union node::cares_wrap::@8::CaresAsyncData::@0 data
void MarkGarbageCollectionEnd(Isolate *isolate, v8::GCType type, v8::GCCallbackFlags flags)
Definition: node_perf.cc:213
v8::GCType performance_last_gc_type_
Definition: node_perf.cc:35
void MarkMilestone(const FunctionCallbackInfo< Value > &args)
Definition: node_perf.cc:159
void GetPerformanceEntryDuration(const Local< String > prop, const PropertyCallbackInfo< Value > &info)
Definition: node_perf.cc:152
Local< Value > GetName(Local< Function > fn)
Definition: node_perf.cc:230
void GetPerformanceEntryType(const Local< String > prop, const PropertyCallbackInfo< Value > &info)
Definition: node_perf.cc:136
char * Data(Local< Value > val)
Definition: node_buffer.cc:211
void SetupPerformanceObservers(const FunctionCallbackInfo< Value > &args)
Definition: node_perf.cc:171
void TimerFunctionCall(const FunctionCallbackInfo< Value > &args)
Definition: node_perf.cc:241
void SetupGarbageCollectionTracking(Isolate *isolate)
Definition: node_perf.cc:225
#define NODE_PERFORMANCE_ENTRY_TYPES(V)
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
Definition: node_buffer.cc:241
void PerformanceGCCallback(uv_async_t *handle)
Definition: node_perf.cc:177
uint64_t GetPerformanceMark(Environment *env, std::string name)
Definition: node_perf.cc:81
void Measure(const FunctionCallbackInfo< Value > &args)
Definition: node_perf.cc:87
uint64_t performance_last_gc_start_mark_
Definition: node_perf.cc:34
#define NODE_PERFORMANCE_MILESTONES(V)
#define NODE_DEFINE_CONSTANT(target, constant)
Definition: node.h:239
uint64_t performance_node_start
Definition: node_perf.cc:31