cachelib/cachebench/util/Config.cpp (162 lines of code) (raw):

/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "cachelib/cachebench/util/Config.h" #include <folly/FileUtil.h> #include <folly/json.h> #include <unordered_map> namespace facebook { namespace cachelib { namespace cachebench { StressorConfig::StressorConfig(const folly::dynamic& configJson) { JSONSetVal(configJson, generator); JSONSetVal(configJson, name); JSONSetVal(configJson, enableLookaside); JSONSetVal(configJson, populateItem); JSONSetVal(configJson, samplingIntervalMs); JSONSetVal(configJson, checkConsistency); JSONSetVal(configJson, numOps); JSONSetVal(configJson, numThreads); JSONSetVal(configJson, numKeys); JSONSetVal(configJson, opDelayBatch); JSONSetVal(configJson, opDelayNs); JSONSetVal(configJson, opRatePerSec); JSONSetVal(configJson, opPoolDistribution); JSONSetVal(configJson, keyPoolDistribution); JSONSetVal(configJson, maxInconsistencyCount); JSONSetVal(configJson, traceFileName); JSONSetVal(configJson, configPath); JSONSetVal(configJson, cachePieceSize); JSONSetVal(configJson, maxCachePieces); JSONSetVal(configJson, maxInvalidDestructorCount); JSONSetVal(configJson, repeatTraceReplay); JSONSetVal(configJson, timestampFactor); if (configJson.count("poolDistributions")) { for (auto& it : configJson["poolDistributions"]) { poolDistributions.push_back(DistributionConfig(it, configPath)); } } else { poolDistributions.push_back(DistributionConfig(configJson, configPath)); } if (configJson.count("replayGeneratorConfig")) { replayGeneratorConfig = ReplayGeneratorConfig{configJson["replayGeneratorConfig"]}; } // If you added new fields to the configuration, update the JSONSetVal // to make them available for the json configs and increment the size // below checkCorrectSize<StressorConfig, 456>(); } bool StressorConfig::usesChainedItems() const { for (const auto& c : poolDistributions) { if (c.usesChainedItems()) { return true; } } return false; } CacheBenchConfig::CacheBenchConfig( const std::string& path, CacheConfigCustomizer cacheConfigCustomizer, StressorConfigCustomizer stressorConfigCustomizer) { std::string configString; if (!folly::readFile(path.c_str(), configString)) { throw std::invalid_argument( folly::sformat("could not read file: {}", path)); } std::cout << "===JSON Config===" << std::endl; std::cout << configString << std::endl; auto configJson = folly::parseJson(folly::json::stripComments(configString)); auto& testConfigJson = configJson["test_config"]; if (testConfigJson.getDefault("configPath", "").empty()) { // strip out the file name at the end to get the directory if the path // contains / and if not, the path is present directory. Assume the file // does not have any escaped '/' auto pos = path.find_last_of('/'); const std::string configDir = (pos != std::string::npos) ? std::string{path.begin(), path.begin() + pos} : "."; testConfigJson["configPath"] = configDir; } // if present, customize the configuration. auto stressorConfig = StressorConfig{testConfigJson}; stressorConfig_ = stressorConfigCustomizer ? stressorConfigCustomizer(stressorConfig) : stressorConfig; auto cacheConfig = CacheConfig{configJson["cache_config"]}; cacheConfig_ = cacheConfigCustomizer ? cacheConfigCustomizer(cacheConfig) : cacheConfig; } DistributionConfig::DistributionConfig(const folly::dynamic& jsonConfig, const std::string& configPath) { JSONSetVal(jsonConfig, keySizeRange); JSONSetVal(jsonConfig, keySizeRangeProbability); JSONSetVal(jsonConfig, valSizeRange); JSONSetVal(jsonConfig, valSizeRangeProbability); JSONSetVal(jsonConfig, valSizeDistFile); JSONSetVal(jsonConfig, chainedItemLengthRange); JSONSetVal(jsonConfig, chainedItemLengthRangeProbability); JSONSetVal(jsonConfig, chainedItemValSizeRange); JSONSetVal(jsonConfig, chainedItemValSizeRangeProbability); JSONSetVal(jsonConfig, popularityBuckets); JSONSetVal(jsonConfig, popularityWeights); JSONSetVal(jsonConfig, popDistFile); JSONSetVal(jsonConfig, getRatio); JSONSetVal(jsonConfig, setRatio); JSONSetVal(jsonConfig, delRatio); JSONSetVal(jsonConfig, addChainedRatio); JSONSetVal(jsonConfig, loneGetRatio); JSONSetVal(jsonConfig, loneSetRatio); JSONSetVal(jsonConfig, updateRatio); auto readFile = [&](const std::string& f) { std::string str; const std::string path = folly::sformat("{}/{}", configPath, f); std::cout << "reading distribution params from " << path << std::endl; if (!folly::readFile(path.c_str(), str)) { throw std::invalid_argument( folly::sformat("could not read file: {}", path)); } return str; }; if (!valSizeDistFile.empty()) { const auto configJsonVal = folly::parseJson(readFile(valSizeDistFile)); JSONSetVal(configJsonVal, valSizeRange); JSONSetVal(configJsonVal, valSizeRangeProbability); } if (!popDistFile.empty()) { const auto configJsonPop = folly::parseJson(readFile(popDistFile)); JSONSetVal(configJsonPop, popularityBuckets); JSONSetVal(configJsonPop, popularityWeights); } checkCorrectSize<DistributionConfig, 360>(); } ReplayGeneratorConfig::ReplayGeneratorConfig(const folly::dynamic& configJson) { JSONSetVal(configJson, replaySerializationMode); JSONSetVal(configJson, relaxedSerialIntervalMs); JSONSetVal(configJson, numAggregationFields); JSONSetVal(configJson, numExtraFields); JSONSetVal(configJson, statsPerAggField); if (configJson.count("mlAdmissionConfig")) { mlAdmissionConfig = std::make_shared<MLAdmissionConfig>(configJson["mlAdmissionConfig"]); } if (replaySerializationMode != "strict" && replaySerializationMode != "relaxed" && replaySerializationMode != "none") { throw std::invalid_argument(folly::sformat( "Unsupported request serialization mode: {}", replaySerializationMode)); } checkCorrectSize<ReplayGeneratorConfig, 120>(); } ReplayGeneratorConfig::SerializeMode ReplayGeneratorConfig::getSerializationMode() const { if (replaySerializationMode == "relaxed") { return ReplayGeneratorConfig::SerializeMode::relaxed; } if (replaySerializationMode == "none") { return ReplayGeneratorConfig::SerializeMode::none; } return ReplayGeneratorConfig::SerializeMode::strict; } MLAdmissionConfig::MLAdmissionConfig(const folly::dynamic& configJson) { JSONSetVal(configJson, modelPath); JSONSetVal(configJson, numericFeatures); JSONSetVal(configJson, categoricalFeatures); JSONSetVal(configJson, targetRecall); JSONSetVal(configJson, admitCategory); checkCorrectSize<MLAdmissionConfig, 160>(); } } // namespace cachebench } // namespace cachelib } // namespace facebook