// Copyright (c) 2017-present, Facebook, Inc. 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). #pragma once #include #include #include #include #include "port/likely.h" #include "port/port.h" #include "util/random.h" namespace rocksdb { // An array of core-local values. Ideally the value type, T, is cache aligned to // prevent false sharing. template class CoreLocalArray { public: CoreLocalArray(); size_t Size() const; // returns pointer to the element corresponding to the core that the thread // currently runs on. T* Access() const; // same as above, but also returns the core index, which the client can cache // to reduce how often core ID needs to be retrieved. Only do this if some // inaccuracy is tolerable, as the thread may migrate to a different core. std::pair AccessElementAndIndex() const; // returns pointer to element for the specified core index. This can be used, // e.g., for aggregation, or if the client caches core index. T* AccessAtCore(size_t core_idx) const; private: std::unique_ptr data_; int size_shift_; }; template CoreLocalArray::CoreLocalArray() { int num_cpus = static_cast(std::thread::hardware_concurrency()); // find a power of two >= num_cpus and >= 8 size_shift_ = 3; while (1 << size_shift_ < num_cpus) { ++size_shift_; } data_.reset(new T[static_cast(1) << size_shift_]); } template size_t CoreLocalArray::Size() const { return static_cast(1) << size_shift_; } template T* CoreLocalArray::Access() const { return AccessElementAndIndex().first; } template std::pair CoreLocalArray::AccessElementAndIndex() const { int cpuid = port::PhysicalCoreID(); size_t core_idx; if (UNLIKELY(cpuid < 0)) { // cpu id unavailable, just pick randomly core_idx = Random::GetTLSInstance()->Uniform(1 << size_shift_); } else { core_idx = static_cast(cpuid & ((1 << size_shift_) - 1)); } return {AccessAtCore(core_idx), core_idx}; } template T* CoreLocalArray::AccessAtCore(size_t core_idx) const { assert(core_idx < static_cast(1) << size_shift_); return &data_[core_idx]; } } // namespace rocksdb