1 #include "histogram.h" // NOLINT(build/include_inline)
2 #include "histogram-inl.h"
3 #include "base_object-inl.h"
4 #include "memory_tracker-inl.h"
5 #include "node_errors.h"
6 namespace node {
7
8 using v8::BigInt;
9 using v8::FunctionCallbackInfo;
10 using v8::FunctionTemplate;
11 using v8::Local;
12 using v8::Map;
13 using v8::Number;
14 using v8::Object;
15 using v8::String;
16 using v8::Value;
17
Histogram(int64_t lowest,int64_t highest,int figures)18 Histogram::Histogram(int64_t lowest, int64_t highest, int figures) {
19 hdr_histogram* histogram;
20 CHECK_EQ(0, hdr_init(lowest, highest, figures, &histogram));
21 histogram_.reset(histogram);
22 }
23
MemoryInfo(MemoryTracker * tracker) const24 void Histogram::MemoryInfo(MemoryTracker* tracker) const {
25 tracker->TrackFieldWithSize("histogram", GetMemorySize());
26 }
27
HistogramImpl(int64_t lowest,int64_t highest,int figures)28 HistogramImpl::HistogramImpl(int64_t lowest, int64_t highest, int figures)
29 : histogram_(new Histogram(lowest, highest, figures)) {}
30
HistogramImpl(std::shared_ptr<Histogram> histogram)31 HistogramImpl::HistogramImpl(std::shared_ptr<Histogram> histogram)
32 : histogram_(std::move(histogram)) {}
33
HistogramBase(Environment * env,Local<Object> wrap,int64_t lowest,int64_t highest,int figures)34 HistogramBase::HistogramBase(
35 Environment* env,
36 Local<Object> wrap,
37 int64_t lowest,
38 int64_t highest,
39 int figures)
40 : BaseObject(env, wrap),
41 HistogramImpl(lowest, highest, figures) {
42 MakeWeak();
43 }
44
HistogramBase(Environment * env,Local<Object> wrap,std::shared_ptr<Histogram> histogram)45 HistogramBase::HistogramBase(
46 Environment* env,
47 Local<Object> wrap,
48 std::shared_ptr<Histogram> histogram)
49 : BaseObject(env, wrap),
50 HistogramImpl(std::move(histogram)) {
51 MakeWeak();
52 }
53
MemoryInfo(MemoryTracker * tracker) const54 void HistogramBase::MemoryInfo(MemoryTracker* tracker) const {
55 tracker->TrackField("histogram", histogram());
56 }
57
GetMin(const FunctionCallbackInfo<Value> & args)58 void HistogramBase::GetMin(const FunctionCallbackInfo<Value>& args) {
59 HistogramBase* histogram;
60 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
61 double value = static_cast<double>((*histogram)->Min());
62 args.GetReturnValue().Set(value);
63 }
64
GetMax(const FunctionCallbackInfo<Value> & args)65 void HistogramBase::GetMax(const FunctionCallbackInfo<Value>& args) {
66 HistogramBase* histogram;
67 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
68 double value = static_cast<double>((*histogram)->Max());
69 args.GetReturnValue().Set(value);
70 }
71
GetMean(const FunctionCallbackInfo<Value> & args)72 void HistogramBase::GetMean(const FunctionCallbackInfo<Value>& args) {
73 HistogramBase* histogram;
74 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
75 args.GetReturnValue().Set((*histogram)->Mean());
76 }
77
GetExceeds(const FunctionCallbackInfo<Value> & args)78 void HistogramBase::GetExceeds(const FunctionCallbackInfo<Value>& args) {
79 HistogramBase* histogram;
80 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
81 double value = static_cast<double>((*histogram)->Exceeds());
82 args.GetReturnValue().Set(value);
83 }
84
GetStddev(const FunctionCallbackInfo<Value> & args)85 void HistogramBase::GetStddev(const FunctionCallbackInfo<Value>& args) {
86 HistogramBase* histogram;
87 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
88 args.GetReturnValue().Set((*histogram)->Stddev());
89 }
90
GetPercentile(const FunctionCallbackInfo<Value> & args)91 void HistogramBase::GetPercentile(const FunctionCallbackInfo<Value>& args) {
92 HistogramBase* histogram;
93 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
94 CHECK(args[0]->IsNumber());
95 double percentile = args[0].As<Number>()->Value();
96 args.GetReturnValue().Set((*histogram)->Percentile(percentile));
97 }
98
GetPercentiles(const FunctionCallbackInfo<Value> & args)99 void HistogramBase::GetPercentiles(const FunctionCallbackInfo<Value>& args) {
100 Environment* env = Environment::GetCurrent(args);
101 HistogramBase* histogram;
102 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
103 CHECK(args[0]->IsMap());
104 Local<Map> map = args[0].As<Map>();
105 (*histogram)->Percentiles([map, env](double key, double value) {
106 map->Set(
107 env->context(),
108 Number::New(env->isolate(), key),
109 Number::New(env->isolate(), value)).IsEmpty();
110 });
111 }
112
DoReset(const FunctionCallbackInfo<Value> & args)113 void HistogramBase::DoReset(const FunctionCallbackInfo<Value>& args) {
114 HistogramBase* histogram;
115 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
116 (*histogram)->Reset();
117 }
118
RecordDelta(const FunctionCallbackInfo<Value> & args)119 void HistogramBase::RecordDelta(const FunctionCallbackInfo<Value>& args) {
120 HistogramBase* histogram;
121 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
122 (*histogram)->RecordDelta();
123 }
124
Record(const FunctionCallbackInfo<Value> & args)125 void HistogramBase::Record(const FunctionCallbackInfo<Value>& args) {
126 Environment* env = Environment::GetCurrent(args);
127 CHECK_IMPLIES(!args[0]->IsNumber(), args[0]->IsBigInt());
128 bool lossless = true;
129 int64_t value = args[0]->IsBigInt()
130 ? args[0].As<BigInt>()->Int64Value(&lossless)
131 : static_cast<int64_t>(args[0].As<Number>()->Value());
132 if (!lossless || value < 1)
133 return THROW_ERR_OUT_OF_RANGE(env, "value is out of range");
134 HistogramBase* histogram;
135 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
136 (*histogram)->Record(value);
137 }
138
Create(Environment * env,int64_t lowest,int64_t highest,int figures)139 BaseObjectPtr<HistogramBase> HistogramBase::Create(
140 Environment* env,
141 int64_t lowest,
142 int64_t highest,
143 int figures) {
144 Local<Object> obj;
145 if (!GetConstructorTemplate(env)
146 ->InstanceTemplate()
147 ->NewInstance(env->context()).ToLocal(&obj)) {
148 return BaseObjectPtr<HistogramBase>();
149 }
150
151 return MakeBaseObject<HistogramBase>(
152 env, obj, lowest, highest, figures);
153 }
154
Create(Environment * env,std::shared_ptr<Histogram> histogram)155 BaseObjectPtr<HistogramBase> HistogramBase::Create(
156 Environment* env,
157 std::shared_ptr<Histogram> histogram) {
158 Local<Object> obj;
159 if (!GetConstructorTemplate(env)
160 ->InstanceTemplate()
161 ->NewInstance(env->context()).ToLocal(&obj)) {
162 return BaseObjectPtr<HistogramBase>();
163 }
164 return MakeBaseObject<HistogramBase>(env, obj, std::move(histogram));
165 }
166
New(const FunctionCallbackInfo<Value> & args)167 void HistogramBase::New(const FunctionCallbackInfo<Value>& args) {
168 CHECK(args.IsConstructCall());
169 Environment* env = Environment::GetCurrent(args);
170 new HistogramBase(env, args.This());
171 }
172
GetConstructorTemplate(Environment * env)173 Local<FunctionTemplate> HistogramBase::GetConstructorTemplate(
174 Environment* env) {
175 Local<FunctionTemplate> tmpl = env->histogram_ctor_template();
176 if (tmpl.IsEmpty()) {
177 tmpl = env->NewFunctionTemplate(New);
178 Local<String> classname =
179 FIXED_ONE_BYTE_STRING(env->isolate(), "Histogram");
180 tmpl->SetClassName(classname);
181 tmpl->Inherit(BaseObject::GetConstructorTemplate(env));
182
183 tmpl->InstanceTemplate()->SetInternalFieldCount(
184 HistogramBase::kInternalFieldCount);
185 env->SetProtoMethodNoSideEffect(tmpl, "exceeds", GetExceeds);
186 env->SetProtoMethodNoSideEffect(tmpl, "min", GetMin);
187 env->SetProtoMethodNoSideEffect(tmpl, "max", GetMax);
188 env->SetProtoMethodNoSideEffect(tmpl, "mean", GetMean);
189 env->SetProtoMethodNoSideEffect(tmpl, "stddev", GetStddev);
190 env->SetProtoMethodNoSideEffect(tmpl, "percentile", GetPercentile);
191 env->SetProtoMethodNoSideEffect(tmpl, "percentiles", GetPercentiles);
192 env->SetProtoMethod(tmpl, "reset", DoReset);
193 env->SetProtoMethod(tmpl, "record", Record);
194 env->SetProtoMethod(tmpl, "recordDelta", RecordDelta);
195 env->set_histogram_ctor_template(tmpl);
196 }
197 return tmpl;
198 }
199
Initialize(Environment * env,Local<Object> target)200 void HistogramBase::Initialize(Environment* env, Local<Object> target) {
201 env->SetConstructorFunction(target, "Histogram", GetConstructorTemplate(env));
202 }
203
Deserialize(Environment * env,v8::Local<v8::Context> context,std::unique_ptr<worker::TransferData> self)204 BaseObjectPtr<BaseObject> HistogramBase::HistogramTransferData::Deserialize(
205 Environment* env,
206 v8::Local<v8::Context> context,
207 std::unique_ptr<worker::TransferData> self) {
208 return Create(env, std::move(histogram_));
209 }
210
CloneForMessaging() const211 std::unique_ptr<worker::TransferData> HistogramBase::CloneForMessaging() const {
212 return std::make_unique<HistogramTransferData>(this);
213 }
214
MemoryInfo(MemoryTracker * tracker) const215 void HistogramBase::HistogramTransferData::MemoryInfo(
216 MemoryTracker* tracker) const {
217 tracker->TrackField("histogram", histogram_);
218 }
219
GetConstructorTemplate(Environment * env)220 Local<FunctionTemplate> IntervalHistogram::GetConstructorTemplate(
221 Environment* env) {
222 Local<FunctionTemplate> tmpl = env->intervalhistogram_constructor_template();
223 if (tmpl.IsEmpty()) {
224 tmpl = FunctionTemplate::New(env->isolate());
225 tmpl->Inherit(HandleWrap::GetConstructorTemplate(env));
226 tmpl->InstanceTemplate()->SetInternalFieldCount(
227 HistogramBase::kInternalFieldCount);
228 env->SetProtoMethodNoSideEffect(tmpl, "exceeds", GetExceeds);
229 env->SetProtoMethodNoSideEffect(tmpl, "min", GetMin);
230 env->SetProtoMethodNoSideEffect(tmpl, "max", GetMax);
231 env->SetProtoMethodNoSideEffect(tmpl, "mean", GetMean);
232 env->SetProtoMethodNoSideEffect(tmpl, "stddev", GetStddev);
233 env->SetProtoMethodNoSideEffect(tmpl, "percentile", GetPercentile);
234 env->SetProtoMethodNoSideEffect(tmpl, "percentiles", GetPercentiles);
235 env->SetProtoMethod(tmpl, "reset", DoReset);
236 env->SetProtoMethod(tmpl, "start", Start);
237 env->SetProtoMethod(tmpl, "stop", Stop);
238 env->set_intervalhistogram_constructor_template(tmpl);
239 }
240 return tmpl;
241 }
242
IntervalHistogram(Environment * env,Local<Object> wrap,AsyncWrap::ProviderType type,int32_t interval,int64_t lowest,int64_t highest,int figures)243 IntervalHistogram::IntervalHistogram(
244 Environment* env,
245 Local<Object> wrap,
246 AsyncWrap::ProviderType type,
247 int32_t interval,
248 int64_t lowest,
249 int64_t highest,
250 int figures)
251 : HandleWrap(
252 env,
253 wrap,
254 reinterpret_cast<uv_handle_t*>(&timer_),
255 type),
256 HistogramImpl(lowest, highest, figures),
257 interval_(interval) {
258 MakeWeak();
259 uv_timer_init(env->event_loop(), &timer_);
260 }
261
TimerCB(uv_timer_t * handle)262 void IntervalHistogram::TimerCB(uv_timer_t* handle) {
263 IntervalHistogram* histogram =
264 ContainerOf(&IntervalHistogram::timer_, handle);
265 histogram->OnInterval();
266 }
267
MemoryInfo(MemoryTracker * tracker) const268 void IntervalHistogram::MemoryInfo(MemoryTracker* tracker) const {
269 tracker->TrackField("histogram", histogram());
270 }
271
OnStart(StartFlags flags)272 void IntervalHistogram::OnStart(StartFlags flags) {
273 if (enabled_ || IsHandleClosing()) return;
274 enabled_ = true;
275 if (flags == StartFlags::RESET)
276 histogram()->Reset();
277 uv_timer_start(&timer_, TimerCB, interval_, interval_);
278 uv_unref(reinterpret_cast<uv_handle_t*>(&timer_));
279 }
280
OnStop()281 void IntervalHistogram::OnStop() {
282 if (!enabled_ || IsHandleClosing()) return;
283 enabled_ = false;
284 uv_timer_stop(&timer_);
285 }
286
Start(const FunctionCallbackInfo<Value> & args)287 void IntervalHistogram::Start(const FunctionCallbackInfo<Value>& args) {
288 IntervalHistogram* histogram;
289 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
290 histogram->OnStart(args[0]->IsTrue() ? StartFlags::RESET : StartFlags::NONE);
291 }
292
Stop(const FunctionCallbackInfo<Value> & args)293 void IntervalHistogram::Stop(const FunctionCallbackInfo<Value>& args) {
294 IntervalHistogram* histogram;
295 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
296 histogram->OnStop();
297 }
298
GetMin(const FunctionCallbackInfo<Value> & args)299 void IntervalHistogram::GetMin(const FunctionCallbackInfo<Value>& args) {
300 IntervalHistogram* histogram;
301 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
302 double value = static_cast<double>((*histogram)->Min());
303 args.GetReturnValue().Set(value);
304 }
305
GetMax(const FunctionCallbackInfo<Value> & args)306 void IntervalHistogram::GetMax(const FunctionCallbackInfo<Value>& args) {
307 IntervalHistogram* histogram;
308 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
309 double value = static_cast<double>((*histogram)->Max());
310 args.GetReturnValue().Set(value);
311 }
312
GetMean(const FunctionCallbackInfo<Value> & args)313 void IntervalHistogram::GetMean(const FunctionCallbackInfo<Value>& args) {
314 IntervalHistogram* histogram;
315 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
316 args.GetReturnValue().Set((*histogram)->Mean());
317 }
318
GetExceeds(const FunctionCallbackInfo<Value> & args)319 void IntervalHistogram::GetExceeds(const FunctionCallbackInfo<Value>& args) {
320 IntervalHistogram* histogram;
321 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
322 double value = static_cast<double>((*histogram)->Exceeds());
323 args.GetReturnValue().Set(value);
324 }
325
GetStddev(const FunctionCallbackInfo<Value> & args)326 void IntervalHistogram::GetStddev(const FunctionCallbackInfo<Value>& args) {
327 IntervalHistogram* histogram;
328 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
329 args.GetReturnValue().Set((*histogram)->Stddev());
330 }
331
GetPercentile(const FunctionCallbackInfo<Value> & args)332 void IntervalHistogram::GetPercentile(const FunctionCallbackInfo<Value>& args) {
333 IntervalHistogram* histogram;
334 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
335 CHECK(args[0]->IsNumber());
336 double percentile = args[0].As<Number>()->Value();
337 args.GetReturnValue().Set((*histogram)->Percentile(percentile));
338 }
339
GetPercentiles(const FunctionCallbackInfo<Value> & args)340 void IntervalHistogram::GetPercentiles(
341 const FunctionCallbackInfo<Value>& args) {
342 Environment* env = Environment::GetCurrent(args);
343 IntervalHistogram* histogram;
344 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
345 CHECK(args[0]->IsMap());
346 Local<Map> map = args[0].As<Map>();
347 (*histogram)->Percentiles([map, env](double key, double value) {
348 map->Set(
349 env->context(),
350 Number::New(env->isolate(), key),
351 Number::New(env->isolate(), value)).IsEmpty();
352 });
353 }
354
DoReset(const FunctionCallbackInfo<Value> & args)355 void IntervalHistogram::DoReset(const FunctionCallbackInfo<Value>& args) {
356 IntervalHistogram* histogram;
357 ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
358 (*histogram)->Reset();
359 }
360
361 std::unique_ptr<worker::TransferData>
CloneForMessaging() const362 IntervalHistogram::CloneForMessaging() const {
363 return std::make_unique<HistogramBase::HistogramTransferData>(histogram());
364 }
365
366 } // namespace node
367