Skip to content

Extend cachbench with touch value #85

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 12 additions & 24 deletions cachelib/cachebench/cache/Cache-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ uint64_t Cache<Allocator>::fetchNandWrites() const {
template <typename Allocator>
Cache<Allocator>::Cache(const CacheConfig& config,
ChainedItemMovingSync movingSync,
std::string cacheDir)
std::string cacheDir,
bool touchValue)
: config_(config),
touchValue_(touchValue),
nandBytesBegin_{fetchNandWrites()},
itemRecords_(config_.enableItemDestructorCheck) {
constexpr size_t MB = 1024ULL * 1024ULL;
Expand Down Expand Up @@ -325,22 +327,13 @@ template <typename Allocator>
void Cache<Allocator>::enableConsistencyCheck(
const std::vector<std::string>& keys) {
XDCHECK(valueTracker_ == nullptr);
XDCHECK(!valueValidatingEnabled());
valueTracker_ =
std::make_unique<ValueTracker>(ValueTracker::wrapStrings(keys));
for (const std::string& key : keys) {
invalidKeys_[key] = false;
}
}

template <typename Allocator>
void Cache<Allocator>::enableValueValidating(
const std::string &expectedValue) {
XDCHECK(!valueValidatingEnabled());
XDCHECK(!consistencyCheckEnabled());
this->expectedValue_ = expectedValue;
}

template <typename Allocator>
typename Cache<Allocator>::RemoveRes Cache<Allocator>::remove(Key key) {
if (!consistencyCheckEnabled()) {
Expand Down Expand Up @@ -434,17 +427,15 @@ typename Cache<Allocator>::ItemHandle Cache<Allocator>::insertOrReplace(
}

template <typename Allocator>
void Cache<Allocator>::validateValue(const ItemHandle &it) const {
XDCHECK(valueValidatingEnabled());

const auto &expected = expectedValue_.value();
void Cache<Allocator>::touchValue(const ItemHandle& it) const {
XDCHECK(touchValueEnabled());

auto ptr = reinterpret_cast<const uint8_t*>(getMemory(it));
auto cmp = std::memcmp(ptr, expected.data(), std::min<size_t>(expected.size(),
getSize(it)));
if (cmp != 0) {
throw std::runtime_error("Value does not match!");
}

/* The accumulate call is intended to access all bytes of the value
* and nothing more. */
auto sum = std::accumulate(ptr, ptr + getSize(it), 0ULL);
folly::doNotOptimizeAway(sum);
}

template <typename Allocator>
Expand All @@ -459,9 +450,8 @@ typename Cache<Allocator>::ItemHandle Cache<Allocator>::find(Key key,
auto it = cache_->find(key, mode);
it.wait();

if (valueValidatingEnabled()) {
XDCHECK(!consistencyCheckEnabled());
validateValue(it);
if (touchValueEnabled()) {
touchValue(it);
}

return it;
Expand All @@ -472,8 +462,6 @@ typename Cache<Allocator>::ItemHandle Cache<Allocator>::find(Key key,
return it;
}

XDCHECK(!valueValidatingEnabled());

auto opId = valueTracker_->beginGet(key);
auto it = findFn();
if (checkGet(opId, it)) {
Expand Down
19 changes: 9 additions & 10 deletions cachelib/cachebench/cache/Cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ class Cache {
// cache.
// @param cacheDir optional directory for the cache to enable
// persistence across restarts.
// @param touchValue read entire value on find
explicit Cache(const CacheConfig& config,
ChainedItemMovingSync movingSync = {},
std::string cacheDir = "");
std::string cacheDir = "",
bool touchValue = true);

~Cache();

Expand Down Expand Up @@ -168,8 +170,8 @@ class Cache {
return getSize(item.get());
}

// checks if values stored in it matches expectedValue_.
void validateValue(const ItemHandle &it) const;
// read entire value on find.
void touchValue(const ItemHandle& it) const;

// returns the size of the item, taking into account ItemRecords could be
// enabled.
Expand Down Expand Up @@ -228,14 +230,11 @@ class Cache {
// @param keys list of keys that the stressor uses for the workload.
void enableConsistencyCheck(const std::vector<std::string>& keys);

// enables validating all values on find. Each value is compared to
// expected Value.
void enableValueValidating(const std::string &expectedValue);

// returns true if the consistency checking is enabled.
bool consistencyCheckEnabled() const { return valueTracker_ != nullptr; }

bool valueValidatingEnabled() const { return expectedValue_.has_value(); }
// returns true if touching value is enabled.
bool touchValueEnabled() const { return touchValue_; }

// return true if the key was previously detected to be inconsistent. This
// is useful only when consistency checking is enabled by calling
Expand Down Expand Up @@ -359,8 +358,8 @@ class Cache {
// tracker for consistency monitoring.
std::unique_ptr<ValueTracker> valueTracker_;

// exceptected value of all items in Cache.
std::optional<std::string> expectedValue_;
// read entire value on find.
bool touchValue_{true};

// reading of the nand bytes written for the benchmark if enabled.
const uint64_t nandBytesBegin_{0};
Expand Down
6 changes: 2 additions & 4 deletions cachelib/cachebench/runner/CacheStressor.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ class CacheStressor : public Stressor {
cacheConfig.ticker = ticker_;
}

cache_ = std::make_unique<CacheT>(cacheConfig, movingSync);
cache_ = std::make_unique<CacheT>(cacheConfig, movingSync, "",
config_.touchValue);
if (config_.opPoolDistribution.size() > cache_->numPools()) {
throw std::invalid_argument(folly::sformat(
"more pools specified in the test than in the cache. "
Expand All @@ -110,9 +111,6 @@ class CacheStressor : public Stressor {
if (config_.checkConsistency) {
cache_->enableConsistencyCheck(wg_->getAllKeys());
}
if (config_.validateValue) {
cache_->enableValueValidating(hardcodedString_);
}
if (config_.opRatePerSec > 0) {
rateLimiter_ = std::make_unique<folly::BasicTokenBucket<>>(
config_.opRatePerSec, config_.opRatePerSec);
Expand Down
2 changes: 1 addition & 1 deletion cachelib/cachebench/util/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ StressorConfig::StressorConfig(const folly::dynamic& configJson) {
JSONSetVal(configJson, samplingIntervalMs);

JSONSetVal(configJson, checkConsistency);
JSONSetVal(configJson, validateValue);
JSONSetVal(configJson, touchValue);

JSONSetVal(configJson, numOps);
JSONSetVal(configJson, numThreads);
Expand Down
4 changes: 4 additions & 0 deletions cachelib/cachebench/util/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ struct StressorConfig : public JSONConfig {
// Mutually exclusive with checkConsistency
bool validateValue{false};

// If enabled, each value will be read on find. This is useful for measuring
// performance of value access.
bool touchValue{true};

uint64_t numOps{0}; // operation per thread
uint64_t numThreads{0}; // number of threads that will run
uint64_t numKeys{0}; // number of keys that will be used
Expand Down