Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
perf_hooks: fix histogram fast call signatures
  • Loading branch information
Renegade334 committed Jul 27, 2025
commit 50fe51f118f60148e1198da656884fe1ead92266
54 changes: 26 additions & 28 deletions src/histogram.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "base_object-inl.h"
#include "histogram-inl.h"
#include "memory_tracker-inl.h"
#include "node_debug.h"
#include "node_errors.h"
#include "node_external_reference.h"
#include "util.h"
Expand All @@ -11,10 +12,8 @@ namespace node {
using v8::BigInt;
using v8::CFunction;
using v8::Context;
using v8::FastApiCallbackOptions;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::HandleScope;
using v8::Integer;
using v8::Isolate;
using v8::Local;
Expand Down Expand Up @@ -162,8 +161,8 @@ void HistogramBase::RecordDelta(const FunctionCallbackInfo<Value>& args) {
(*histogram)->RecordDelta();
}

void HistogramBase::FastRecordDelta(Local<Value> unused,
Local<Value> receiver) {
void HistogramBase::FastRecordDelta(Local<Value> receiver) {
TRACK_V8_FAST_API_CALL("histogram.recordDelta");
HistogramBase* histogram;
ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver);
(*histogram)->RecordDelta();
Expand All @@ -183,15 +182,9 @@ void HistogramBase::Record(const FunctionCallbackInfo<Value>& args) {
(*histogram)->Record(value);
}

void HistogramBase::FastRecord(Local<Value> unused,
Local<Value> receiver,
const int64_t value,
FastApiCallbackOptions& options) {
if (value < 1) {
HandleScope scope(options.isolate);
THROW_ERR_OUT_OF_RANGE(options.isolate, "value is out of range");
return;
}
Comment on lines -190 to -194
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value is validated in the JS layer, so an assertion check should be fine here.

void HistogramBase::FastRecord(Local<Value> receiver, const int64_t value) {
CHECK_GE(value, 1);
TRACK_V8_FAST_API_CALL("histogram.record");
HistogramBase* histogram;
ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver);
(*histogram)->Record(value);
Expand Down Expand Up @@ -428,9 +421,8 @@ void IntervalHistogram::Start(const FunctionCallbackInfo<Value>& args) {
histogram->OnStart(args[0]->IsTrue() ? StartFlags::RESET : StartFlags::NONE);
}

void IntervalHistogram::FastStart(Local<Value> unused,
Local<Value> receiver,
bool reset) {
void IntervalHistogram::FastStart(Local<Value> receiver, bool reset) {
TRACK_V8_FAST_API_CALL("histogram.start");
IntervalHistogram* histogram;
ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver);
histogram->OnStart(reset ? StartFlags::RESET : StartFlags::NONE);
Expand All @@ -442,7 +434,8 @@ void IntervalHistogram::Stop(const FunctionCallbackInfo<Value>& args) {
histogram->OnStop();
}

void IntervalHistogram::FastStop(Local<Value> unused, Local<Value> receiver) {
void IntervalHistogram::FastStop(Local<Value> receiver) {
TRACK_V8_FAST_API_CALL("histogram.stop");
IntervalHistogram* histogram;
ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver);
histogram->OnStop();
Expand Down Expand Up @@ -558,46 +551,51 @@ void HistogramImpl::DoReset(const FunctionCallbackInfo<Value>& args) {
(*histogram)->Reset();
}

void HistogramImpl::FastReset(Local<Value> unused, Local<Value> receiver) {
void HistogramImpl::FastReset(Local<Value> receiver) {
TRACK_V8_FAST_API_CALL("histogram.reset");
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
(*histogram)->Reset();
}

double HistogramImpl::FastGetCount(Local<Value> unused, Local<Value> receiver) {
double HistogramImpl::FastGetCount(Local<Value> receiver) {
TRACK_V8_FAST_API_CALL("histogram.count");
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
return static_cast<double>((*histogram)->Count());
}

double HistogramImpl::FastGetMin(Local<Value> unused, Local<Value> receiver) {
double HistogramImpl::FastGetMin(Local<Value> receiver) {
TRACK_V8_FAST_API_CALL("histogram.min");
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
return static_cast<double>((*histogram)->Min());
}

double HistogramImpl::FastGetMax(Local<Value> unused, Local<Value> receiver) {
double HistogramImpl::FastGetMax(Local<Value> receiver) {
TRACK_V8_FAST_API_CALL("histogram.max");
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
return static_cast<double>((*histogram)->Max());
}

double HistogramImpl::FastGetMean(Local<Value> unused, Local<Value> receiver) {
double HistogramImpl::FastGetMean(Local<Value> receiver) {
TRACK_V8_FAST_API_CALL("histogram.mean");
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
return (*histogram)->Mean();
}

double HistogramImpl::FastGetExceeds(Local<Value> unused,
Local<Value> receiver) {
double HistogramImpl::FastGetExceeds(Local<Value> receiver) {
TRACK_V8_FAST_API_CALL("histogram.exceeds");
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
return static_cast<double>((*histogram)->Exceeds());
}

double HistogramImpl::FastGetStddev(Local<Value> unused,
Local<Value> receiver) {
double HistogramImpl::FastGetStddev(Local<Value> receiver) {
TRACK_V8_FAST_API_CALL("histogram.stddev");
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
return (*histogram)->Stddev();
}

double HistogramImpl::FastGetPercentile(Local<Value> unused,
Local<Value> receiver,
double HistogramImpl::FastGetPercentile(Local<Value> receiver,
const double percentile) {
TRACK_V8_FAST_API_CALL("histogram.percentile");
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
return static_cast<double>((*histogram)->Percentile(percentile));
}
Expand Down
40 changes: 12 additions & 28 deletions src/histogram.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,14 @@ class HistogramImpl {
static void GetPercentilesBigInt(
const v8::FunctionCallbackInfo<v8::Value>& args);

static void FastReset(v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver);
static double FastGetCount(v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver);
static double FastGetMin(v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver);
static double FastGetMax(v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver);
static double FastGetMean(v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver);
static double FastGetExceeds(v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver);
static double FastGetStddev(v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver);
static double FastGetPercentile(v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver,
static void FastReset(v8::Local<v8::Value> receiver);
static double FastGetCount(v8::Local<v8::Value> receiver);
static double FastGetMin(v8::Local<v8::Value> receiver);
static double FastGetMax(v8::Local<v8::Value> receiver);
static double FastGetMean(v8::Local<v8::Value> receiver);
static double FastGetExceeds(v8::Local<v8::Value> receiver);
static double FastGetStddev(v8::Local<v8::Value> receiver);
static double FastGetPercentile(v8::Local<v8::Value> receiver,
const double percentile);

static void AddMethods(v8::Isolate* isolate,
Expand Down Expand Up @@ -165,13 +157,8 @@ class HistogramBase final : public BaseObject, public HistogramImpl {
static void RecordDelta(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Add(const v8::FunctionCallbackInfo<v8::Value>& args);

static void FastRecord(
v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver,
const int64_t value,
v8::FastApiCallbackOptions& options); // NOLINT(runtime/references)
static void FastRecordDelta(v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver);
static void FastRecord(v8::Local<v8::Value> receiver, const int64_t value);
static void FastRecordDelta(v8::Local<v8::Value> receiver);

HistogramBase(
Environment* env,
Expand Down Expand Up @@ -243,11 +230,8 @@ class IntervalHistogram final : public HandleWrap, public HistogramImpl {
static void Start(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Stop(const v8::FunctionCallbackInfo<v8::Value>& args);

static void FastStart(v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver,
bool reset);
static void FastStop(v8::Local<v8::Value> unused,
v8::Local<v8::Value> receiver);
static void FastStart(v8::Local<v8::Value> receiver, bool reset);
static void FastStop(v8::Local<v8::Value> receiver);

BaseObject::TransferMode GetTransferMode() const override {
return TransferMode::kCloneable;
Expand Down
35 changes: 35 additions & 0 deletions test/parallel/test-perf-hooks-histogram-fast-calls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Flags: --expose-internals --no-warnings --allow-natives-syntax
'use strict';

const common = require('../common');
const assert = require('assert');

const { internalBinding } = require('internal/test/binding');

const histogram = require('perf_hooks').createHistogram();

function testFastMethods() {
histogram.record(1);
histogram.recordDelta();
histogram.percentile(50);
histogram.reset();
}

eval('%PrepareFunctionForOptimization(histogram.record)');
eval('%PrepareFunctionForOptimization(histogram.recordDelta)');
eval('%PrepareFunctionForOptimization(histogram.percentile)');
eval('%PrepareFunctionForOptimization(histogram.reset)');
testFastMethods();
eval('%OptimizeFunctionOnNextCall(histogram.record)');
eval('%OptimizeFunctionOnNextCall(histogram.recordDelta)');
eval('%OptimizeFunctionOnNextCall(histogram.percentile)');
eval('%OptimizeFunctionOnNextCall(histogram.reset)');
testFastMethods();

if (common.isDebug) {
const { getV8FastApiCallCount } = internalBinding('debug');
assert.strictEqual(getV8FastApiCallCount('histogram.record'), 1);
assert.strictEqual(getV8FastApiCallCount('histogram.recordDelta'), 1);
assert.strictEqual(getV8FastApiCallCount('histogram.percentile'), 1);
assert.strictEqual(getV8FastApiCallCount('histogram.reset'), 1);
}
6 changes: 4 additions & 2 deletions test/parallel/test-perf-hooks-histogram.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ const { inspect } = require('util');
code: 'ERR_INVALID_ARG_TYPE'
});
});
throws(() => h.record(0, Number.MAX_SAFE_INTEGER + 1), {
code: 'ERR_OUT_OF_RANGE'
[0, Number.MAX_SAFE_INTEGER + 1].forEach((i) => {
throws(() => h.record(i), {
code: 'ERR_OUT_OF_RANGE'
});
});

strictEqual(h.min, 1);
Expand Down