12 #include <boost/test/unit_test.hpp>
41 for (
int x = 0; x < 100000; ++x) {
42 cc.insert(InsecureRand256());
44 for (
int x = 0; x < 100000; ++x) {
45 BOOST_CHECK(!cc.contains(InsecureRand256(),
false));
52 template <
typename Cache>
56 std::vector<uint256> hashes;
58 size_t bytes = megabytes * (1 << 20);
59 set.setup_bytes(bytes);
60 uint32_t n_insert =
static_cast<uint32_t
>(load * (bytes /
sizeof(
uint256)));
61 hashes.resize(n_insert);
62 for (uint32_t i = 0; i < n_insert; ++i) {
63 uint32_t* ptr = (uint32_t*)hashes[i].begin();
64 for (uint8_t j = 0; j < 8; ++j)
65 *(ptr++) = InsecureRand32();
71 std::vector<uint256> hashes_insert_copy = hashes;
73 for (
uint256& h : hashes_insert_copy)
78 count += set.contains(h,
false);
79 double hit_rate = ((double)count) / ((double)n_insert);
102 return hits * std::max(load, 1.0);
111 double HitRateThresh = 0.98;
112 size_t megabytes = 4;
113 for (
double load = 0.1; load < 2; load *= 2) {
114 double hits = test_cache<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes, load);
122 template <
typename Cache>
127 std::vector<uint256> hashes;
129 size_t bytes = megabytes * (1 << 20);
130 set.setup_bytes(bytes);
131 uint32_t n_insert =
static_cast<uint32_t
>(load * (bytes /
sizeof(
uint256)));
132 hashes.resize(n_insert);
133 for (uint32_t i = 0; i < n_insert; ++i) {
134 uint32_t* ptr = (uint32_t*)hashes[i].begin();
135 for (uint8_t j = 0; j < 8; ++j)
136 *(ptr++) = InsecureRand32();
142 std::vector<uint256> hashes_insert_copy = hashes;
145 for (uint32_t i = 0; i < (n_insert / 2); ++i)
146 set.insert(hashes_insert_copy[i]);
148 for (uint32_t i = 0; i < (n_insert / 4); ++i)
149 set.contains(hashes[i],
true);
151 for (uint32_t i = (n_insert / 2); i < n_insert; ++i)
152 set.insert(hashes_insert_copy[i]);
155 size_t count_erased_but_contained = 0;
157 size_t count_stale = 0;
159 size_t count_fresh = 0;
161 for (uint32_t i = 0; i < (n_insert / 4); ++i)
162 count_erased_but_contained += set.contains(hashes[i],
false);
163 for (uint32_t i = (n_insert / 4); i < (n_insert / 2); ++i)
164 count_stale += set.contains(hashes[i],
false);
165 for (uint32_t i = (n_insert / 2); i < n_insert; ++i)
166 count_fresh += set.contains(hashes[i],
false);
168 double hit_rate_erased_but_contained = double(count_erased_but_contained) / (double(n_insert) / 4.0);
169 double hit_rate_stale = double(count_stale) / (double(n_insert) / 4.0);
170 double hit_rate_fresh = double(count_fresh) / (double(n_insert) / 2.0);
176 BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained);
181 size_t megabytes = 4;
182 test_cache_erase<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes);
185 template <
typename Cache>
190 std::vector<uint256> hashes;
192 size_t bytes = megabytes * (1 << 20);
193 set.setup_bytes(bytes);
194 uint32_t n_insert =
static_cast<uint32_t
>(load * (bytes /
sizeof(
uint256)));
195 hashes.resize(n_insert);
196 for (uint32_t i = 0; i < n_insert; ++i) {
197 uint32_t* ptr = (uint32_t*)hashes[i].begin();
198 for (uint8_t j = 0; j < 8; ++j)
199 *(ptr++) = InsecureRand32();
205 std::vector<uint256> hashes_insert_copy = hashes;
206 boost::shared_mutex mtx;
210 boost::unique_lock<boost::shared_mutex> l(mtx);
212 for (uint32_t i = 0; i < (n_insert / 2); ++i)
213 set.insert(hashes_insert_copy[i]);
218 std::vector<std::thread> threads;
220 for (uint32_t x = 0; x < 3; ++x)
223 threads.emplace_back([&, x] {
224 boost::shared_lock<boost::shared_mutex> l(mtx);
225 size_t ntodo = (n_insert/4)/3;
226 size_t start = ntodo*x;
227 size_t end = ntodo*(x+1);
228 for (uint32_t i = start; i < end; ++i)
229 set.contains(hashes[i],
true);
234 for (std::thread& t : threads)
237 boost::unique_lock<boost::shared_mutex> l(mtx);
239 for (uint32_t i = (n_insert / 2); i < n_insert; ++i)
240 set.insert(hashes_insert_copy[i]);
243 size_t count_erased_but_contained = 0;
245 size_t count_stale = 0;
247 size_t count_fresh = 0;
249 for (uint32_t i = 0; i < (n_insert / 4); ++i)
250 count_erased_but_contained += set.contains(hashes[i],
false);
251 for (uint32_t i = (n_insert / 4); i < (n_insert / 2); ++i)
252 count_stale += set.contains(hashes[i],
false);
253 for (uint32_t i = (n_insert / 2); i < n_insert; ++i)
254 count_fresh += set.contains(hashes[i],
false);
256 double hit_rate_erased_but_contained = double(count_erased_but_contained) / (double(n_insert) / 4.0);
257 double hit_rate_stale = double(count_stale) / (double(n_insert) / 4.0);
258 double hit_rate_fresh = double(count_fresh) / (double(n_insert) / 2.0);
264 BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained);
268 size_t megabytes = 4;
269 test_cache_erase_parallel<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes);
273 template <
typename Cache>
279 double min_hit_rate = 0.99;
280 double tight_hit_rate = 0.999;
281 double max_rate_less_than_tight_hit_rate = 0.01;
298 struct block_activity {
299 std::vector<uint256> reads;
300 block_activity(uint32_t n_insert, Cache& c) : reads()
302 std::vector<uint256> inserts;
303 inserts.resize(n_insert);
304 reads.reserve(n_insert / 2);
305 for (uint32_t i = 0; i < n_insert; ++i) {
306 uint32_t* ptr = (uint32_t*)inserts[i].begin();
307 for (uint8_t j = 0; j < 8; ++j)
308 *(ptr++) = InsecureRand32();
310 for (uint32_t i = 0; i < n_insert / 4; ++i)
311 reads.push_back(inserts[i]);
312 for (uint32_t i = n_insert - (n_insert / 4); i < n_insert; ++i)
313 reads.push_back(inserts[i]);
314 for (
auto h : inserts)
319 const uint32_t BLOCK_SIZE = 1000;
322 const uint32_t WINDOW_SIZE = 60;
323 const uint32_t POP_AMOUNT = (BLOCK_SIZE / WINDOW_SIZE) / 2;
324 const double load = 10;
325 const size_t megabytes = 4;
326 const size_t bytes = megabytes * (1 << 20);
327 const uint32_t n_insert =
static_cast<uint32_t
>(load * (bytes /
sizeof(
uint256)));
329 std::vector<block_activity> hashes;
331 set.setup_bytes(bytes);
332 hashes.reserve(n_insert / BLOCK_SIZE);
333 std::deque<block_activity> last_few;
334 uint32_t out_of_tight_tolerance = 0;
335 uint32_t total = n_insert / BLOCK_SIZE;
339 for (uint32_t i = 0; i < total; ++i) {
340 if (last_few.size() == WINDOW_SIZE)
341 last_few.pop_front();
342 last_few.emplace_back(BLOCK_SIZE, set);
344 for (
auto& act : last_few)
345 for (uint32_t k = 0; k < POP_AMOUNT; ++k) {
346 count += set.contains(act.reads.back(),
true);
347 act.reads.pop_back();
352 double hit = (double(count)) / (last_few.size() * POP_AMOUNT);
357 out_of_tight_tolerance += hit < tight_hit_rate;
361 BOOST_CHECK(
double(out_of_tight_tolerance) /
double(total) < max_rate_less_than_tight_hit_rate);
365 test_cache_generations<CuckooCache::cache<uint256, SignatureCacheHasher>>();
cache implements a cache with properties similar to a cuckoo-set
uint32_t setup_bytes(size_t bytes)
setup_bytes is a convenience function which accounts for internal memory usage when deciding how many...
BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes)
double normalize_hit_rate(double hits, double load)
The normalized hit rate for a given load.
double test_cache(size_t megabytes, double load)
This helper returns the hit rate when megabytes*load worth of entries are inserted into a megabytes s...
void test_cache_erase(size_t megabytes)
This helper checks that erased elements are preferentially inserted onto and that the hit rate of "fr...
void test_cache_erase_parallel(size_t megabytes)
BOOST_AUTO_TEST_SUITE(cuckoocache_tests)
Test Suite for CuckooCache.
void test_cache_generations()
BOOST_AUTO_TEST_SUITE_END()
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
@ ZEROS
Seed with a compile time constant of zeros.