Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions lib/internal/perf/nodetiming.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const {
},
loopIdleTime,
uvMetricsInfo,
uvMetricsBuffer,
} = internalBinding('performance');

class PerformanceNodeTiming {
Expand Down Expand Up @@ -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],
};
},
},
Expand Down
35 changes: 24 additions & 11 deletions src/node_perf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
namespace node {
namespace performance {

using v8::Array;
using v8::Context;
using v8::DontDelete;
using v8::Function;
Expand Down Expand Up @@ -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.
Expand All @@ -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;
}

Expand All @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);

Expand Down
3 changes: 3 additions & 0 deletions src/node_perf_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class PerformanceState {
AliasedBufferIndex root;
AliasedBufferIndex milestones;
AliasedBufferIndex observers;
AliasedBufferIndex uv_metrics;
};

explicit PerformanceState(v8::Isolate* isolate,
Expand All @@ -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;
Expand All @@ -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];
};
};

Expand Down
3 changes: 3 additions & 0 deletions src/node_snapshotable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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);
Expand All @@ -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);
Expand Down
10 changes: 9 additions & 1 deletion test/fixtures/test-nodetiming-uvmetricsinfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
3 changes: 2 additions & 1 deletion typings/internalBinding/performance.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export interface PerformanceBinding {
samplePerIteration: boolean,
): InternalPerformanceBinding.ELDHistogram;
markBootstrapComplete(): void;
uvMetricsInfo(): [number, number, number];
uvMetricsInfo(): void;
uvMetricsBuffer: Int32Array;
now(): number;
}
Loading