ribbon_config.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. #include "util/ribbon_config.h"
  6. namespace ROCKSDB_NAMESPACE::ribbon::detail {
  7. // Each instantiation of this struct is sufficiently unique for configuration
  8. // purposes, and is only instantiated for settings where we support the
  9. // configuration API. An application might only reference one instantiation,
  10. // meaning the rest could be pruned at link time.
  11. template <ConstructionFailureChance kCfc, uint64_t kCoeffBits, bool kUseSmash>
  12. struct BandingConfigHelperData {
  13. static constexpr size_t kKnownSize = 18U;
  14. // Because of complexity in the data, for smaller numbers of slots
  15. // (powers of two up to 2^17), we record known numbers that can be added
  16. // with kCfc chance of construction failure and settings in template
  17. // parameters. Zero means "unsupported (too small) number of slots".
  18. // (GetNumToAdd below will use interpolation for numbers of slots
  19. // between powers of two; double rather than integer values here make
  20. // that more accurate.)
  21. static const std::array<double, kKnownSize> kKnownToAddByPow2;
  22. // For sufficiently large number of slots, doubling the number of
  23. // slots will increase the expected overhead (slots over number added)
  24. // by approximately this constant.
  25. // (This is roughly constant regardless of ConstructionFailureChance and
  26. // smash setting.)
  27. // (Would be a constant if we had partial template specialization for
  28. // static const members.)
  29. static inline double GetFactorPerPow2() {
  30. if (kCoeffBits == 128U) {
  31. return 0.0038;
  32. } else {
  33. assert(kCoeffBits == 64U);
  34. return 0.0083;
  35. }
  36. }
  37. // Overhead factor for 2^(kKnownSize-1) slots
  38. // (Would be a constant if we had partial template specialization for
  39. // static const members.)
  40. static inline double GetFinalKnownFactor() {
  41. return 1.0 * (uint32_t{1} << (kKnownSize - 1)) /
  42. kKnownToAddByPow2[kKnownSize - 1];
  43. }
  44. // GetFinalKnownFactor() - (kKnownSize-1) * GetFactorPerPow2()
  45. // (Would be a constant if we had partial template specialization for
  46. // static const members.)
  47. static inline double GetBaseFactor() {
  48. return GetFinalKnownFactor() - (kKnownSize - 1) * GetFactorPerPow2();
  49. }
  50. // Get overhead factor (slots over number to add) for sufficiently large
  51. // number of slots (by log base 2)
  52. static inline double GetFactorForLarge(double log2_num_slots) {
  53. return GetBaseFactor() + log2_num_slots * GetFactorPerPow2();
  54. }
  55. // For a given power of two number of slots (specified by whole number
  56. // log base 2), implements GetNumToAdd for such limited case, returning
  57. // double for better interpolation in GetNumToAdd and GetNumSlots.
  58. static inline double GetNumToAddForPow2(uint32_t log2_num_slots) {
  59. assert(log2_num_slots <= 32); // help clang-analyze
  60. if (log2_num_slots < kKnownSize) {
  61. return kKnownToAddByPow2[log2_num_slots];
  62. } else {
  63. return 1.0 * (uint64_t{1} << log2_num_slots) /
  64. GetFactorForLarge(1.0 * log2_num_slots);
  65. }
  66. }
  67. };
  68. // Based on data from FindOccupancy in ribbon_test
  69. template <>
  70. const std::array<double, 18>
  71. BandingConfigHelperData<kOneIn2, 128U, false>::kKnownToAddByPow2{{
  72. 0,
  73. 0,
  74. 0,
  75. 0,
  76. 0,
  77. 0,
  78. 0,
  79. 0, // unsupported
  80. 252.984,
  81. 506.109,
  82. 1013.71,
  83. 2029.47,
  84. 4060.43,
  85. 8115.63,
  86. 16202.2,
  87. 32305.1,
  88. 64383.5,
  89. 128274,
  90. }};
  91. template <>
  92. const std::array<double, 18>
  93. BandingConfigHelperData<kOneIn2, 128U, /*smash*/ true>::kKnownToAddByPow2{{
  94. 0,
  95. 0,
  96. 0,
  97. 0,
  98. 0,
  99. 0,
  100. 0, // unsupported
  101. 126.274,
  102. 254.279,
  103. 510.27,
  104. 1022.24,
  105. 2046.02,
  106. 4091.99,
  107. 8154.98,
  108. 16244.3,
  109. 32349.7,
  110. 64426.6,
  111. 128307,
  112. }};
  113. template <>
  114. const std::array<double, 18>
  115. BandingConfigHelperData<kOneIn2, 64U, false>::kKnownToAddByPow2{{
  116. 0,
  117. 0,
  118. 0,
  119. 0,
  120. 0,
  121. 0,
  122. 0, // unsupported
  123. 124.94,
  124. 249.968,
  125. 501.234,
  126. 1004.06,
  127. 2006.15,
  128. 3997.89,
  129. 7946.99,
  130. 15778.4,
  131. 31306.9,
  132. 62115.3,
  133. 123284,
  134. }};
  135. template <>
  136. const std::array<double, 18>
  137. BandingConfigHelperData<kOneIn2, 64U, /*smash*/ true>::kKnownToAddByPow2{{
  138. 0,
  139. 0,
  140. 0,
  141. 0,
  142. 0,
  143. 0, // unsupported
  144. 62.2683,
  145. 126.259,
  146. 254.268,
  147. 509.975,
  148. 1019.98,
  149. 2026.16,
  150. 4019.75,
  151. 7969.8,
  152. 15798.2,
  153. 31330.3,
  154. 62134.2,
  155. 123255,
  156. }};
  157. template <>
  158. const std::array<double, 18>
  159. BandingConfigHelperData<kOneIn20, 128U, false>::kKnownToAddByPow2{{
  160. 0,
  161. 0,
  162. 0,
  163. 0,
  164. 0,
  165. 0,
  166. 0,
  167. 0, // unsupported
  168. 248.851,
  169. 499.532,
  170. 1001.26,
  171. 2003.97,
  172. 4005.59,
  173. 8000.39,
  174. 15966.6,
  175. 31828.1,
  176. 63447.3,
  177. 126506,
  178. }};
  179. template <>
  180. const std::array<double, 18>
  181. BandingConfigHelperData<kOneIn20, 128U, /*smash*/ true>::kKnownToAddByPow2{{
  182. 0,
  183. 0,
  184. 0,
  185. 0,
  186. 0,
  187. 0,
  188. 0, // unsupported
  189. 122.637,
  190. 250.651,
  191. 506.625,
  192. 1018.54,
  193. 2036.43,
  194. 4041.6,
  195. 8039.25,
  196. 16005,
  197. 31869.6,
  198. 63492.8,
  199. 126537,
  200. }};
  201. template <>
  202. const std::array<double, 18>
  203. BandingConfigHelperData<kOneIn20, 64U, false>::kKnownToAddByPow2{{
  204. 0,
  205. 0,
  206. 0,
  207. 0,
  208. 0,
  209. 0,
  210. 0, // unsupported
  211. 120.659,
  212. 243.346,
  213. 488.168,
  214. 976.373,
  215. 1948.86,
  216. 3875.85,
  217. 7704.97,
  218. 15312.4,
  219. 30395.1,
  220. 60321.8,
  221. 119813,
  222. }};
  223. template <>
  224. const std::array<double, 18>
  225. BandingConfigHelperData<kOneIn20, 64U, /*smash*/ true>::kKnownToAddByPow2{{
  226. 0,
  227. 0,
  228. 0,
  229. 0,
  230. 0,
  231. 0, // unsupported
  232. 58.6016,
  233. 122.619,
  234. 250.641,
  235. 503.595,
  236. 994.165,
  237. 1967.36,
  238. 3898.17,
  239. 7727.21,
  240. 15331.5,
  241. 30405.8,
  242. 60376.2,
  243. 119836,
  244. }};
  245. template <>
  246. const std::array<double, 18>
  247. BandingConfigHelperData<kOneIn1000, 128U, false>::kKnownToAddByPow2{{
  248. 0,
  249. 0,
  250. 0,
  251. 0,
  252. 0,
  253. 0,
  254. 0,
  255. 0, // unsupported
  256. 242.61,
  257. 491.887,
  258. 983.603,
  259. 1968.21,
  260. 3926.98,
  261. 7833.99,
  262. 15629,
  263. 31199.9,
  264. 62307.8,
  265. 123870,
  266. }};
  267. template <>
  268. const std::array<double, 18> BandingConfigHelperData<
  269. kOneIn1000, 128U, /*smash*/ true>::kKnownToAddByPow2{{
  270. 0,
  271. 0,
  272. 0,
  273. 0,
  274. 0,
  275. 0,
  276. 0, // unsupported
  277. 117.19,
  278. 245.105,
  279. 500.748,
  280. 1010.67,
  281. 1993.4,
  282. 3950.01,
  283. 7863.31,
  284. 15652,
  285. 31262.1,
  286. 62462.8,
  287. 124095,
  288. }};
  289. template <>
  290. const std::array<double, 18>
  291. BandingConfigHelperData<kOneIn1000, 64U, false>::kKnownToAddByPow2{{
  292. 0,
  293. 0,
  294. 0,
  295. 0,
  296. 0,
  297. 0,
  298. 0, // unsupported
  299. 114,
  300. 234.8,
  301. 471.498,
  302. 940.165,
  303. 1874,
  304. 3721.5,
  305. 7387.5,
  306. 14592,
  307. 29160,
  308. 57745,
  309. 115082,
  310. }};
  311. template <>
  312. const std::array<double, 18>
  313. BandingConfigHelperData<kOneIn1000, 64U, /*smash*/ true>::kKnownToAddByPow2{
  314. {
  315. 0,
  316. 0,
  317. 0,
  318. 0,
  319. 0,
  320. 0, // unsupported
  321. 53.0434,
  322. 117,
  323. 245.312,
  324. 483.571,
  325. 950.251,
  326. 1878,
  327. 3736.34,
  328. 7387.97,
  329. 14618,
  330. 29142.9,
  331. 57838.8,
  332. 114932,
  333. }};
  334. // We hide these implementation details from the .h file with explicit
  335. // instantiations below these partial specializations.
  336. template <ConstructionFailureChance kCfc, uint64_t kCoeffBits, bool kUseSmash,
  337. bool kHomogeneous>
  338. uint32_t BandingConfigHelper1MaybeSupported<
  339. kCfc, kCoeffBits, kUseSmash, kHomogeneous,
  340. true /* kIsSupported */>::GetNumToAdd(uint32_t num_slots) {
  341. using Data = detail::BandingConfigHelperData<kCfc, kCoeffBits, kUseSmash>;
  342. if (num_slots == 0) {
  343. return 0;
  344. }
  345. uint32_t num_to_add;
  346. double log2_num_slots = std::log(num_slots) * 1.4426950409;
  347. uint32_t floor_log2 = static_cast<uint32_t>(log2_num_slots);
  348. if (floor_log2 + 1 < Data::kKnownSize) {
  349. double ceil_portion = 1.0 * num_slots / (uint32_t{1} << floor_log2) - 1.0;
  350. // Must be a supported number of slots
  351. assert(Data::kKnownToAddByPow2[floor_log2] > 0.0);
  352. // Weighted average of two nearest known data points
  353. num_to_add = static_cast<uint32_t>(
  354. ceil_portion * Data::kKnownToAddByPow2[floor_log2 + 1] +
  355. (1.0 - ceil_portion) * Data::kKnownToAddByPow2[floor_log2]);
  356. } else {
  357. // Use formula for large values
  358. double factor = Data::GetFactorForLarge(log2_num_slots);
  359. assert(factor >= 1.0);
  360. num_to_add = static_cast<uint32_t>(num_slots / factor);
  361. }
  362. if (kHomogeneous) {
  363. // Even when standard filter construction would succeed, we might
  364. // have loaded things up too much for Homogeneous filter. (Complete
  365. // explanation not known but observed empirically.) This seems to
  366. // correct for that, mostly affecting small filter configurations.
  367. if (num_to_add >= 8) {
  368. num_to_add -= 8;
  369. } else {
  370. assert(false);
  371. }
  372. }
  373. return num_to_add;
  374. }
  375. template <ConstructionFailureChance kCfc, uint64_t kCoeffBits, bool kUseSmash,
  376. bool kHomogeneous>
  377. uint32_t BandingConfigHelper1MaybeSupported<
  378. kCfc, kCoeffBits, kUseSmash, kHomogeneous,
  379. true /* kIsSupported */>::GetNumSlots(uint32_t num_to_add) {
  380. using Data = detail::BandingConfigHelperData<kCfc, kCoeffBits, kUseSmash>;
  381. if (num_to_add == 0) {
  382. return 0;
  383. }
  384. if (kHomogeneous) {
  385. // Reverse of above in GetNumToAdd
  386. num_to_add += 8;
  387. }
  388. double log2_num_to_add = std::log(num_to_add) * 1.4426950409;
  389. uint32_t approx_log2_slots = static_cast<uint32_t>(log2_num_to_add + 0.5);
  390. assert(approx_log2_slots <= 32); // help clang-analyze
  391. double lower_num_to_add = Data::GetNumToAddForPow2(approx_log2_slots);
  392. double upper_num_to_add;
  393. if (approx_log2_slots == 0 || lower_num_to_add == /* unsupported */ 0) {
  394. // Return minimum non-zero slots in standard implementation
  395. return kUseSmash ? kCoeffBits : 2 * kCoeffBits;
  396. } else if (num_to_add < lower_num_to_add) {
  397. upper_num_to_add = lower_num_to_add;
  398. --approx_log2_slots;
  399. lower_num_to_add = Data::GetNumToAddForPow2(approx_log2_slots);
  400. } else {
  401. upper_num_to_add = Data::GetNumToAddForPow2(approx_log2_slots + 1);
  402. }
  403. assert(num_to_add >= lower_num_to_add);
  404. assert(num_to_add < upper_num_to_add);
  405. double upper_portion =
  406. (num_to_add - lower_num_to_add) / (upper_num_to_add - lower_num_to_add);
  407. double lower_num_slots = 1.0 * (uint64_t{1} << approx_log2_slots);
  408. // Interpolation, round up
  409. return static_cast<uint32_t>(upper_portion * lower_num_slots +
  410. lower_num_slots + 0.999999999);
  411. }
  412. // These explicit instantiations enable us to hide most of the
  413. // implementation details from the .h file. (The .h file currently
  414. // needs to determine whether settings are "supported" or not.)
  415. template struct BandingConfigHelper1MaybeSupported<kOneIn2, 128U, /*sm*/ false,
  416. /*hm*/ false, /*sup*/ true>;
  417. template struct BandingConfigHelper1MaybeSupported<kOneIn2, 128U, /*sm*/ true,
  418. /*hm*/ false, /*sup*/ true>;
  419. template struct BandingConfigHelper1MaybeSupported<kOneIn2, 128U, /*sm*/ false,
  420. /*hm*/ true, /*sup*/ true>;
  421. template struct BandingConfigHelper1MaybeSupported<kOneIn2, 128U, /*sm*/ true,
  422. /*hm*/ true, /*sup*/ true>;
  423. template struct BandingConfigHelper1MaybeSupported<kOneIn2, 64U, /*sm*/ false,
  424. /*hm*/ false, /*sup*/ true>;
  425. template struct BandingConfigHelper1MaybeSupported<kOneIn2, 64U, /*sm*/ true,
  426. /*hm*/ false, /*sup*/ true>;
  427. template struct BandingConfigHelper1MaybeSupported<kOneIn2, 64U, /*sm*/ false,
  428. /*hm*/ true, /*sup*/ true>;
  429. template struct BandingConfigHelper1MaybeSupported<kOneIn2, 64U, /*sm*/ true,
  430. /*hm*/ true, /*sup*/ true>;
  431. template struct BandingConfigHelper1MaybeSupported<kOneIn20, 128U, /*sm*/ false,
  432. /*hm*/ false, /*sup*/ true>;
  433. template struct BandingConfigHelper1MaybeSupported<kOneIn20, 128U, /*sm*/ true,
  434. /*hm*/ false, /*sup*/ true>;
  435. template struct BandingConfigHelper1MaybeSupported<kOneIn20, 128U, /*sm*/ false,
  436. /*hm*/ true, /*sup*/ true>;
  437. template struct BandingConfigHelper1MaybeSupported<kOneIn20, 128U, /*sm*/ true,
  438. /*hm*/ true, /*sup*/ true>;
  439. template struct BandingConfigHelper1MaybeSupported<kOneIn20, 64U, /*sm*/ false,
  440. /*hm*/ false, /*sup*/ true>;
  441. template struct BandingConfigHelper1MaybeSupported<kOneIn20, 64U, /*sm*/ true,
  442. /*hm*/ false, /*sup*/ true>;
  443. template struct BandingConfigHelper1MaybeSupported<kOneIn20, 64U, /*sm*/ false,
  444. /*hm*/ true, /*sup*/ true>;
  445. template struct BandingConfigHelper1MaybeSupported<kOneIn20, 64U, /*sm*/ true,
  446. /*hm*/ true, /*sup*/ true>;
  447. template struct BandingConfigHelper1MaybeSupported<
  448. kOneIn1000, 128U, /*sm*/ false, /*hm*/ false, /*sup*/ true>;
  449. template struct BandingConfigHelper1MaybeSupported<
  450. kOneIn1000, 128U, /*sm*/ true, /*hm*/ false, /*sup*/ true>;
  451. template struct BandingConfigHelper1MaybeSupported<
  452. kOneIn1000, 128U, /*sm*/ false, /*hm*/ true, /*sup*/ true>;
  453. template struct BandingConfigHelper1MaybeSupported<
  454. kOneIn1000, 128U, /*sm*/ true, /*hm*/ true, /*sup*/ true>;
  455. template struct BandingConfigHelper1MaybeSupported<
  456. kOneIn1000, 64U, /*sm*/ false, /*hm*/ false, /*sup*/ true>;
  457. template struct BandingConfigHelper1MaybeSupported<kOneIn1000, 64U, /*sm*/ true,
  458. /*hm*/ false, /*sup*/ true>;
  459. template struct BandingConfigHelper1MaybeSupported<
  460. kOneIn1000, 64U, /*sm*/ false, /*hm*/ true, /*sup*/ true>;
  461. template struct BandingConfigHelper1MaybeSupported<kOneIn1000, 64U, /*sm*/ true,
  462. /*hm*/ true, /*sup*/ true>;
  463. } // namespace ROCKSDB_NAMESPACE::ribbon::detail