masaori335 commented on code in PR #13741: URL: https://github.com/apache/trafficserver/pull/13741#discussion_r4120590281
########## src/iocore/cache/unit_tests/test_RamCacheHitRate.cc: ########## @@ -0,0 +1,280 @@ +/** @file + + Catch-based unit tests for RamCache hit rates under a Zipf workload. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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 "main.h" +#include "test_doubles.h" + +#include "../P_CacheInternal.h" +#include "../P_RamCache.h" + +#include "tscore/Random.h" + +#include <cmath> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <vector> + +int cache_vols = 1; +bool reuse_existing_cache = false; + +namespace +{ + +// Inherited from the regression test. 1 MB is the tight size: LRU variable-size scored 0.5565 and CLFUS 0.5665 at the port. +constexpr double MIN_HIT_RATE = 0.55; +constexpr int ZIPF_SIZE = 1 << 20; +constexpr double ZIPF_ALPHA = 1.2; + +struct PolicyCase { + RamCache *(*factory)(); + const char *name; +}; + +const PolicyCase policy_cases[] = { + {new_RamCacheLRU, "LRU" }, + {new_RamCacheCLFUS, "CLFUS" }, + {new_RamCacheS3FIFO, "S3-FIFO"}, +}; + +struct HitRates { + bool hot_keys_resident = true; + double fixed_size = 0; + double variable_size = 0; + int64_t size = 0; +}; + +void +wire_stripe(StripeSM &stripe, CacheVol &cache_vol) +{ + stripe.cache_vol = &cache_vol; + + cache_rsb.ram_cache_bytes = ts::Metrics::Gauge::createPtr("unit_test.hitrate.ram_cache.bytes"); + cache_rsb.ram_cache_hits = ts::Metrics::Counter::createPtr("unit_test.hitrate.ram_cache.hits"); + cache_rsb.ram_cache_misses = ts::Metrics::Counter::createPtr("unit_test.hitrate.ram_cache.misses"); + cache_vol.vol_rsb.ram_cache_bytes = ts::Metrics::Gauge::createPtr("unit_test.hitrate.vol.ram_cache.bytes"); + cache_vol.vol_rsb.ram_cache_hits = ts::Metrics::Counter::createPtr("unit_test.hitrate.vol.ram_cache.hits"); + cache_vol.vol_rsb.ram_cache_misses = ts::Metrics::Counter::createPtr("unit_test.hitrate.vol.ram_cache.misses"); +} + +RamCache * +make_cache(RamCache *(*factory)(), StripeSM &stripe, int64_t max_bytes) +{ + // No compression, so CLFUS schedules no background compressor holding a pointer to this cache. + cache_config_ram_cache_compress = CACHE_COMPRESSION_NONE; + cache_config_ram_cache_use_seen_filter = 1; + + // The policies have no destructors; keep every cache reachable so leak checkers stay quiet. + static std::vector<RamCache *> &all_caches = *new std::vector<RamCache *>; + RamCache *rc = factory(); + + all_caches.push_back(rc); + rc->init(max_bytes, &stripe); + return rc; +} + +std::vector<double> const & +zipf_cdf() +{ + static std::vector<double> const table = [] { + std::vector<double> t(ZIPF_SIZE); + + for (int i = 0; i < ZIPF_SIZE; i++) { + t[i] = 1.0 / std::pow(i + 2, ZIPF_ALPHA); + } + for (int i = 1; i < ZIPF_SIZE; i++) { + t[i] += t[i - 1]; + } + double const total = t.back(); + for (auto &x : t) { + x /= total; + } + return t; + }(); + + return table; +} + +// Kept bit-for-bit with the former regression test's search: the hit-rate floor was calibrated against it. +int +zipf_sample(double v) +{ + auto const &cdf = zipf_cdf(); + int l = 0; + int r = ZIPF_SIZE - 1; + int m = 0; + + do { + m = (r + l) / 2; + if (v < cdf[m]) { + r = m - 1; + } else { + l = m + 1; + } + } while (l < r); + return m; +} + +CryptoHash +numbered_key(uint64_t n) +{ + CryptoHash key; + + key.u64[0] = (n << 32) + n; + key.u64[1] = (n << 32) + n; + return key; +} + +Ptr<IOBufferData> +zeroed_buffer(int64_t size_index) +{ + Ptr<IOBufferData> data{make_ptr(new_IOBufferData(size_index))}; + + std::memset(data->data(), 0, data->block_size()); + return data; +} + +// Only the second half of the samples is scored, so the cache is warm. Fixed-size fills put 16K buffers with a +// 32K length, as the regression did; variable-size fills use 8K/16K/32K buffers at their real length. +double +hit_rate(RamCache *cache, std::vector<int> const &samples, bool variable_size) +{ + std::vector<Ptr<IOBufferData>> fills; Review Comment: I'd reject this. The RAM cache entries hold Ptr<IOBufferData> (e.g. RamCacheLRU.cc:270, RamCacheS3FIFO.cc:440, RamCacheCLFUS.cc:939), so each resident entry keeps its own reference; destroying fills/warm only drops the test's reference. The former regression cleared its buffer vector between passes the same way. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
