nodejs/node · #65985
perf_hooks: reuse buffer for uv metrics
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; }