| #include "histogram.h" // NOLINT(build/include_inline) |
| #include "histogram-inl.h" |
| #include "base_object-inl.h" |
| #include "memory_tracker-inl.h" |
| #include "node_errors.h" |
| namespace node { |
| |
| using v8::BigInt; |
| using v8::FunctionCallbackInfo; |
| using v8::FunctionTemplate; |
| using v8::Local; |
| using v8::Map; |
| using v8::Number; |
| using v8::Object; |
| using v8::String; |
| using v8::Value; |
| |
| Histogram::Histogram(int64_t lowest, int64_t highest, int figures) { |
| hdr_histogram* histogram; |
| CHECK_EQ(0, hdr_init(lowest, highest, figures, &histogram)); |
| histogram_.reset(histogram); |
| } |
| |
| void Histogram::MemoryInfo(MemoryTracker* tracker) const { |
| tracker->TrackFieldWithSize("histogram", GetMemorySize()); |
| } |
| |
| HistogramImpl::HistogramImpl(int64_t lowest, int64_t highest, int figures) |
| : histogram_(new Histogram(lowest, highest, figures)) {} |
| |
| HistogramImpl::HistogramImpl(std::shared_ptr<Histogram> histogram) |
| : histogram_(std::move(histogram)) {} |
| |
| HistogramBase::HistogramBase( |
| Environment* env, |
| Local<Object> wrap, |
| int64_t lowest, |
| int64_t highest, |
| int figures) |
| : BaseObject(env, wrap), |
| HistogramImpl(lowest, highest, figures) { |
| MakeWeak(); |
| } |
| |
| HistogramBase::HistogramBase( |
| Environment* env, |
| Local<Object> wrap, |
| std::shared_ptr<Histogram> histogram) |
| : BaseObject(env, wrap), |
| HistogramImpl(std::move(histogram)) { |
| MakeWeak(); |
| } |
| |
| void HistogramBase::MemoryInfo(MemoryTracker* tracker) const { |
| tracker->TrackField("histogram", histogram()); |
| } |
| |
| void HistogramBase::GetMin(const FunctionCallbackInfo<Value>& args) { |
| HistogramBase* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| double value = static_cast<double>((*histogram)->Min()); |
| args.GetReturnValue().Set(value); |
| } |
| |
| void HistogramBase::GetMax(const FunctionCallbackInfo<Value>& args) { |
| HistogramBase* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| double value = static_cast<double>((*histogram)->Max()); |
| args.GetReturnValue().Set(value); |
| } |
| |
| void HistogramBase::GetMean(const FunctionCallbackInfo<Value>& args) { |
| HistogramBase* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| args.GetReturnValue().Set((*histogram)->Mean()); |
| } |
| |
| void HistogramBase::GetExceeds(const FunctionCallbackInfo<Value>& args) { |
| HistogramBase* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| double value = static_cast<double>((*histogram)->Exceeds()); |
| args.GetReturnValue().Set(value); |
| } |
| |
| void HistogramBase::GetStddev(const FunctionCallbackInfo<Value>& args) { |
| HistogramBase* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| args.GetReturnValue().Set((*histogram)->Stddev()); |
| } |
| |
| void HistogramBase::GetPercentile(const FunctionCallbackInfo<Value>& args) { |
| HistogramBase* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| CHECK(args[0]->IsNumber()); |
| double percentile = args[0].As<Number>()->Value(); |
| args.GetReturnValue().Set((*histogram)->Percentile(percentile)); |
| } |
| |
| void HistogramBase::GetPercentiles(const FunctionCallbackInfo<Value>& args) { |
| Environment* env = Environment::GetCurrent(args); |
| HistogramBase* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| CHECK(args[0]->IsMap()); |
| Local<Map> map = args[0].As<Map>(); |
| (*histogram)->Percentiles([map, env](double key, double value) { |
| map->Set( |
| env->context(), |
| Number::New(env->isolate(), key), |
| Number::New(env->isolate(), value)).IsEmpty(); |
| }); |
| } |
| |
| void HistogramBase::DoReset(const FunctionCallbackInfo<Value>& args) { |
| HistogramBase* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| (*histogram)->Reset(); |
| } |
| |
| void HistogramBase::RecordDelta(const FunctionCallbackInfo<Value>& args) { |
| HistogramBase* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| (*histogram)->RecordDelta(); |
| } |
| |
| void HistogramBase::Record(const FunctionCallbackInfo<Value>& args) { |
| Environment* env = Environment::GetCurrent(args); |
| CHECK_IMPLIES(!args[0]->IsNumber(), args[0]->IsBigInt()); |
| bool lossless = true; |
| int64_t value = args[0]->IsBigInt() |
| ? args[0].As<BigInt>()->Int64Value(&lossless) |
| : static_cast<int64_t>(args[0].As<Number>()->Value()); |
| if (!lossless || value < 1) |
| return THROW_ERR_OUT_OF_RANGE(env, "value is out of range"); |
| HistogramBase* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| (*histogram)->Record(value); |
| } |
| |
| BaseObjectPtr<HistogramBase> HistogramBase::Create( |
| Environment* env, |
| int64_t lowest, |
| int64_t highest, |
| int figures) { |
| Local<Object> obj; |
| if (!GetConstructorTemplate(env) |
| ->InstanceTemplate() |
| ->NewInstance(env->context()).ToLocal(&obj)) { |
| return BaseObjectPtr<HistogramBase>(); |
| } |
| |
| return MakeBaseObject<HistogramBase>( |
| env, obj, lowest, highest, figures); |
| } |
| |
| BaseObjectPtr<HistogramBase> HistogramBase::Create( |
| Environment* env, |
| std::shared_ptr<Histogram> histogram) { |
| Local<Object> obj; |
| if (!GetConstructorTemplate(env) |
| ->InstanceTemplate() |
| ->NewInstance(env->context()).ToLocal(&obj)) { |
| return BaseObjectPtr<HistogramBase>(); |
| } |
| return MakeBaseObject<HistogramBase>(env, obj, std::move(histogram)); |
| } |
| |
| void HistogramBase::New(const FunctionCallbackInfo<Value>& args) { |
| CHECK(args.IsConstructCall()); |
| Environment* env = Environment::GetCurrent(args); |
| new HistogramBase(env, args.This()); |
| } |
| |
| Local<FunctionTemplate> HistogramBase::GetConstructorTemplate( |
| Environment* env) { |
| Local<FunctionTemplate> tmpl = env->histogram_ctor_template(); |
| if (tmpl.IsEmpty()) { |
| tmpl = env->NewFunctionTemplate(New); |
| Local<String> classname = |
| FIXED_ONE_BYTE_STRING(env->isolate(), "Histogram"); |
| tmpl->SetClassName(classname); |
| tmpl->Inherit(BaseObject::GetConstructorTemplate(env)); |
| |
| tmpl->InstanceTemplate()->SetInternalFieldCount( |
| HistogramBase::kInternalFieldCount); |
| env->SetProtoMethodNoSideEffect(tmpl, "exceeds", GetExceeds); |
| env->SetProtoMethodNoSideEffect(tmpl, "min", GetMin); |
| env->SetProtoMethodNoSideEffect(tmpl, "max", GetMax); |
| env->SetProtoMethodNoSideEffect(tmpl, "mean", GetMean); |
| env->SetProtoMethodNoSideEffect(tmpl, "stddev", GetStddev); |
| env->SetProtoMethodNoSideEffect(tmpl, "percentile", GetPercentile); |
| env->SetProtoMethodNoSideEffect(tmpl, "percentiles", GetPercentiles); |
| env->SetProtoMethod(tmpl, "reset", DoReset); |
| env->SetProtoMethod(tmpl, "record", Record); |
| env->SetProtoMethod(tmpl, "recordDelta", RecordDelta); |
| env->set_histogram_ctor_template(tmpl); |
| } |
| return tmpl; |
| } |
| |
| void HistogramBase::Initialize(Environment* env, Local<Object> target) { |
| env->SetConstructorFunction(target, "Histogram", GetConstructorTemplate(env)); |
| } |
| |
| BaseObjectPtr<BaseObject> HistogramBase::HistogramTransferData::Deserialize( |
| Environment* env, |
| v8::Local<v8::Context> context, |
| std::unique_ptr<worker::TransferData> self) { |
| return Create(env, std::move(histogram_)); |
| } |
| |
| std::unique_ptr<worker::TransferData> HistogramBase::CloneForMessaging() const { |
| return std::make_unique<HistogramTransferData>(this); |
| } |
| |
| void HistogramBase::HistogramTransferData::MemoryInfo( |
| MemoryTracker* tracker) const { |
| tracker->TrackField("histogram", histogram_); |
| } |
| |
| Local<FunctionTemplate> IntervalHistogram::GetConstructorTemplate( |
| Environment* env) { |
| Local<FunctionTemplate> tmpl = env->intervalhistogram_constructor_template(); |
| if (tmpl.IsEmpty()) { |
| tmpl = FunctionTemplate::New(env->isolate()); |
| tmpl->Inherit(HandleWrap::GetConstructorTemplate(env)); |
| tmpl->InstanceTemplate()->SetInternalFieldCount( |
| HistogramBase::kInternalFieldCount); |
| env->SetProtoMethodNoSideEffect(tmpl, "exceeds", GetExceeds); |
| env->SetProtoMethodNoSideEffect(tmpl, "min", GetMin); |
| env->SetProtoMethodNoSideEffect(tmpl, "max", GetMax); |
| env->SetProtoMethodNoSideEffect(tmpl, "mean", GetMean); |
| env->SetProtoMethodNoSideEffect(tmpl, "stddev", GetStddev); |
| env->SetProtoMethodNoSideEffect(tmpl, "percentile", GetPercentile); |
| env->SetProtoMethodNoSideEffect(tmpl, "percentiles", GetPercentiles); |
| env->SetProtoMethod(tmpl, "reset", DoReset); |
| env->SetProtoMethod(tmpl, "start", Start); |
| env->SetProtoMethod(tmpl, "stop", Stop); |
| env->set_intervalhistogram_constructor_template(tmpl); |
| } |
| return tmpl; |
| } |
| |
| IntervalHistogram::IntervalHistogram( |
| Environment* env, |
| Local<Object> wrap, |
| AsyncWrap::ProviderType type, |
| int32_t interval, |
| int64_t lowest, |
| int64_t highest, |
| int figures) |
| : HandleWrap( |
| env, |
| wrap, |
| reinterpret_cast<uv_handle_t*>(&timer_), |
| type), |
| HistogramImpl(lowest, highest, figures), |
| interval_(interval) { |
| MakeWeak(); |
| uv_timer_init(env->event_loop(), &timer_); |
| } |
| |
| void IntervalHistogram::TimerCB(uv_timer_t* handle) { |
| IntervalHistogram* histogram = |
| ContainerOf(&IntervalHistogram::timer_, handle); |
| histogram->OnInterval(); |
| } |
| |
| void IntervalHistogram::MemoryInfo(MemoryTracker* tracker) const { |
| tracker->TrackField("histogram", histogram()); |
| } |
| |
| void IntervalHistogram::OnStart(StartFlags flags) { |
| if (enabled_ || IsHandleClosing()) return; |
| enabled_ = true; |
| if (flags == StartFlags::RESET) |
| histogram()->Reset(); |
| uv_timer_start(&timer_, TimerCB, interval_, interval_); |
| uv_unref(reinterpret_cast<uv_handle_t*>(&timer_)); |
| } |
| |
| void IntervalHistogram::OnStop() { |
| if (!enabled_ || IsHandleClosing()) return; |
| enabled_ = false; |
| uv_timer_stop(&timer_); |
| } |
| |
| void IntervalHistogram::Start(const FunctionCallbackInfo<Value>& args) { |
| IntervalHistogram* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| histogram->OnStart(args[0]->IsTrue() ? StartFlags::RESET : StartFlags::NONE); |
| } |
| |
| void IntervalHistogram::Stop(const FunctionCallbackInfo<Value>& args) { |
| IntervalHistogram* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| histogram->OnStop(); |
| } |
| |
| void IntervalHistogram::GetMin(const FunctionCallbackInfo<Value>& args) { |
| IntervalHistogram* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| double value = static_cast<double>((*histogram)->Min()); |
| args.GetReturnValue().Set(value); |
| } |
| |
| void IntervalHistogram::GetMax(const FunctionCallbackInfo<Value>& args) { |
| IntervalHistogram* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| double value = static_cast<double>((*histogram)->Max()); |
| args.GetReturnValue().Set(value); |
| } |
| |
| void IntervalHistogram::GetMean(const FunctionCallbackInfo<Value>& args) { |
| IntervalHistogram* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| args.GetReturnValue().Set((*histogram)->Mean()); |
| } |
| |
| void IntervalHistogram::GetExceeds(const FunctionCallbackInfo<Value>& args) { |
| IntervalHistogram* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| double value = static_cast<double>((*histogram)->Exceeds()); |
| args.GetReturnValue().Set(value); |
| } |
| |
| void IntervalHistogram::GetStddev(const FunctionCallbackInfo<Value>& args) { |
| IntervalHistogram* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| args.GetReturnValue().Set((*histogram)->Stddev()); |
| } |
| |
| void IntervalHistogram::GetPercentile(const FunctionCallbackInfo<Value>& args) { |
| IntervalHistogram* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| CHECK(args[0]->IsNumber()); |
| double percentile = args[0].As<Number>()->Value(); |
| args.GetReturnValue().Set((*histogram)->Percentile(percentile)); |
| } |
| |
| void IntervalHistogram::GetPercentiles( |
| const FunctionCallbackInfo<Value>& args) { |
| Environment* env = Environment::GetCurrent(args); |
| IntervalHistogram* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| CHECK(args[0]->IsMap()); |
| Local<Map> map = args[0].As<Map>(); |
| (*histogram)->Percentiles([map, env](double key, double value) { |
| map->Set( |
| env->context(), |
| Number::New(env->isolate(), key), |
| Number::New(env->isolate(), value)).IsEmpty(); |
| }); |
| } |
| |
| void IntervalHistogram::DoReset(const FunctionCallbackInfo<Value>& args) { |
| IntervalHistogram* histogram; |
| ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder()); |
| (*histogram)->Reset(); |
| } |
| |
| std::unique_ptr<worker::TransferData> |
| IntervalHistogram::CloneForMessaging() const { |
| return std::make_unique<HistogramBase::HistogramTransferData>(histogram()); |
| } |
| |
| } // namespace node |