From e192ba18cdad4cffe8f7ea4ed94c9fa0e490f441 Mon Sep 17 00:00:00 2001 From: IlyasShabi Date: Wed, 28 Feb 2024 17:52:30 +0100 Subject: [PATCH] perf_hooks: performance milestone time origin timestamp improvement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/51713 Reviewed-By: Vinícius Lourenço Claro Cardoso Reviewed-By: Yagiz Nizipli Reviewed-By: Marco Ippolito Reviewed-By: Minwoo Jung Reviewed-By: Benjamin Gruenbaum Reviewed-By: Joyee Cheung --- benchmark/perf_hooks/time-origin.js | 45 +++++++++++++++++++++++++++++ lib/internal/perf/performance.js | 6 +--- lib/internal/perf/utils.js | 6 ++++ src/env.cc | 7 +++-- src/node_perf.cc | 32 +++++++++----------- src/node_perf_common.h | 8 +++-- 6 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 benchmark/perf_hooks/time-origin.js diff --git a/benchmark/perf_hooks/time-origin.js b/benchmark/perf_hooks/time-origin.js new file mode 100644 index 00000000000000..90a24f45341ed4 --- /dev/null +++ b/benchmark/perf_hooks/time-origin.js @@ -0,0 +1,45 @@ +'use strict'; + +const assert = require('assert'); +const common = require('../common.js'); + +const bench = common.createBenchmark(main, { + n: [1e6], + method: ['timeOrigin', 'toJSON'], +}); + +function main({ method, n }) { + switch (method) { + case 'timeOrigin': + benchTimeOrigin(n); + break; + case 'toJSON': + benchToJSON(n); + break; + default: + throw new Error(`Unsupported method ${method}`); + } +} + +function benchTimeOrigin(n) { + const arr = []; + for (let i = 0; i < n; ++i) { + arr.push(performance.timeOrigin); + } + + bench.start(); + for (let i = 0; i < n; i++) { + arr[i] = performance.timeOrigin; + } + bench.end(n); + + assert.strictEqual(arr.length, n); +} + +function benchToJSON(n) { + bench.start(); + for (let i = 0; i < n; i++) { + performance.toJSON(); + } + bench.end(n); +} diff --git a/lib/internal/perf/performance.js b/lib/internal/perf/performance.js index 0cc90bc95b532b..836dcaa87d8b31 100644 --- a/lib/internal/perf/performance.js +++ b/lib/internal/perf/performance.js @@ -22,7 +22,7 @@ const { defineEventHandler, } = require('internal/event_target'); -const { now } = require('internal/perf/utils'); +const { now, getTimeOriginTimestamp } = require('internal/perf/utils'); const { markResourceTiming } = require('internal/perf/resource_timing'); @@ -46,10 +46,6 @@ const { inspect } = require('util'); const { validateInternalField } = require('internal/validators'); const { convertToInt } = require('internal/webidl'); -const { - getTimeOriginTimestamp, -} = internalBinding('performance'); - const kPerformanceBrand = Symbol('performance'); class Performance extends EventTarget { diff --git a/lib/internal/perf/utils.js b/lib/internal/perf/utils.js index bbc1c996e318f8..5836efc7008526 100644 --- a/lib/internal/perf/utils.js +++ b/lib/internal/perf/utils.js @@ -3,6 +3,7 @@ const { constants: { NODE_PERFORMANCE_MILESTONE_TIME_ORIGIN, + NODE_PERFORMANCE_MILESTONE_TIME_ORIGIN_TIMESTAMP, }, milestones, now, @@ -22,7 +23,12 @@ function getMilestoneTimestamp(milestoneIdx) { return ns / 1e6 - getTimeOrigin(); } +function getTimeOriginTimestamp() { + return milestones[NODE_PERFORMANCE_MILESTONE_TIME_ORIGIN_TIMESTAMP] / 1e3; +} + module.exports = { now, getMilestoneTimestamp, + getTimeOriginTimestamp, }; diff --git a/src/env.cc b/src/env.cc index efc3dd7067bf03..9f83720fefc773 100644 --- a/src/env.cc +++ b/src/env.cc @@ -880,7 +880,10 @@ Environment::Environment(IsolateData* isolate_data, destroy_async_id_list_.reserve(512); performance_state_ = std::make_unique( - isolate, time_origin_, MAYBE_FIELD_PTR(env_info, performance_state)); + isolate, + time_origin_, + time_origin_timestamp_, + MAYBE_FIELD_PTR(env_info, performance_state)); if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( TRACING_CATEGORY_NODE1(environment)) != 0) { @@ -1837,7 +1840,7 @@ void Environment::DeserializeProperties(const EnvSerializeInfo* info) { immediate_info_.Deserialize(ctx); timeout_info_.Deserialize(ctx); tick_info_.Deserialize(ctx); - performance_state_->Deserialize(ctx, time_origin_); + performance_state_->Deserialize(ctx, time_origin_, time_origin_timestamp_); exit_info_.Deserialize(ctx); stream_base_state_.Deserialize(ctx); should_abort_on_uncaught_toggle_.Deserialize(ctx); diff --git a/src/node_perf.cc b/src/node_perf.cc index 603af57b2639b2..1aa264cc1e64ad 100644 --- a/src/node_perf.cc +++ b/src/node_perf.cc @@ -24,7 +24,6 @@ using v8::Integer; using v8::Isolate; using v8::Local; using v8::MaybeLocal; -using v8::Number; using v8::Object; using v8::ObjectTemplate; using v8::PropertyAttribute; @@ -43,6 +42,7 @@ uint64_t performance_v8_start; PerformanceState::PerformanceState(Isolate* isolate, uint64_t time_origin, + double time_origin_timestamp, const PerformanceState::SerializeInfo* info) : root(isolate, sizeof(performance_state_internal), @@ -63,7 +63,7 @@ PerformanceState::PerformanceState(Isolate* isolate, // For deserialized performance states, we will do the // initialization in the deserialize callback. ResetMilestones(); - Initialize(time_origin); + Initialize(time_origin, time_origin_timestamp); } } @@ -86,23 +86,27 @@ PerformanceState::SerializeInfo PerformanceState::Serialize( return info; } -void PerformanceState::Initialize(uint64_t time_origin) { - // We are only reusing the milestone array to store the time origin, so do - // not use the Mark() method. The time origin milestone is not exposed - // to user land. +void PerformanceState::Initialize(uint64_t time_origin, + double time_origin_timestamp) { + // We are only reusing the milestone array to store the time origin + // and time origin timestamp, so do not use the Mark() method. + // The time origin milestone is not exposed to user land. this->milestones[NODE_PERFORMANCE_MILESTONE_TIME_ORIGIN] = static_cast(time_origin); + this->milestones[NODE_PERFORMANCE_MILESTONE_TIME_ORIGIN_TIMESTAMP] = + time_origin_timestamp; } void PerformanceState::Deserialize(v8::Local context, - uint64_t time_origin) { + uint64_t time_origin, + double time_origin_timestamp) { // Resets the pointers. root.Deserialize(context); milestones.Deserialize(context); observers.Deserialize(context); - // Re-initialize the time origin i.e. the process start time. - Initialize(time_origin); + // Re-initialize the time origin and timestamp i.e. the process start time. + Initialize(time_origin, time_origin_timestamp); } std::ostream& operator<<(std::ostream& o, @@ -254,7 +258,7 @@ void Notify(const FunctionCallbackInfo& args) { void LoopIdleTime(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); uint64_t idle_time = uv_metrics_idle_time(env->event_loop()); - args.GetReturnValue().Set(1.0 * idle_time / 1e6); + args.GetReturnValue().Set(1.0 * idle_time / NANOS_PER_MILLIS); } void CreateELDHistogram(const FunctionCallbackInfo& args) { @@ -278,12 +282,6 @@ void CreateELDHistogram(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(histogram->object()); } -void GetTimeOriginTimeStamp(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - args.GetReturnValue().Set(Number::New( - args.GetIsolate(), env->time_origin_timestamp() / MICROS_PER_MILLIS)); -} - void MarkBootstrapComplete(const FunctionCallbackInfo& args) { Realm* realm = Realm::GetCurrent(args); CHECK_EQ(realm->kind(), Realm::Kind::kPrincipal); @@ -324,7 +322,6 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data, RemoveGarbageCollectionTracking); SetMethod(isolate, target, "notify", Notify); SetMethod(isolate, target, "loopIdleTime", LoopIdleTime); - SetMethod(isolate, target, "getTimeOriginTimestamp", GetTimeOriginTimeStamp); SetMethod(isolate, target, "createELDHistogram", CreateELDHistogram); SetMethod(isolate, target, "markBootstrapComplete", MarkBootstrapComplete); SetFastMethodNoSideEffect( @@ -391,7 +388,6 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(RemoveGarbageCollectionTracking); registry->Register(Notify); registry->Register(LoopIdleTime); - registry->Register(GetTimeOriginTimeStamp); registry->Register(CreateELDHistogram); registry->Register(MarkBootstrapComplete); registry->Register(SlowPerformanceNow); diff --git a/src/node_perf_common.h b/src/node_perf_common.h index dd757651c09e9f..ad09658e13ec79 100644 --- a/src/node_perf_common.h +++ b/src/node_perf_common.h @@ -25,6 +25,7 @@ extern const double performance_process_start_timestamp; extern uint64_t performance_v8_start; #define NODE_PERFORMANCE_MILESTONES(V) \ + V(TIME_ORIGIN_TIMESTAMP, "timeOriginTimestamp") \ V(TIME_ORIGIN, "timeOrigin") \ V(ENVIRONMENT, "environment") \ V(NODE_START, "nodeStart") \ @@ -64,10 +65,13 @@ class PerformanceState { explicit PerformanceState(v8::Isolate* isolate, uint64_t time_origin, + double time_origin_timestamp, const SerializeInfo* info); SerializeInfo Serialize(v8::Local context, v8::SnapshotCreator* creator); - void Deserialize(v8::Local context, uint64_t time_origin); + void Deserialize(v8::Local context, + uint64_t time_origin, + double time_origin_timestamp); friend std::ostream& operator<<(std::ostream& o, const SerializeInfo& i); AliasedUint8Array root; @@ -81,7 +85,7 @@ class PerformanceState { uint64_t ts = PERFORMANCE_NOW()); private: - void Initialize(uint64_t time_origin); + void Initialize(uint64_t time_origin, double time_origin_timestamp); void ResetMilestones(); struct performance_state_internal { // doubles first so that they are always sizeof(double)-aligned