histogram_snapshot.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #pragma once
  2. #include <util/generic/array_ref.h>
  3. #include <util/generic/ptr.h>
  4. #include <util/generic/vector.h>
  5. #include <util/generic/yexception.h>
  6. #include <util/generic/ylimits.h>
  7. #include <cmath>
  8. #include <limits>
  9. namespace NMonitoring {
  10. using TBucketBound = double;
  11. using TBucketValue = ui64;
  12. using TBucketBounds = TVector<TBucketBound>;
  13. using TBucketValues = TVector<TBucketValue>;
  14. constexpr ui32 HISTOGRAM_MAX_BUCKETS_COUNT = 51;
  15. constexpr TBucketBound HISTOGRAM_INF_BOUND = std::numeric_limits<TBucketBound>::max();
  16. ///////////////////////////////////////////////////////////////////////////
  17. // IHistogramSnapshot
  18. ///////////////////////////////////////////////////////////////////////////
  19. class IHistogramSnapshot: public TAtomicRefCount<IHistogramSnapshot> {
  20. public:
  21. virtual ~IHistogramSnapshot() = default;
  22. /**
  23. * @return buckets count.
  24. */
  25. virtual ui32 Count() const = 0;
  26. /**
  27. * @return upper bound for the bucket with particular index.
  28. */
  29. virtual TBucketBound UpperBound(ui32 index) const = 0;
  30. /**
  31. * @return value stored in the bucket with particular index.
  32. */
  33. virtual TBucketValue Value(ui32 index) const = 0;
  34. };
  35. using IHistogramSnapshotPtr = TIntrusivePtr<IHistogramSnapshot>;
  36. ///////////////////////////////////////////////////////////////////////////////
  37. // TLinearHistogramSnapshot
  38. ///////////////////////////////////////////////////////////////////////////////
  39. class TLinearHistogramSnapshot: public IHistogramSnapshot {
  40. public:
  41. TLinearHistogramSnapshot(
  42. TBucketBound startValue, TBucketBound bucketWidth, TBucketValues values)
  43. : StartValue_(startValue)
  44. , BucketWidth_(bucketWidth)
  45. , Values_(std::move(values))
  46. {
  47. }
  48. ui32 Count() const override {
  49. return static_cast<ui32>(Values_.size());
  50. }
  51. TBucketBound UpperBound(ui32 index) const override {
  52. Y_ASSERT(index < Values_.size());
  53. if (index == Count() - 1) {
  54. return Max<TBucketBound>();
  55. }
  56. return StartValue_ + BucketWidth_ * index;
  57. }
  58. TBucketValue Value(ui32 index) const override {
  59. Y_ASSERT(index < Values_.size());
  60. return Values_[index];
  61. }
  62. ui64 MemorySizeBytes() {
  63. return sizeof(*this) + Values_.capacity() * sizeof(decltype(Values_)::value_type);
  64. }
  65. private:
  66. TBucketBound StartValue_;
  67. TBucketBound BucketWidth_;
  68. TBucketValues Values_;
  69. };
  70. ///////////////////////////////////////////////////////////////////////////
  71. // TExponentialHistogramSnapshot
  72. ///////////////////////////////////////////////////////////////////////////
  73. class TExponentialHistogramSnapshot: public IHistogramSnapshot {
  74. public:
  75. TExponentialHistogramSnapshot(
  76. double base, double scale, TBucketValues values)
  77. : Base_(base)
  78. , Scale_(scale)
  79. , Values_(std::move(values))
  80. {
  81. }
  82. ui32 Count() const override {
  83. return static_cast<ui32>(Values_.size());
  84. }
  85. TBucketBound UpperBound(ui32 index) const override {
  86. Y_ASSERT(index < Values_.size());
  87. if (index == Values_.size() - 1) {
  88. return Max<TBucketBound>();
  89. }
  90. return std::round(Scale_ * std::pow(Base_, index));
  91. }
  92. TBucketValue Value(ui32 index) const override {
  93. Y_ASSERT(index < Values_.size());
  94. return Values_[index];
  95. }
  96. ui64 MemorySizeBytes() {
  97. return sizeof(*this) + Values_.capacity() * sizeof(decltype(Values_)::value_type);
  98. }
  99. private:
  100. double Base_;
  101. double Scale_;
  102. TBucketValues Values_;
  103. };
  104. using TBucket = std::pair<TBucketBound, TBucketValue>;
  105. ///////////////////////////////////////////////////////////////////////
  106. // TExplicitHistogramSnapshot
  107. ///////////////////////////////////////////////////////////////////////
  108. //
  109. // Memory layout (single contiguous block):
  110. //
  111. // +------+-----------+--------------+--------+--------+- -+--------+--------+
  112. // | vptr | RefsCount | BucketsCount | Bound1 | Value1 | ... | BoundN | ValueN |
  113. // +------+-----------+--------------+--------+--------+- -+--------+--------+
  114. //
  115. class alignas(TBucketValue) TExplicitHistogramSnapshot: public IHistogramSnapshot, private TNonCopyable {
  116. public:
  117. static TIntrusivePtr<TExplicitHistogramSnapshot> New(ui32 bucketsCount) {
  118. size_t bucketsSize = bucketsCount * sizeof(TBucket);
  119. Y_ENSURE(bucketsCount <= HISTOGRAM_MAX_BUCKETS_COUNT, "Cannot allocate a histogram with " << bucketsCount
  120. << " buckets. Bucket count is limited to " << HISTOGRAM_MAX_BUCKETS_COUNT);
  121. return new(bucketsSize) TExplicitHistogramSnapshot(bucketsCount);
  122. }
  123. TBucket& operator[](ui32 index) noexcept {
  124. return Bucket(index);
  125. }
  126. ui32 Count() const override {
  127. return BucketsCount_;
  128. }
  129. TBucketBound UpperBound(ui32 index) const override {
  130. return Bucket(index).first;
  131. }
  132. TBucketValue Value(ui32 index) const override {
  133. return Bucket(index).second;
  134. }
  135. ui64 MemorySizeBytes() const {
  136. return sizeof(*this) + BucketsCount_ * sizeof(TBucket);
  137. }
  138. private:
  139. explicit TExplicitHistogramSnapshot(ui32 bucketsCount) noexcept
  140. : BucketsCount_(bucketsCount)
  141. {
  142. }
  143. static void* operator new(size_t size, size_t bucketsSize) {
  144. return ::operator new(size + bucketsSize);
  145. }
  146. static void operator delete(void* mem) {
  147. ::operator delete(mem);
  148. }
  149. static void operator delete(void* mem, size_t, size_t) {
  150. // this operator can be called as paired for custom new operator
  151. ::operator delete(mem);
  152. }
  153. TBucket& Bucket(ui32 index) noexcept {
  154. Y_DEBUG_ABORT_UNLESS(index < BucketsCount_);
  155. return *(reinterpret_cast<TBucket*>(this + 1) + index);
  156. }
  157. const TBucket& Bucket(ui32 index) const noexcept {
  158. Y_DEBUG_ABORT_UNLESS(index < BucketsCount_);
  159. return *(reinterpret_cast<const TBucket*>(this + 1) + index);
  160. }
  161. private:
  162. ui32 BucketsCount_;
  163. };
  164. static_assert(alignof(TExplicitHistogramSnapshot) == alignof(TBucket),
  165. "mismatched alingments of THistogramSnapshot and TBucket");
  166. IHistogramSnapshotPtr ExplicitHistogramSnapshot(TConstArrayRef<TBucketBound> bounds, TConstArrayRef<TBucketValue> values, bool shrinkBuckets = false);
  167. } // namespace NMonitoring
  168. std::ostream& operator<<(std::ostream& os, const NMonitoring::IHistogramSnapshot& hist);