/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include #include namespace folly { class PredefinedQuantiles { public: class Default { public: static constexpr std::array kQuantiles{ 0.0, 0.001, 0.01, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99, 0.999, 1.0}; }; class MinAndMax { public: static constexpr std::array kQuantiles{0.0, 1.0}; }; class Median { public: static constexpr std::array kQuantiles{0.0, 0.5, 1.0}; }; class P01 { public: static constexpr std::array kQuantiles{0.0, 0.01, 1.0}; }; class P99 { public: static constexpr std::array kQuantiles{0.0, 0.99, 1.0}; }; class MedianAndHigh { public: static constexpr std::array kQuantiles{ 0.0, 0.5, 0.9, 0.99, 0.999, 1.0}; }; class Quartiles { public: static constexpr std::array kQuantiles{ 0.0, 0.25, 0.5, 0.75, 1.0}; }; class Deciles { public: static constexpr std::array kQuantiles{ 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}; }; class Ventiles { public: static constexpr std::array kQuantiles{ 0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0}; }; }; template class QuantileHistogram { public: QuantileHistogram() = default; explicit QuantileHistogram(size_t) : QuantileHistogram() {} static constexpr decltype(Q::kQuantiles) quantiles() { return Q::kQuantiles; } /* * Combines the given histograms into a new histogram where the locations for * each tracked quantile is the weighted average of the corresponding quantile * locations. The min and max for the new histogram will be the smallest min * or the largest max of all of the given histograms. */ static QuantileHistogram merge( Range*> qhists); QuantileHistogram merge(Range unsortedValues) const; void addValue(double value); /* * Estimates the value of the given quantile. */ double estimateQuantile(double q) const; uint64_t count() const { return count_; } bool empty() const { return count_ == 0; } double min() const { return locations_.front(); } double max() const { return locations_.back(); } std::string debugString() const; private: static_assert(quantiles().size() >= 2, "Quantiles 0.0 and 1.0 are required."); static_assert(quantiles().front() == 0.0, "Quantile 0.0 is required."); static_assert(quantiles().back() == 1.0, "Quantile 1.0 is required."); // locations_ tracks min and max at the two ends. typename std::remove_const::type locations_{}; uint64_t count_{0}; inline size_t addValueImpl( double value, const decltype(Q::kQuantiles)& oldLocations); void dcheckSane() const; }; // The CPUShardedQuantileHistogram class behaves similarly to QuantileHistogram // except that it is thread-safe. Adding values is heavily optimized while any // kind of inference will incur a heavy cost because all cpu-local shards must // be merged. template class CPUShardedQuantileHistogram { public: CPUShardedQuantileHistogram() : histBuilder_( /*bufferSize=*/hardware_destructive_interference_size / sizeof(double), /*digestSize=*/0) {} static constexpr decltype(Q::kQuantiles) quantiles() { return Q::kQuantiles; } void addValue(double value); double estimateQuantile(double q); uint64_t count(); double min(); double max(); std::string debugString(); private: mutable SharedMutex mtx_; QuantileHistogram mergedHist_; DigestBuilder> histBuilder_; // Assumes mtx is held. void flush(); }; } // namespace folly #include