• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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