1*4bdc9457SAndroid Build Coastguard Worker // Copyright 2022 Google LLC
2*4bdc9457SAndroid Build Coastguard Worker //
3*4bdc9457SAndroid Build Coastguard Worker // This source code is licensed under the BSD-style license found in the
4*4bdc9457SAndroid Build Coastguard Worker // LICENSE file in the root directory of this source tree.
5*4bdc9457SAndroid Build Coastguard Worker
6*4bdc9457SAndroid Build Coastguard Worker #include <cstdint> // For uintptr_t.
7*4bdc9457SAndroid Build Coastguard Worker #include <cstring> // For memcpy.
8*4bdc9457SAndroid Build Coastguard Worker
9*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack.h>
10*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/cache.h>
11*4bdc9457SAndroid Build Coastguard Worker
12*4bdc9457SAndroid Build Coastguard Worker #include <gtest/gtest.h>
13*4bdc9457SAndroid Build Coastguard Worker
cache_end(const xnn_code_cache * cache)14*4bdc9457SAndroid Build Coastguard Worker static void* cache_end(const xnn_code_cache* cache) {
15*4bdc9457SAndroid Build Coastguard Worker return reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(cache->cache.code.start) + cache->cache.code.size);
16*4bdc9457SAndroid Build Coastguard Worker }
17*4bdc9457SAndroid Build Coastguard Worker
write_code(xnn_code_cache * cache,const std::string & str)18*4bdc9457SAndroid Build Coastguard Worker static void write_code(xnn_code_cache* cache, const std::string& str) {
19*4bdc9457SAndroid Build Coastguard Worker ASSERT_GE(cache->cache.code.capacity - cache->cache.code.size, str.length());
20*4bdc9457SAndroid Build Coastguard Worker std::memcpy(cache_end(cache), str.data(), str.length());
21*4bdc9457SAndroid Build Coastguard Worker cache->cache.code.size += str.length();
22*4bdc9457SAndroid Build Coastguard Worker };
23*4bdc9457SAndroid Build Coastguard Worker
TEST(CODE_CACHE,init_and_release)24*4bdc9457SAndroid Build Coastguard Worker TEST(CODE_CACHE, init_and_release)
25*4bdc9457SAndroid Build Coastguard Worker {
26*4bdc9457SAndroid Build Coastguard Worker xnn_initialize(/*allocator=*/nullptr);
27*4bdc9457SAndroid Build Coastguard Worker xnn_code_cache cache;
28*4bdc9457SAndroid Build Coastguard Worker EXPECT_EQ(xnn_status_success, xnn_init_code_cache(&cache));
29*4bdc9457SAndroid Build Coastguard Worker EXPECT_EQ(xnn_status_success, xnn_release_code_cache(&cache));
30*4bdc9457SAndroid Build Coastguard Worker }
31*4bdc9457SAndroid Build Coastguard Worker
32*4bdc9457SAndroid Build Coastguard Worker
TEST(CODE_CACHE,release_null)33*4bdc9457SAndroid Build Coastguard Worker TEST(CODE_CACHE, release_null)
34*4bdc9457SAndroid Build Coastguard Worker {
35*4bdc9457SAndroid Build Coastguard Worker EXPECT_EQ(xnn_status_success, xnn_release_code_cache(NULL));
36*4bdc9457SAndroid Build Coastguard Worker }
37*4bdc9457SAndroid Build Coastguard Worker
TEST(CODE_CACHE,get_or_insert)38*4bdc9457SAndroid Build Coastguard Worker TEST(CODE_CACHE, get_or_insert)
39*4bdc9457SAndroid Build Coastguard Worker {
40*4bdc9457SAndroid Build Coastguard Worker xnn_initialize(/*allocator=*/nullptr);
41*4bdc9457SAndroid Build Coastguard Worker xnn_code_cache cache;
42*4bdc9457SAndroid Build Coastguard Worker EXPECT_EQ(xnn_status_success, xnn_init_code_cache(&cache));
43*4bdc9457SAndroid Build Coastguard Worker
44*4bdc9457SAndroid Build Coastguard Worker write_code(&cache, "1234");
45*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(0, xnn_get_or_insert_code_cache(&cache, cache.cache.code.start, 4));
46*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(0, cache.cache.hits);
47*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(1, cache.cache.misses);
48*4bdc9457SAndroid Build Coastguard Worker
49*4bdc9457SAndroid Build Coastguard Worker void* span2_code = cache_end(&cache);
50*4bdc9457SAndroid Build Coastguard Worker // Simulate a cache hit.
51*4bdc9457SAndroid Build Coastguard Worker write_code(&cache, "1234");
52*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(0, xnn_get_or_insert_code_cache(&cache, span2_code, 4));
53*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(1, cache.cache.hits);
54*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(1, cache.cache.misses);
55*4bdc9457SAndroid Build Coastguard Worker
56*4bdc9457SAndroid Build Coastguard Worker void* span3_code = cache_end(&cache);
57*4bdc9457SAndroid Build Coastguard Worker // Simulate a cache miss.
58*4bdc9457SAndroid Build Coastguard Worker write_code(&cache, "5678");
59*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(4, xnn_get_or_insert_code_cache(&cache, span3_code, 4));
60*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(1, cache.cache.hits);
61*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(2, cache.cache.misses);
62*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(2, cache.cache.num_entries);
63*4bdc9457SAndroid Build Coastguard Worker
64*4bdc9457SAndroid Build Coastguard Worker EXPECT_EQ(xnn_status_success, xnn_release_code_cache(&cache));
65*4bdc9457SAndroid Build Coastguard Worker }
66*4bdc9457SAndroid Build Coastguard Worker
TEST(CODE_CACHE,grow)67*4bdc9457SAndroid Build Coastguard Worker TEST(CODE_CACHE, grow) {
68*4bdc9457SAndroid Build Coastguard Worker xnn_initialize(/*allocator=*/nullptr);
69*4bdc9457SAndroid Build Coastguard Worker xnn_code_cache cache;
70*4bdc9457SAndroid Build Coastguard Worker EXPECT_EQ(xnn_status_success, xnn_init_code_cache(&cache));
71*4bdc9457SAndroid Build Coastguard Worker size_t old_num_buckets = cache.cache.num_buckets;
72*4bdc9457SAndroid Build Coastguard Worker for (size_t i = 0, expected_offset = 0; i < old_num_buckets; i++) {
73*4bdc9457SAndroid Build Coastguard Worker // Add many entries to force cache to grow.
74*4bdc9457SAndroid Build Coastguard Worker const std::string s = std::to_string(i);
75*4bdc9457SAndroid Build Coastguard Worker // write_code will update cache size, so get the code offset first.
76*4bdc9457SAndroid Build Coastguard Worker void* code_ptr = cache_end(&cache);
77*4bdc9457SAndroid Build Coastguard Worker write_code(&cache, s);
78*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(expected_offset, xnn_get_or_insert_code_cache(&cache, code_ptr, s.length()));
79*4bdc9457SAndroid Build Coastguard Worker expected_offset += s.length();
80*4bdc9457SAndroid Build Coastguard Worker }
81*4bdc9457SAndroid Build Coastguard Worker
82*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(0, cache.cache.hits);
83*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(old_num_buckets, cache.cache.num_entries);
84*4bdc9457SAndroid Build Coastguard Worker // Check that cache has grown.
85*4bdc9457SAndroid Build Coastguard Worker ASSERT_LT(old_num_buckets, cache.cache.num_buckets);
86*4bdc9457SAndroid Build Coastguard Worker // Check that all the entries are still in cache.
87*4bdc9457SAndroid Build Coastguard Worker for (size_t i = 0, expected_offset = 0; i < old_num_buckets; i++) {
88*4bdc9457SAndroid Build Coastguard Worker const std::string s = std::to_string(i);
89*4bdc9457SAndroid Build Coastguard Worker // write_code will update cache size, so get the code offset first.
90*4bdc9457SAndroid Build Coastguard Worker void* code_ptr = cache_end(&cache);
91*4bdc9457SAndroid Build Coastguard Worker write_code(&cache, s);
92*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(expected_offset, xnn_get_or_insert_code_cache(&cache, code_ptr, s.length()));
93*4bdc9457SAndroid Build Coastguard Worker expected_offset += s.length();
94*4bdc9457SAndroid Build Coastguard Worker }
95*4bdc9457SAndroid Build Coastguard Worker // And now all of the lookups should be cache hits.
96*4bdc9457SAndroid Build Coastguard Worker ASSERT_EQ(old_num_buckets, cache.cache.hits);
97*4bdc9457SAndroid Build Coastguard Worker
98*4bdc9457SAndroid Build Coastguard Worker EXPECT_EQ(xnn_status_success, xnn_release_code_cache(&cache));
99*4bdc9457SAndroid Build Coastguard Worker }
100