nodejs/node · #65985

perf_hooks: reuse buffer for uv metrics

HoonDongKang · merged Sep 14, 20266 files · 46 + / 17
lib/internal/perf/nodetiming.js5 + / 4
@@ -29,6 +29,7 @@ const {   },   loopIdleTime,   uvMetricsInfo,+  uvMetricsBuffer, } = internalBinding('performance');  class PerformanceNodeTiming {@@ -129,11 +130,11 @@ class PerformanceNodeTiming {         enumerable: true,         configurable: true,         get: () => {-          const metrics = uvMetricsInfo();+          uvMetricsInfo();           return {-            loopCount: metrics[0],-            events: metrics[1],-            eventsWaiting: metrics[2],+            loopCount: uvMetricsBuffer[0],+            events: uvMetricsBuffer[1],+            eventsWaiting: uvMetricsBuffer[2],           };         },       },
src/node_perf.cc24 + / 11
@@ -14,7 +14,6 @@ namespace node { namespace performance { -using v8::Array; using v8::Context; using v8::DontDelete; using v8::Function;@@ -57,7 +56,12 @@ PerformanceState::PerformanceState(Isolate* isolate,                 offsetof(performance_state_internal, observers),                 NODE_PERFORMANCE_ENTRY_TYPE_INVALID,                 root,-                MAYBE_FIELD_PTR(info, observers)) {+                MAYBE_FIELD_PTR(info, observers)),+      uv_metrics(isolate,+                 offsetof(performance_state_internal, uv_metrics),+                 3,+                 root,+                 MAYBE_FIELD_PTR(info, uv_metrics)) {   if (info == nullptr) {     // For performance states initialized from scratch, reset     // all the milestones and initialize the time origin.@@ -81,9 +85,15 @@ PerformanceState::SerializeInfo PerformanceState::Serialize(   // We'll re-initialize them after deserialization.   ResetMilestones(); +  // Do not retain runtime metrics in the snapshot.+  for (size_t i = 0; i < uv_metrics.Length(); ++i) {+    uv_metrics[i] = 0;+  }+   SerializeInfo info{root.Serialize(context, creator),                      milestones.Serialize(context, creator),-                     observers.Serialize(context, creator)};+                     observers.Serialize(context, creator),+                     uv_metrics.Serialize(context, creator)};   return info; } @@ -105,6 +115,7 @@ void PerformanceState::Deserialize(v8::Local<v8::Context> context,   root.Deserialize(context);   milestones.Deserialize(context);   observers.Deserialize(context);+  uv_metrics.Deserialize(context);    // Re-initialize the time origin and timestamp i.e. the process start time.   Initialize(time_origin, time_origin_timestamp);@@ -116,6 +127,7 @@ std::ostream& operator<<(std::ostream& o,     << "  " << i.root << ",  // root\n"     << "  " << i.milestones << ",  // milestones\n"     << "  " << i.observers << ",  // observers\n"+    << "  " << i.uv_metrics << ",  // uv_metrics\n"     << "}";   return o; }@@ -265,17 +277,13 @@ void LoopIdleTime(const FunctionCallbackInfo<Value>& args) {  void UvMetricsInfo(const FunctionCallbackInfo<Value>& args) {   Environment* env = Environment::GetCurrent(args);-  Isolate* isolate = env->isolate();   uv_metrics_t metrics;   // uv_metrics_info always return 0   CHECK_EQ(uv_metrics_info(env->event_loop(), &metrics), 0);-  Local<Value> data[] = {-      Integer::New(isolate, metrics.loop_count),-      Integer::New(isolate, metrics.events),-      Integer::New(isolate, metrics.events_waiting),-  };-  Local<Array> arr = Array::New(env->isolate(), data, arraysize(data));-  args.GetReturnValue().Set(arr);+  AliasedInt32Array& buffer = env->performance_state()->uv_metrics;+  buffer[0] = static_cast<int32_t>(metrics.loop_count);+  buffer[1] = static_cast<int32_t>(metrics.events);+  buffer[2] = static_cast<int32_t>(metrics.events_waiting); }  void CreateELDHistogram(const FunctionCallbackInfo<Value>& args) {@@ -366,6 +374,11 @@ void CreatePerContextProperties(Local<Object> target,   target->Set(context,               FIXED_ONE_BYTE_STRING(isolate, "milestones"),               state->milestones.GetJSArray()).Check();+  target+      ->Set(context,+            FIXED_ONE_BYTE_STRING(isolate, "uvMetricsBuffer"),+            state->uv_metrics.GetJSArray())+      .Check();    Local<Object> constants = Object::New(isolate); 
src/node_perf_common.h3 + / 0
@@ -62,6 +62,7 @@ class PerformanceState {     AliasedBufferIndex root;     AliasedBufferIndex milestones;     AliasedBufferIndex observers;+    AliasedBufferIndex uv_metrics;   };    explicit PerformanceState(v8::Isolate* isolate,@@ -78,6 +79,7 @@ class PerformanceState {   AliasedUint8Array root;   AliasedFloat64Array milestones;   AliasedUint32Array observers;+  AliasedInt32Array uv_metrics;    uint64_t performance_last_gc_start_mark = 0;   uint16_t current_gc_type = 0;@@ -92,6 +94,7 @@ class PerformanceState {     // doubles first so that they are always sizeof(double)-aligned     double milestones[NODE_PERFORMANCE_MILESTONE_INVALID];     uint32_t observers[NODE_PERFORMANCE_ENTRY_TYPE_INVALID];+    int32_t uv_metrics[3];   }; }; 
src/node_snapshotable.cc3 + / 0
@@ -392,6 +392,7 @@ size_t SnapshotSerializer::Write(const ImmediateInfo::SerializeInfo& data) { // [ 4/8 bytes ]  snapshot index of root // [ 4/8 bytes ]  snapshot index of milestones // [ 4/8 bytes ]  snapshot index of observers+// [ 4/8 bytes ]  snapshot index of uv_metrics template <> performance::PerformanceState::SerializeInfo SnapshotDeserializer::Read() {   Debug("Read<PerformanceState::SerializeInfo>()\n");@@ -400,6 +401,7 @@ performance::PerformanceState::SerializeInfo SnapshotDeserializer::Read() {   result.root = ReadArithmetic<AliasedBufferIndex>();   result.milestones = ReadArithmetic<AliasedBufferIndex>();   result.observers = ReadArithmetic<AliasedBufferIndex>();+  result.uv_metrics = ReadArithmetic<AliasedBufferIndex>();   if (is_debug) {     std::string str = ToStr(result);     Debug("Read<PerformanceState::SerializeInfo>() %s\n", str);@@ -418,6 +420,7 @@ size_t SnapshotSerializer::Write(   size_t written_total = WriteArithmetic<AliasedBufferIndex>(data.root);   written_total += WriteArithmetic<AliasedBufferIndex>(data.milestones);   written_total += WriteArithmetic<AliasedBufferIndex>(data.observers);+  written_total += WriteArithmetic<AliasedBufferIndex>(data.uv_metrics);    Debug("Write<PerformanceState::SerializeInfo>() wrote %d bytes\n",         written_total);
test/fixtures/test-nodetiming-uvmetricsinfo.js9 + / 1
@@ -40,7 +40,15 @@ function safeMetricsInfo(cb) {     fs.open(__filename, 'r', (err) => {       assert.ifError(err);     });++    const saved = { ...info };+    safeMetricsInfo((nextInfo) => {+      assert.notStrictEqual(nextInfo, info);+      assert.ok(nextInfo.loopCount > saved.loopCount);+      // Updating the shared buffer must not change earlier results.+      assert.deepStrictEqual(info, saved);+    });   }    safeMetricsInfo(openFile);-}\ No newline at end of file+}
typings/internalBinding/performance.d.ts2 + / 1
@@ -129,6 +129,7 @@ export interface PerformanceBinding {     samplePerIteration: boolean,   ): InternalPerformanceBinding.ELDHistogram;   markBootstrapComplete(): void;-  uvMetricsInfo(): [number, number, number];+  uvMetricsInfo(): void;+  uvMetricsBuffer: Int32Array;   now(): number; }