61 std::lock_guard lock{mImpl->mutex};
62 const auto it = mImpl->entries.find(
key);
63 if (it == mImpl->entries.end() || it->second.nSamples == 0) {
64 return mImpl->cfg.floorSlots;
66 const auto& e = it->second;
67 const double raw = double(e.ratio) * scale * double(e.margin);
68 if (!std::isfinite(
raw) ||
raw < 0.) {
69 return mImpl->cfg.floorSlots;
75 const size_t ceiling = std::max(mImpl->cfg.floorSlots,
static_cast<size_t>(
double(e.maxEmitted) *
double(mImpl->cfg.marginMax)));
76 if (
raw >=
static_cast<double>(ceiling)) {
79 return std::max(mImpl->cfg.floorSlots,
static_cast<size_t>(std::ceil(
raw)));
84 std::lock_guard lock{mImpl->mutex};
85 const auto it = mImpl->entries.find(
key);
86 if (it == mImpl->entries.end() || it->second.maxEmitted == 0) {
87 return mImpl->cfg.floorSlots;
89 const auto& e = it->second;
90 const double raw = double(e.maxEmitted) * double(e.margin);
91 if (!std::isfinite(
raw) ||
raw >=
static_cast<double>(std::numeric_limits<size_t>::max())) {
92 return std::numeric_limits<size_t>::max();
94 return std::max(mImpl->cfg.floorSlots,
static_cast<size_t>(std::ceil(
raw)));
116 std::lock_guard lock{mImpl->mutex};
117 auto& e = mImpl->entries[
key];
118 const auto& cfg = mImpl->cfg;
120 const bool firstSample = e.nSamples == 0;
122 e.margin = cfg.marginInit;
124 const auto sample =
static_cast<float>(double(emitted) / scale);
125 e.ratio = firstSample ? sample : (cfg.alpha * sample) + ((1.f - cfg.alpha) * e.ratio);
126 e.maxEmitted = std::max(e.maxEmitted, emitted);
131 e.margin = std::max(cfg.marginMin, e.margin * cfg.marginDown);
138 const float shortfall = capacityUsed ?
static_cast<float>(double(emitted) / double(capacityUsed)) : cfg.marginUp;
139 e.margin = std::min(cfg.marginMax, e.margin * std::clamp(shortfall * cfg.marginOverflowSlack, 1.02f, cfg.marginUp));
143 const float util = capacityUsed ? float(
double(emitted) /
double(capacityUsed)) : 1.f;
144 if (util < cfg.lowWatermark) {
145 if (++e.nLowStreak >= cfg.decayAfter) {
146 e.margin = std::max(cfg.marginMin, e.margin * cfg.marginDown);
149 }
else if (e.nLowStreak > 0) {
156 std::lock_guard lock{mImpl->mutex};
157 std::vector<KeyType> keys;
158 keys.reserve(mImpl->entries.size());
159 for (
const auto& [
key, _] : mImpl->entries) {
163 const auto da = decodeKey(a);
164 const auto db = decodeKey(b);
165 return std::tie(da.site, da.iteration, da.variant, da.slot) <
166 std::tie(db.site, db.iteration, db.variant, db.slot);
171 LOGP(info,
"Printing CapacityEstimators:");
172 for (
const auto key : keys) {
173 const auto&
value = mImpl->entries.at(
key);
175 LOGP(info,
"\tSite:{} | iter:{} | var:({},{}) | slot:{} | ratio:{} | margin:{} | maxEmitted:{} | sam:{} | low:{} | overflows:{}",
SlabSiteNames[decoded.site], decoded.iteration,
getVariantHigh(decoded.variant),
getVariantLow(decoded.variant), decoded.slot,
value.ratio,
value.margin,
value.maxEmitted,
value.nSamples,
value.nLowStreak,
value.nOverflows);