core_local.h 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. // Copyright (c) 2017-present, Facebook, Inc. 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. #pragma once
  6. #include <cstddef>
  7. #include <thread>
  8. #include <utility>
  9. #include <vector>
  10. #include "port/likely.h"
  11. #include "port/port.h"
  12. #include "util/random.h"
  13. namespace ROCKSDB_NAMESPACE {
  14. // An array of core-local values. Ideally the value type, T, is cache aligned to
  15. // prevent false sharing.
  16. template <typename T>
  17. class CoreLocalArray {
  18. public:
  19. CoreLocalArray();
  20. size_t Size() const;
  21. // returns pointer to the element corresponding to the core that the thread
  22. // currently runs on.
  23. T* Access() const;
  24. // same as above, but also returns the core index, which the client can cache
  25. // to reduce how often core ID needs to be retrieved. Only do this if some
  26. // inaccuracy is tolerable, as the thread may migrate to a different core.
  27. std::pair<T*, size_t> AccessElementAndIndex() const;
  28. // returns pointer to element for the specified core index. This can be used,
  29. // e.g., for aggregation, or if the client caches core index.
  30. T* AccessAtCore(size_t core_idx) const;
  31. private:
  32. std::unique_ptr<T[]> data_;
  33. int size_shift_;
  34. };
  35. template <typename T>
  36. CoreLocalArray<T>::CoreLocalArray() {
  37. int num_cpus = static_cast<int>(std::thread::hardware_concurrency());
  38. // find a power of two >= num_cpus and >= 8
  39. size_shift_ = 3;
  40. while (1 << size_shift_ < num_cpus) {
  41. ++size_shift_;
  42. }
  43. data_.reset(new T[static_cast<size_t>(1) << size_shift_]);
  44. }
  45. template <typename T>
  46. size_t CoreLocalArray<T>::Size() const {
  47. return static_cast<size_t>(1) << size_shift_;
  48. }
  49. template <typename T>
  50. T* CoreLocalArray<T>::Access() const {
  51. return AccessElementAndIndex().first;
  52. }
  53. template <typename T>
  54. std::pair<T*, size_t> CoreLocalArray<T>::AccessElementAndIndex() const {
  55. int cpuid = port::PhysicalCoreID();
  56. size_t core_idx;
  57. if (UNLIKELY(cpuid < 0)) {
  58. // cpu id unavailable, just pick randomly
  59. core_idx = Random::GetTLSInstance()->Uniform(1 << size_shift_);
  60. } else {
  61. core_idx = static_cast<size_t>(cpuid & ((1 << size_shift_) - 1));
  62. }
  63. return {AccessAtCore(core_idx), core_idx};
  64. }
  65. template <typename T>
  66. T* CoreLocalArray<T>::AccessAtCore(size_t core_idx) const {
  67. assert(core_idx < static_cast<size_t>(1) << size_shift_);
  68. return &data_[core_idx];
  69. }
  70. } // namespace ROCKSDB_NAMESPACE