#pragma once #include <library/cpp/json/json_value.h> #include <library/cpp/json/writer/json.h> #include <library/cpp/threading/future/async.h> #include <util/generic/algorithm.h> #include <util/generic/hash.h> #include <util/generic/utility.h> #include <util/generic/vector.h> #include <util/generic/yexception.h> #include <util/stream/format.h> #include <util/string/builder.h> #include <util/thread/pool.h> #include <util/system/mutex.h> namespace NSimpleHistogram { template <typename T> class THistogram { public: explicit THistogram(TVector<T>&& values) : Values_(std::move(values)) { } size_t TotalCount() const { return Values_.size(); } T ValueAtPercentile(double percentile) const { Y_ASSERT(!Values_.empty()); Y_ASSERT(percentile >= 0.0 && percentile <= 1.0); const size_t index = static_cast<size_t>(percentile * Values_.size()); return Values_[Min(Values_.size() - 1, index)]; } private: TVector<T> Values_; }; template <typename T> class THistogramCalcer { public: size_t TotalCount() const { return Values_.size(); } void Reserve(size_t cnt) { Values_.reserve(cnt); } void RecordValue(T value) { Values_.push_back(value); } THistogram<T> Calc() { if (!IsSorted(Values_.begin(), Values_.end())) { Sort(Values_.begin(), Values_.end()); } return THistogram<T>(std::move(Values_)); } private: TVector<T> Values_; }; template <typename T> class TMultiHistogramCalcer { public: void RecordValue(TStringBuf name, T value) { Calcers_[name].RecordValue(value); } THashMap<TString, THistogram<T>> Calc() { THashMap<TString, THistogram<T>> result; for (auto& calcer : Calcers_) { result.emplace(calcer.first, calcer.second.Calc()); } return result; } private: THashMap<TString, THistogramCalcer<T>> Calcers_; }; template <typename T> class TThreadSafeMultiHistogramCalcer { public: void RecordValue(TStringBuf name, T value) { TGuard<TMutex> guard(Mutex_); Calcer_.RecordValue(name, value); } THashMap<TString, THistogram<T>> Calc() { return Calcer_.Calc(); } private: TMutex Mutex_; TMultiHistogramCalcer<T> Calcer_; }; template <typename T> NJson::TJsonValue ToJson(const THistogram<T>& hist, const TVector<double>& percentiles) { NJson::TJsonValue json; for (double percentile : percentiles) { TStringBuilder name; name << "Q" << Prec(percentile * 100, PREC_POINT_DIGITS_STRIP_ZEROES, 2); json[name] = hist.ValueAtPercentile(percentile); } json["RecordCount"] = hist.TotalCount(); return json; } template <typename T> NJson::TJsonValue ToJson(const THashMap<TString, THistogram<T>>& hists, const TVector<double>& percentiles) { NJson::TJsonValue json; for (const auto& p : hists) { json[p.first] = ToJson(p.second, percentiles); } return json; } template <typename T> TString ToJsonStr(const THashMap<TString, THistogram<T>>& hists, const TVector<double>& percentiles, bool format = true) { NJson::TJsonValue json = ToJson(hists, percentiles); NJsonWriter::TBuf buf; if (format) { buf.SetIndentSpaces(4); } return buf.WriteJsonValue(&json, true).Str(); } }