mirror of https://github.com/facebook/rocksdb.git
499 lines
15 KiB
C++
499 lines
15 KiB
C++
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
// (found in the LICENSE.Apache file in the root directory).
|
|
|
|
#include "util/ribbon_config.h"
|
|
|
|
namespace ROCKSDB_NAMESPACE::ribbon::detail {
|
|
|
|
// Each instantiation of this struct is sufficiently unique for configuration
|
|
// purposes, and is only instantiated for settings where we support the
|
|
// configuration API. An application might only reference one instantiation,
|
|
// meaning the rest could be pruned at link time.
|
|
template <ConstructionFailureChance kCfc, uint64_t kCoeffBits, bool kUseSmash>
|
|
struct BandingConfigHelperData {
|
|
static constexpr size_t kKnownSize = 18U;
|
|
|
|
// Because of complexity in the data, for smaller numbers of slots
|
|
// (powers of two up to 2^17), we record known numbers that can be added
|
|
// with kCfc chance of construction failure and settings in template
|
|
// parameters. Zero means "unsupported (too small) number of slots".
|
|
// (GetNumToAdd below will use interpolation for numbers of slots
|
|
// between powers of two; double rather than integer values here make
|
|
// that more accurate.)
|
|
static const std::array<double, kKnownSize> kKnownToAddByPow2;
|
|
|
|
// For sufficiently large number of slots, doubling the number of
|
|
// slots will increase the expected overhead (slots over number added)
|
|
// by approximately this constant.
|
|
// (This is roughly constant regardless of ConstructionFailureChance and
|
|
// smash setting.)
|
|
// (Would be a constant if we had partial template specialization for
|
|
// static const members.)
|
|
static inline double GetFactorPerPow2() {
|
|
if (kCoeffBits == 128U) {
|
|
return 0.0038;
|
|
} else {
|
|
assert(kCoeffBits == 64U);
|
|
return 0.0083;
|
|
}
|
|
}
|
|
|
|
// Overhead factor for 2^(kKnownSize-1) slots
|
|
// (Would be a constant if we had partial template specialization for
|
|
// static const members.)
|
|
static inline double GetFinalKnownFactor() {
|
|
return 1.0 * (uint32_t{1} << (kKnownSize - 1)) /
|
|
kKnownToAddByPow2[kKnownSize - 1];
|
|
}
|
|
|
|
// GetFinalKnownFactor() - (kKnownSize-1) * GetFactorPerPow2()
|
|
// (Would be a constant if we had partial template specialization for
|
|
// static const members.)
|
|
static inline double GetBaseFactor() {
|
|
return GetFinalKnownFactor() - (kKnownSize - 1) * GetFactorPerPow2();
|
|
}
|
|
|
|
// Get overhead factor (slots over number to add) for sufficiently large
|
|
// number of slots (by log base 2)
|
|
static inline double GetFactorForLarge(double log2_num_slots) {
|
|
return GetBaseFactor() + log2_num_slots * GetFactorPerPow2();
|
|
}
|
|
|
|
// For a given power of two number of slots (specified by whole number
|
|
// log base 2), implements GetNumToAdd for such limited case, returning
|
|
// double for better interpolation in GetNumToAdd and GetNumSlots.
|
|
static inline double GetNumToAddForPow2(uint32_t log2_num_slots) {
|
|
assert(log2_num_slots <= 32); // help clang-analyze
|
|
if (log2_num_slots < kKnownSize) {
|
|
return kKnownToAddByPow2[log2_num_slots];
|
|
} else {
|
|
return 1.0 * (uint64_t{1} << log2_num_slots) /
|
|
GetFactorForLarge(1.0 * log2_num_slots);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Based on data from FindOccupancy in ribbon_test
|
|
template <>
|
|
const std::array<double, 18>
|
|
BandingConfigHelperData<kOneIn2, 128U, false>::kKnownToAddByPow2{{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
252.984,
|
|
506.109,
|
|
1013.71,
|
|
2029.47,
|
|
4060.43,
|
|
8115.63,
|
|
16202.2,
|
|
32305.1,
|
|
64383.5,
|
|
128274,
|
|
}};
|
|
|
|
template <>
|
|
const std::array<double, 18>
|
|
BandingConfigHelperData<kOneIn2, 128U, /*smash*/ true>::kKnownToAddByPow2{{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
126.274,
|
|
254.279,
|
|
510.27,
|
|
1022.24,
|
|
2046.02,
|
|
4091.99,
|
|
8154.98,
|
|
16244.3,
|
|
32349.7,
|
|
64426.6,
|
|
128307,
|
|
}};
|
|
|
|
template <>
|
|
const std::array<double, 18>
|
|
BandingConfigHelperData<kOneIn2, 64U, false>::kKnownToAddByPow2{{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
124.94,
|
|
249.968,
|
|
501.234,
|
|
1004.06,
|
|
2006.15,
|
|
3997.89,
|
|
7946.99,
|
|
15778.4,
|
|
31306.9,
|
|
62115.3,
|
|
123284,
|
|
}};
|
|
|
|
template <>
|
|
const std::array<double, 18>
|
|
BandingConfigHelperData<kOneIn2, 64U, /*smash*/ true>::kKnownToAddByPow2{{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
62.2683,
|
|
126.259,
|
|
254.268,
|
|
509.975,
|
|
1019.98,
|
|
2026.16,
|
|
4019.75,
|
|
7969.8,
|
|
15798.2,
|
|
31330.3,
|
|
62134.2,
|
|
123255,
|
|
}};
|
|
|
|
template <>
|
|
const std::array<double, 18>
|
|
BandingConfigHelperData<kOneIn20, 128U, false>::kKnownToAddByPow2{{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
248.851,
|
|
499.532,
|
|
1001.26,
|
|
2003.97,
|
|
4005.59,
|
|
8000.39,
|
|
15966.6,
|
|
31828.1,
|
|
63447.3,
|
|
126506,
|
|
}};
|
|
|
|
template <>
|
|
const std::array<double, 18>
|
|
BandingConfigHelperData<kOneIn20, 128U, /*smash*/ true>::kKnownToAddByPow2{{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
122.637,
|
|
250.651,
|
|
506.625,
|
|
1018.54,
|
|
2036.43,
|
|
4041.6,
|
|
8039.25,
|
|
16005,
|
|
31869.6,
|
|
63492.8,
|
|
126537,
|
|
}};
|
|
|
|
template <>
|
|
const std::array<double, 18>
|
|
BandingConfigHelperData<kOneIn20, 64U, false>::kKnownToAddByPow2{{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
120.659,
|
|
243.346,
|
|
488.168,
|
|
976.373,
|
|
1948.86,
|
|
3875.85,
|
|
7704.97,
|
|
15312.4,
|
|
30395.1,
|
|
60321.8,
|
|
119813,
|
|
}};
|
|
|
|
template <>
|
|
const std::array<double, 18>
|
|
BandingConfigHelperData<kOneIn20, 64U, /*smash*/ true>::kKnownToAddByPow2{{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
58.6016,
|
|
122.619,
|
|
250.641,
|
|
503.595,
|
|
994.165,
|
|
1967.36,
|
|
3898.17,
|
|
7727.21,
|
|
15331.5,
|
|
30405.8,
|
|
60376.2,
|
|
119836,
|
|
}};
|
|
|
|
template <>
|
|
const std::array<double, 18>
|
|
BandingConfigHelperData<kOneIn1000, 128U, false>::kKnownToAddByPow2{{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
242.61,
|
|
491.887,
|
|
983.603,
|
|
1968.21,
|
|
3926.98,
|
|
7833.99,
|
|
15629,
|
|
31199.9,
|
|
62307.8,
|
|
123870,
|
|
}};
|
|
|
|
template <>
|
|
const std::array<double, 18> BandingConfigHelperData<
|
|
kOneIn1000, 128U, /*smash*/ true>::kKnownToAddByPow2{{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
117.19,
|
|
245.105,
|
|
500.748,
|
|
1010.67,
|
|
1993.4,
|
|
3950.01,
|
|
7863.31,
|
|
15652,
|
|
31262.1,
|
|
62462.8,
|
|
124095,
|
|
}};
|
|
|
|
template <>
|
|
const std::array<double, 18>
|
|
BandingConfigHelperData<kOneIn1000, 64U, false>::kKnownToAddByPow2{{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
114,
|
|
234.8,
|
|
471.498,
|
|
940.165,
|
|
1874,
|
|
3721.5,
|
|
7387.5,
|
|
14592,
|
|
29160,
|
|
57745,
|
|
115082,
|
|
}};
|
|
|
|
template <>
|
|
const std::array<double, 18>
|
|
BandingConfigHelperData<kOneIn1000, 64U, /*smash*/ true>::kKnownToAddByPow2{
|
|
{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // unsupported
|
|
53.0434,
|
|
117,
|
|
245.312,
|
|
483.571,
|
|
950.251,
|
|
1878,
|
|
3736.34,
|
|
7387.97,
|
|
14618,
|
|
29142.9,
|
|
57838.8,
|
|
114932,
|
|
}};
|
|
|
|
// We hide these implementation details from the .h file with explicit
|
|
// instantiations below these partial specializations.
|
|
|
|
template <ConstructionFailureChance kCfc, uint64_t kCoeffBits, bool kUseSmash,
|
|
bool kHomogeneous>
|
|
uint32_t BandingConfigHelper1MaybeSupported<
|
|
kCfc, kCoeffBits, kUseSmash, kHomogeneous,
|
|
true /* kIsSupported */>::GetNumToAdd(uint32_t num_slots) {
|
|
using Data = detail::BandingConfigHelperData<kCfc, kCoeffBits, kUseSmash>;
|
|
if (num_slots == 0) {
|
|
return 0;
|
|
}
|
|
uint32_t num_to_add;
|
|
double log2_num_slots = std::log(num_slots) * 1.4426950409;
|
|
uint32_t floor_log2 = static_cast<uint32_t>(log2_num_slots);
|
|
if (floor_log2 + 1 < Data::kKnownSize) {
|
|
double ceil_portion = 1.0 * num_slots / (uint32_t{1} << floor_log2) - 1.0;
|
|
// Must be a supported number of slots
|
|
assert(Data::kKnownToAddByPow2[floor_log2] > 0.0);
|
|
// Weighted average of two nearest known data points
|
|
num_to_add = static_cast<uint32_t>(
|
|
ceil_portion * Data::kKnownToAddByPow2[floor_log2 + 1] +
|
|
(1.0 - ceil_portion) * Data::kKnownToAddByPow2[floor_log2]);
|
|
} else {
|
|
// Use formula for large values
|
|
double factor = Data::GetFactorForLarge(log2_num_slots);
|
|
assert(factor >= 1.0);
|
|
num_to_add = static_cast<uint32_t>(num_slots / factor);
|
|
}
|
|
if (kHomogeneous) {
|
|
// Even when standard filter construction would succeed, we might
|
|
// have loaded things up too much for Homogeneous filter. (Complete
|
|
// explanation not known but observed empirically.) This seems to
|
|
// correct for that, mostly affecting small filter configurations.
|
|
if (num_to_add >= 8) {
|
|
num_to_add -= 8;
|
|
} else {
|
|
assert(false);
|
|
}
|
|
}
|
|
return num_to_add;
|
|
}
|
|
|
|
template <ConstructionFailureChance kCfc, uint64_t kCoeffBits, bool kUseSmash,
|
|
bool kHomogeneous>
|
|
uint32_t BandingConfigHelper1MaybeSupported<
|
|
kCfc, kCoeffBits, kUseSmash, kHomogeneous,
|
|
true /* kIsSupported */>::GetNumSlots(uint32_t num_to_add) {
|
|
using Data = detail::BandingConfigHelperData<kCfc, kCoeffBits, kUseSmash>;
|
|
|
|
if (num_to_add == 0) {
|
|
return 0;
|
|
}
|
|
if (kHomogeneous) {
|
|
// Reverse of above in GetNumToAdd
|
|
num_to_add += 8;
|
|
}
|
|
double log2_num_to_add = std::log(num_to_add) * 1.4426950409;
|
|
uint32_t approx_log2_slots = static_cast<uint32_t>(log2_num_to_add + 0.5);
|
|
assert(approx_log2_slots <= 32); // help clang-analyze
|
|
|
|
double lower_num_to_add = Data::GetNumToAddForPow2(approx_log2_slots);
|
|
double upper_num_to_add;
|
|
if (approx_log2_slots == 0 || lower_num_to_add == /* unsupported */ 0) {
|
|
// Return minimum non-zero slots in standard implementation
|
|
return kUseSmash ? kCoeffBits : 2 * kCoeffBits;
|
|
} else if (num_to_add < lower_num_to_add) {
|
|
upper_num_to_add = lower_num_to_add;
|
|
--approx_log2_slots;
|
|
lower_num_to_add = Data::GetNumToAddForPow2(approx_log2_slots);
|
|
} else {
|
|
upper_num_to_add = Data::GetNumToAddForPow2(approx_log2_slots + 1);
|
|
}
|
|
|
|
assert(num_to_add >= lower_num_to_add);
|
|
assert(num_to_add < upper_num_to_add);
|
|
|
|
double upper_portion =
|
|
(num_to_add - lower_num_to_add) / (upper_num_to_add - lower_num_to_add);
|
|
|
|
double lower_num_slots = 1.0 * (uint64_t{1} << approx_log2_slots);
|
|
|
|
// Interpolation, round up
|
|
return static_cast<uint32_t>(upper_portion * lower_num_slots +
|
|
lower_num_slots + 0.999999999);
|
|
}
|
|
|
|
// These explicit instantiations enable us to hide most of the
|
|
// implementation details from the .h file. (The .h file currently
|
|
// needs to determine whether settings are "supported" or not.)
|
|
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn2, 128U, /*sm*/ false,
|
|
/*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn2, 128U, /*sm*/ true,
|
|
/*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn2, 128U, /*sm*/ false,
|
|
/*hm*/ true, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn2, 128U, /*sm*/ true,
|
|
/*hm*/ true, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn2, 64U, /*sm*/ false,
|
|
/*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn2, 64U, /*sm*/ true,
|
|
/*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn2, 64U, /*sm*/ false,
|
|
/*hm*/ true, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn2, 64U, /*sm*/ true,
|
|
/*hm*/ true, /*sup*/ true>;
|
|
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn20, 128U, /*sm*/ false,
|
|
/*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn20, 128U, /*sm*/ true,
|
|
/*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn20, 128U, /*sm*/ false,
|
|
/*hm*/ true, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn20, 128U, /*sm*/ true,
|
|
/*hm*/ true, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn20, 64U, /*sm*/ false,
|
|
/*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn20, 64U, /*sm*/ true,
|
|
/*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn20, 64U, /*sm*/ false,
|
|
/*hm*/ true, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn20, 64U, /*sm*/ true,
|
|
/*hm*/ true, /*sup*/ true>;
|
|
|
|
template struct BandingConfigHelper1MaybeSupported<
|
|
kOneIn1000, 128U, /*sm*/ false, /*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<
|
|
kOneIn1000, 128U, /*sm*/ true, /*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<
|
|
kOneIn1000, 128U, /*sm*/ false, /*hm*/ true, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<
|
|
kOneIn1000, 128U, /*sm*/ true, /*hm*/ true, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<
|
|
kOneIn1000, 64U, /*sm*/ false, /*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn1000, 64U, /*sm*/ true,
|
|
/*hm*/ false, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<
|
|
kOneIn1000, 64U, /*sm*/ false, /*hm*/ true, /*sup*/ true>;
|
|
template struct BandingConfigHelper1MaybeSupported<kOneIn1000, 64U, /*sm*/ true,
|
|
/*hm*/ true, /*sup*/ true>;
|
|
|
|
} // namespace ROCKSDB_NAMESPACE::ribbon::detail
|