Summary: Moved the logic for core-local array out of ConcurrentArena and into a separate class because I want to reuse it for core-local stats. Closes https://github.com/facebook/rocksdb/pull/2256 Differential Revision: D5011518 Pulled By: ajkr fbshipit-source-id: a75a7b8f7b7a42fd6273489ada405f14c6be196amain
parent
93949667cc
commit
cda5fde2d9
@ -0,0 +1,84 @@ |
|||||||
|
// Copyright (c) 2017-present, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under the BSD-style license found in the
|
||||||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
// This source code is also licensed under the GPLv2 license found in the
|
||||||
|
// COPYING file in the root directory of this source tree.
|
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include "port/likely.h" |
||||||
|
#include "port/port.h" |
||||||
|
#include "util/random.h" |
||||||
|
|
||||||
|
#include <cstddef> |
||||||
|
#include <thread> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
namespace rocksdb { |
||||||
|
|
||||||
|
// An array of core-local values. Ideally the value type, T, is cache aligned to
|
||||||
|
// prevent false sharing.
|
||||||
|
template<typename T> |
||||||
|
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<T*, size_t> 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<T[]> data_; |
||||||
|
size_t size_shift_; |
||||||
|
}; |
||||||
|
|
||||||
|
template<typename T> |
||||||
|
CoreLocalArray<T>::CoreLocalArray() { |
||||||
|
unsigned int num_cpus = std::thread::hardware_concurrency(); |
||||||
|
// find a power of two >= num_cpus and >= 8
|
||||||
|
size_shift_ = 3; |
||||||
|
while (1u << size_shift_ < num_cpus) { |
||||||
|
++size_shift_; |
||||||
|
} |
||||||
|
data_.reset(new T[1 << size_shift_]); |
||||||
|
} |
||||||
|
|
||||||
|
template<typename T> |
||||||
|
size_t CoreLocalArray<T>::Size() const { |
||||||
|
return 1u << size_shift_; |
||||||
|
} |
||||||
|
|
||||||
|
template<typename T> |
||||||
|
T* CoreLocalArray<T>::Access() const { |
||||||
|
return AccessElementAndIndex().first; |
||||||
|
} |
||||||
|
|
||||||
|
template<typename T> |
||||||
|
std::pair<T*, size_t> CoreLocalArray<T>::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<size_t>(cpuid & ((1 << size_shift_) - 1)); |
||||||
|
} |
||||||
|
return {AccessAtCore(core_idx), core_idx}; |
||||||
|
} |
||||||
|
|
||||||
|
template<typename T> |
||||||
|
T* CoreLocalArray<T>::AccessAtCore(size_t core_idx) const { |
||||||
|
assert(core_idx < 1u << size_shift_); |
||||||
|
return &data_[core_idx]; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace rocksdb
|
Loading…
Reference in new issue