Skip to content

Commit 0022767

Browse files
jasnellrichardlau
authored andcommitted
src: add fast api for Histogram
PR-URL: #51296 Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Vinícius Lourenço Claro Cardoso <[email protected]> Reviewed-By: Mohammed Keyvanzadeh <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
1 parent 1da2e8d commit 0022767

File tree

4 files changed

+215
-14
lines changed

4 files changed

+215
-14
lines changed
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const common = require('../common.js');
5+
6+
const { createHistogram } = require('perf_hooks');
7+
8+
const bench = common.createBenchmark(main, {
9+
n: [1e5],
10+
});
11+
12+
function main({ n }) {
13+
const histogram = createHistogram();
14+
bench.start();
15+
for (let i = 0; i < n; i++) {
16+
histogram.record(i + 1);
17+
/* eslint-disable no-unused-expressions */
18+
histogram.max;
19+
histogram.mean;
20+
/* eslint-enable no-unused-expressions */
21+
}
22+
bench.end(n);
23+
24+
// Avoid V8 deadcode (elimination)
25+
assert.ok(histogram);
26+
}

src/histogram.cc

+145-14
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
namespace node {
1010

1111
using v8::BigInt;
12+
using v8::CFunction;
1213
using v8::Context;
14+
using v8::FastApiCallbackOptions;
1315
using v8::FunctionCallbackInfo;
1416
using v8::FunctionTemplate;
1517
using v8::Integer;
@@ -42,7 +44,34 @@ HistogramImpl::HistogramImpl(const Histogram::Options& options)
4244
HistogramImpl::HistogramImpl(std::shared_ptr<Histogram> histogram)
4345
: histogram_(std::move(histogram)) {}
4446

47+
CFunction HistogramImpl::fast_reset_(
48+
CFunction::Make(&HistogramImpl::FastReset));
49+
CFunction HistogramImpl::fast_get_count_(
50+
CFunction::Make(&HistogramImpl::FastGetCount));
51+
CFunction HistogramImpl::fast_get_min_(
52+
CFunction::Make(&HistogramImpl::FastGetMin));
53+
CFunction HistogramImpl::fast_get_max_(
54+
CFunction::Make(&HistogramImpl::FastGetMax));
55+
CFunction HistogramImpl::fast_get_mean_(
56+
CFunction::Make(&HistogramImpl::FastGetMean));
57+
CFunction HistogramImpl::fast_get_exceeds_(
58+
CFunction::Make(&HistogramImpl::FastGetExceeds));
59+
CFunction HistogramImpl::fast_get_stddev_(
60+
CFunction::Make(&HistogramImpl::FastGetStddev));
61+
CFunction HistogramImpl::fast_get_percentile_(
62+
CFunction::Make(&HistogramImpl::FastGetPercentile));
63+
CFunction HistogramBase::fast_record_(
64+
CFunction::Make(&HistogramBase::FastRecord));
65+
CFunction HistogramBase::fast_record_delta_(
66+
CFunction::Make(&HistogramBase::FastRecordDelta));
67+
CFunction IntervalHistogram::fast_start_(
68+
CFunction::Make(&IntervalHistogram::FastStart));
69+
CFunction IntervalHistogram::fast_stop_(
70+
CFunction::Make(&IntervalHistogram::FastStop));
71+
4572
void HistogramImpl::AddMethods(Isolate* isolate, Local<FunctionTemplate> tmpl) {
73+
// TODO(@jasnell): The bigint API variations do not yet support fast
74+
// variations since v8 will not return a bigint value from a fast method.
4675
SetProtoMethodNoSideEffect(isolate, tmpl, "countBigInt", GetCountBigInt);
4776
SetProtoMethodNoSideEffect(isolate, tmpl, "exceedsBigInt", GetExceedsBigInt);
4877
SetProtoMethodNoSideEffect(isolate, tmpl, "minBigInt", GetMinBigInt);
@@ -52,14 +81,20 @@ void HistogramImpl::AddMethods(Isolate* isolate, Local<FunctionTemplate> tmpl) {
5281
SetProtoMethodNoSideEffect(isolate, tmpl, "percentiles", GetPercentiles);
5382
SetProtoMethodNoSideEffect(
5483
isolate, tmpl, "percentilesBigInt", GetPercentilesBigInt);
55-
SetProtoMethodNoSideEffect(isolate, tmpl, "count", GetCount);
56-
SetProtoMethodNoSideEffect(isolate, tmpl, "exceeds", GetExceeds);
57-
SetProtoMethodNoSideEffect(isolate, tmpl, "min", GetMin);
58-
SetProtoMethodNoSideEffect(isolate, tmpl, "max", GetMax);
59-
SetProtoMethodNoSideEffect(isolate, tmpl, "mean", GetMean);
60-
SetProtoMethodNoSideEffect(isolate, tmpl, "stddev", GetStddev);
61-
SetProtoMethodNoSideEffect(isolate, tmpl, "percentile", GetPercentile);
62-
SetProtoMethod(isolate, tmpl, "reset", DoReset);
84+
auto instance = tmpl->InstanceTemplate();
85+
SetFastMethodNoSideEffect(
86+
isolate, instance, "count", GetCount, &fast_get_count_);
87+
SetFastMethodNoSideEffect(
88+
isolate, instance, "exceeds", GetExceeds, &fast_get_exceeds_);
89+
SetFastMethodNoSideEffect(isolate, instance, "min", GetMin, &fast_get_min_);
90+
SetFastMethodNoSideEffect(isolate, instance, "max", GetMax, &fast_get_max_);
91+
SetFastMethodNoSideEffect(
92+
isolate, instance, "mean", GetMean, &fast_get_mean_);
93+
SetFastMethodNoSideEffect(
94+
isolate, instance, "stddev", GetStddev, &fast_get_stddev_);
95+
SetFastMethodNoSideEffect(
96+
isolate, instance, "percentile", GetPercentile, &fast_get_percentile_);
97+
SetFastMethod(isolate, instance, "reset", DoReset, &fast_reset_);
6398
}
6499

65100
void HistogramImpl::RegisterExternalReferences(
@@ -81,6 +116,22 @@ void HistogramImpl::RegisterExternalReferences(
81116
registry->Register(GetPercentiles);
82117
registry->Register(GetPercentilesBigInt);
83118
registry->Register(DoReset);
119+
registry->Register(fast_reset_.GetTypeInfo());
120+
registry->Register(fast_get_count_.GetTypeInfo());
121+
registry->Register(fast_get_min_.GetTypeInfo());
122+
registry->Register(fast_get_max_.GetTypeInfo());
123+
registry->Register(fast_get_mean_.GetTypeInfo());
124+
registry->Register(fast_get_exceeds_.GetTypeInfo());
125+
registry->Register(fast_get_stddev_.GetTypeInfo());
126+
registry->Register(fast_get_percentile_.GetTypeInfo());
127+
registry->Register(FastReset);
128+
registry->Register(FastGetCount);
129+
registry->Register(FastGetMin);
130+
registry->Register(FastGetMax);
131+
registry->Register(FastGetMean);
132+
registry->Register(FastGetExceeds);
133+
registry->Register(FastGetStddev);
134+
registry->Register(FastGetPercentile);
84135
is_registerd = true;
85136
}
86137

@@ -118,6 +169,12 @@ void HistogramBase::RecordDelta(const FunctionCallbackInfo<Value>& args) {
118169
(*histogram)->RecordDelta();
119170
}
120171

172+
void HistogramBase::FastRecordDelta(Local<Value> receiver) {
173+
HistogramBase* histogram;
174+
ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver);
175+
(*histogram)->RecordDelta();
176+
}
177+
121178
void HistogramBase::Record(const FunctionCallbackInfo<Value>& args) {
122179
Environment* env = Environment::GetCurrent(args);
123180
CHECK_IMPLIES(!args[0]->IsNumber(), args[0]->IsBigInt());
@@ -132,6 +189,18 @@ void HistogramBase::Record(const FunctionCallbackInfo<Value>& args) {
132189
(*histogram)->Record(value);
133190
}
134191

192+
void HistogramBase::FastRecord(Local<Value> receiver,
193+
const int64_t value,
194+
FastApiCallbackOptions& options) {
195+
if (value < 1) {
196+
options.fallback = true;
197+
return;
198+
}
199+
HistogramBase* histogram;
200+
ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver);
201+
(*histogram)->Record(value);
202+
}
203+
135204
void HistogramBase::Add(const FunctionCallbackInfo<Value>& args) {
136205
Environment* env = Environment::GetCurrent(args);
137206
HistogramBase* histogram;
@@ -213,8 +282,9 @@ Local<FunctionTemplate> HistogramBase::GetConstructorTemplate(
213282
tmpl->SetClassName(classname);
214283
auto instance = tmpl->InstanceTemplate();
215284
instance->SetInternalFieldCount(HistogramImpl::kInternalFieldCount);
216-
SetProtoMethod(isolate, tmpl, "record", Record);
217-
SetProtoMethod(isolate, tmpl, "recordDelta", RecordDelta);
285+
SetFastMethod(isolate, instance, "record", Record, &fast_record_);
286+
SetFastMethod(
287+
isolate, instance, "recordDelta", RecordDelta, &fast_record_delta_);
218288
SetProtoMethod(isolate, tmpl, "add", Add);
219289
HistogramImpl::AddMethods(isolate, tmpl);
220290
isolate_data->set_histogram_ctor_template(tmpl);
@@ -228,6 +298,10 @@ void HistogramBase::RegisterExternalReferences(
228298
registry->Register(Add);
229299
registry->Register(Record);
230300
registry->Register(RecordDelta);
301+
registry->Register(fast_record_.GetTypeInfo());
302+
registry->Register(fast_record_delta_.GetTypeInfo());
303+
registry->Register(FastRecord);
304+
registry->Register(FastRecordDelta);
231305
HistogramImpl::RegisterExternalReferences(registry);
232306
}
233307

@@ -264,11 +338,11 @@ Local<FunctionTemplate> IntervalHistogram::GetConstructorTemplate(
264338
tmpl = NewFunctionTemplate(isolate, nullptr);
265339
tmpl->Inherit(HandleWrap::GetConstructorTemplate(env));
266340
tmpl->SetClassName(OneByteString(isolate, "Histogram"));
267-
tmpl->InstanceTemplate()->SetInternalFieldCount(
268-
HistogramImpl::kInternalFieldCount);
341+
auto instance = tmpl->InstanceTemplate();
342+
instance->SetInternalFieldCount(HistogramImpl::kInternalFieldCount);
269343
HistogramImpl::AddMethods(isolate, tmpl);
270-
SetProtoMethod(isolate, tmpl, "start", Start);
271-
SetProtoMethod(isolate, tmpl, "stop", Stop);
344+
SetFastMethod(isolate, instance, "start", Start, &fast_start_);
345+
SetFastMethod(isolate, instance, "stop", Stop, &fast_stop_);
272346
env->set_intervalhistogram_constructor_template(tmpl);
273347
}
274348
return tmpl;
@@ -278,6 +352,10 @@ void IntervalHistogram::RegisterExternalReferences(
278352
ExternalReferenceRegistry* registry) {
279353
registry->Register(Start);
280354
registry->Register(Stop);
355+
registry->Register(fast_start_.GetTypeInfo());
356+
registry->Register(fast_stop_.GetTypeInfo());
357+
registry->Register(FastStart);
358+
registry->Register(FastStop);
281359
HistogramImpl::RegisterExternalReferences(registry);
282360
}
283361

@@ -358,12 +436,24 @@ void IntervalHistogram::Start(const FunctionCallbackInfo<Value>& args) {
358436
histogram->OnStart(args[0]->IsTrue() ? StartFlags::RESET : StartFlags::NONE);
359437
}
360438

439+
void IntervalHistogram::FastStart(Local<Value> receiver, bool reset) {
440+
IntervalHistogram* histogram;
441+
ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver);
442+
histogram->OnStart(reset ? StartFlags::RESET : StartFlags::NONE);
443+
}
444+
361445
void IntervalHistogram::Stop(const FunctionCallbackInfo<Value>& args) {
362446
IntervalHistogram* histogram;
363447
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
364448
histogram->OnStop();
365449
}
366450

451+
void IntervalHistogram::FastStop(Local<Value> receiver) {
452+
IntervalHistogram* histogram;
453+
ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver);
454+
histogram->OnStop();
455+
}
456+
367457
void HistogramImpl::GetCount(const FunctionCallbackInfo<Value>& args) {
368458
HistogramImpl* histogram = HistogramImpl::FromJSObject(args.Holder());
369459
double value = static_cast<double>((*histogram)->Count());
@@ -474,6 +564,47 @@ void HistogramImpl::DoReset(const FunctionCallbackInfo<Value>& args) {
474564
(*histogram)->Reset();
475565
}
476566

567+
void HistogramImpl::FastReset(Local<Value> receiver) {
568+
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
569+
(*histogram)->Reset();
570+
}
571+
572+
double HistogramImpl::FastGetCount(Local<Value> receiver) {
573+
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
574+
return static_cast<double>((*histogram)->Count());
575+
}
576+
577+
double HistogramImpl::FastGetMin(Local<Value> receiver) {
578+
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
579+
return static_cast<double>((*histogram)->Min());
580+
}
581+
582+
double HistogramImpl::FastGetMax(Local<Value> receiver) {
583+
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
584+
return static_cast<double>((*histogram)->Max());
585+
}
586+
587+
double HistogramImpl::FastGetMean(Local<Value> receiver) {
588+
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
589+
return (*histogram)->Mean();
590+
}
591+
592+
double HistogramImpl::FastGetExceeds(Local<Value> receiver) {
593+
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
594+
return static_cast<double>((*histogram)->Exceeds());
595+
}
596+
597+
double HistogramImpl::FastGetStddev(Local<Value> receiver) {
598+
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
599+
return (*histogram)->Stddev();
600+
}
601+
602+
double HistogramImpl::FastGetPercentile(Local<Value> receiver,
603+
const double percentile) {
604+
HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver);
605+
return static_cast<double>((*histogram)->Percentile(percentile));
606+
}
607+
477608
HistogramImpl* HistogramImpl::FromJSObject(Local<Value> value) {
478609
auto obj = value.As<Object>();
479610
DCHECK_GE(obj->InternalFieldCount(), HistogramImpl::kInternalFieldCount);

src/histogram.h

+35
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,16 @@ class HistogramImpl {
101101
static void GetPercentilesBigInt(
102102
const v8::FunctionCallbackInfo<v8::Value>& args);
103103

104+
static void FastReset(v8::Local<v8::Value> receiver);
105+
static double FastGetCount(v8::Local<v8::Value> receiver);
106+
static double FastGetMin(v8::Local<v8::Value> receiver);
107+
static double FastGetMax(v8::Local<v8::Value> receiver);
108+
static double FastGetMean(v8::Local<v8::Value> receiver);
109+
static double FastGetExceeds(v8::Local<v8::Value> receiver);
110+
static double FastGetStddev(v8::Local<v8::Value> receiver);
111+
static double FastGetPercentile(v8::Local<v8::Value> receiver,
112+
const double percentile);
113+
104114
static void AddMethods(v8::Isolate* isolate,
105115
v8::Local<v8::FunctionTemplate> tmpl);
106116

@@ -110,6 +120,15 @@ class HistogramImpl {
110120

111121
private:
112122
std::shared_ptr<Histogram> histogram_;
123+
124+
static v8::CFunction fast_reset_;
125+
static v8::CFunction fast_get_count_;
126+
static v8::CFunction fast_get_min_;
127+
static v8::CFunction fast_get_max_;
128+
static v8::CFunction fast_get_mean_;
129+
static v8::CFunction fast_get_exceeds_;
130+
static v8::CFunction fast_get_stddev_;
131+
static v8::CFunction fast_get_percentile_;
113132
};
114133

115134
class HistogramBase final : public BaseObject, public HistogramImpl {
@@ -138,6 +157,12 @@ class HistogramBase final : public BaseObject, public HistogramImpl {
138157
static void RecordDelta(const v8::FunctionCallbackInfo<v8::Value>& args);
139158
static void Add(const v8::FunctionCallbackInfo<v8::Value>& args);
140159

160+
static void FastRecord(
161+
v8::Local<v8::Value> receiver,
162+
const int64_t value,
163+
v8::FastApiCallbackOptions& options); // NOLINT(runtime/references)
164+
static void FastRecordDelta(v8::Local<v8::Value> receiver);
165+
141166
HistogramBase(
142167
Environment* env,
143168
v8::Local<v8::Object> wrap,
@@ -173,6 +198,10 @@ class HistogramBase final : public BaseObject, public HistogramImpl {
173198
private:
174199
std::shared_ptr<Histogram> histogram_;
175200
};
201+
202+
private:
203+
static v8::CFunction fast_record_;
204+
static v8::CFunction fast_record_delta_;
176205
};
177206

178207
class IntervalHistogram final : public HandleWrap, public HistogramImpl {
@@ -204,6 +233,9 @@ class IntervalHistogram final : public HandleWrap, public HistogramImpl {
204233
static void Start(const v8::FunctionCallbackInfo<v8::Value>& args);
205234
static void Stop(const v8::FunctionCallbackInfo<v8::Value>& args);
206235

236+
static void FastStart(v8::Local<v8::Value> receiver, bool reset);
237+
static void FastStop(v8::Local<v8::Value> receiver);
238+
207239
TransferMode GetTransferMode() const override {
208240
return TransferMode::kCloneable;
209241
}
@@ -222,6 +254,9 @@ class IntervalHistogram final : public HandleWrap, public HistogramImpl {
222254
int32_t interval_ = 0;
223255
std::function<void(Histogram&)> on_interval_;
224256
uv_timer_t timer_;
257+
258+
static v8::CFunction fast_start_;
259+
static v8::CFunction fast_stop_;
225260
};
226261

227262
} // namespace node

src/node_external_reference.h

+9
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ using CFunctionCallbackWithStrings =
2929
const v8::FastOneByteString& base);
3030
using CFunctionWithUint32 = uint32_t (*)(v8::Local<v8::Value>,
3131
const uint32_t input);
32+
using CFunctionWithDoubleReturnDouble = double (*)(v8::Local<v8::Value>,
33+
const double);
34+
using CFunctionWithInt64Fallback = void (*)(v8::Local<v8::Value>,
35+
const int64_t,
36+
v8::FastApiCallbackOptions&);
37+
using CFunctionWithBool = void (*)(v8::Local<v8::Value>, bool);
3238

3339
// This class manages the external references from the V8 heap
3440
// to the C++ addresses in Node.js.
@@ -46,6 +52,9 @@ class ExternalReferenceRegistry {
4652
V(CFunctionCallbackWithString) \
4753
V(CFunctionCallbackWithStrings) \
4854
V(CFunctionWithUint32) \
55+
V(CFunctionWithDoubleReturnDouble) \
56+
V(CFunctionWithInt64Fallback) \
57+
V(CFunctionWithBool) \
4958
V(const v8::CFunctionInfo*) \
5059
V(v8::FunctionCallback) \
5160
V(v8::AccessorGetterCallback) \

0 commit comments

Comments
 (0)