1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2015 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci/* A collection of unit tests for cache.c */
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include <gtest/gtest.h>
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include <stdio.h>
29bf215546Sopenharmony_ci#include <stdlib.h>
30bf215546Sopenharmony_ci#include <stdbool.h>
31bf215546Sopenharmony_ci#include <string.h>
32bf215546Sopenharmony_ci#include <ftw.h>
33bf215546Sopenharmony_ci#include <errno.h>
34bf215546Sopenharmony_ci#include <stdarg.h>
35bf215546Sopenharmony_ci#include <inttypes.h>
36bf215546Sopenharmony_ci#include <limits.h>
37bf215546Sopenharmony_ci#include <time.h>
38bf215546Sopenharmony_ci#include <unistd.h>
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci#include "util/mesa-sha1.h"
41bf215546Sopenharmony_ci#include "util/disk_cache.h"
42bf215546Sopenharmony_ci#include "util/ralloc.h"
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci#ifdef ENABLE_SHADER_CACHE
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci/* Callback for nftw used in rmrf_local below.
47bf215546Sopenharmony_ci */
48bf215546Sopenharmony_cistatic int
49bf215546Sopenharmony_ciremove_entry(const char *path,
50bf215546Sopenharmony_ci             const struct stat *sb,
51bf215546Sopenharmony_ci             int typeflag,
52bf215546Sopenharmony_ci             struct FTW *ftwbuf)
53bf215546Sopenharmony_ci{
54bf215546Sopenharmony_ci   int err = remove(path);
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   if (err)
57bf215546Sopenharmony_ci      fprintf(stderr, "Error removing %s: %s\n", path, strerror(errno));
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   return err;
60bf215546Sopenharmony_ci}
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci/* Recursively remove a directory.
63bf215546Sopenharmony_ci *
64bf215546Sopenharmony_ci * This is equivalent to "rm -rf <dir>" with one bit of protection
65bf215546Sopenharmony_ci * that the directory name must begin with "." to ensure we don't
66bf215546Sopenharmony_ci * wander around deleting more than intended.
67bf215546Sopenharmony_ci *
68bf215546Sopenharmony_ci * Returns 0 on success, -1 on any error.
69bf215546Sopenharmony_ci */
70bf215546Sopenharmony_cistatic int
71bf215546Sopenharmony_cirmrf_local(const char *path)
72bf215546Sopenharmony_ci{
73bf215546Sopenharmony_ci   if (path == NULL || *path == '\0' || *path != '.')
74bf215546Sopenharmony_ci      return -1;
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   return nftw(path, remove_entry, 64, FTW_DEPTH | FTW_PHYS);
77bf215546Sopenharmony_ci}
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_cistatic void
80bf215546Sopenharmony_cicheck_directories_created(void *mem_ctx, const char *cache_dir)
81bf215546Sopenharmony_ci{
82bf215546Sopenharmony_ci   bool sub_dirs_created = false;
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   char buf[PATH_MAX];
85bf215546Sopenharmony_ci   if (getcwd(buf, PATH_MAX)) {
86bf215546Sopenharmony_ci      char *full_path = ralloc_asprintf(mem_ctx, "%s%s", buf, ++cache_dir);
87bf215546Sopenharmony_ci      struct stat sb;
88bf215546Sopenharmony_ci      if (stat(full_path, &sb) != -1 && S_ISDIR(sb.st_mode))
89bf215546Sopenharmony_ci         sub_dirs_created = true;
90bf215546Sopenharmony_ci   }
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   EXPECT_TRUE(sub_dirs_created) << "create sub dirs";
93bf215546Sopenharmony_ci}
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_cistatic bool
96bf215546Sopenharmony_cidoes_cache_contain(struct disk_cache *cache, const cache_key key)
97bf215546Sopenharmony_ci{
98bf215546Sopenharmony_ci   void *result;
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   result = disk_cache_get(cache, key, NULL);
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci   if (result) {
103bf215546Sopenharmony_ci      free(result);
104bf215546Sopenharmony_ci      return true;
105bf215546Sopenharmony_ci   }
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_ci   return false;
108bf215546Sopenharmony_ci}
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_cistatic bool
111bf215546Sopenharmony_cicache_exists(struct disk_cache *cache)
112bf215546Sopenharmony_ci{
113bf215546Sopenharmony_ci   uint8_t key[20];
114bf215546Sopenharmony_ci   char data[] = "some test data";
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci   if (!cache)
117bf215546Sopenharmony_ci      return false;
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci   disk_cache_compute_key(cache, data, sizeof(data), key);
120bf215546Sopenharmony_ci   disk_cache_put(cache, key, data, sizeof(data), NULL);
121bf215546Sopenharmony_ci   disk_cache_wait_for_idle(cache);
122bf215546Sopenharmony_ci   void *result = disk_cache_get(cache, key, NULL);
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci   free(result);
125bf215546Sopenharmony_ci   return result != NULL;
126bf215546Sopenharmony_ci}
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci#define CACHE_TEST_TMP "./cache-test-tmp"
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_cistatic void
131bf215546Sopenharmony_citest_disk_cache_create(void *mem_ctx, const char *cache_dir_name)
132bf215546Sopenharmony_ci{
133bf215546Sopenharmony_ci   struct disk_cache *cache;
134bf215546Sopenharmony_ci   int err;
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   /* Before doing anything else, ensure that with
137bf215546Sopenharmony_ci    * MESA_SHADER_CACHE_DISABLE set to true, that disk_cache_create returns NULL.
138bf215546Sopenharmony_ci    */
139bf215546Sopenharmony_ci   setenv("MESA_SHADER_CACHE_DISABLE", "true", 1);
140bf215546Sopenharmony_ci   cache = disk_cache_create("test", "make_check", 0);
141bf215546Sopenharmony_ci   EXPECT_EQ(cache, nullptr) << "disk_cache_create with MESA_SHADER_CACHE_DISABLE set";
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci   unsetenv("MESA_SHADER_CACHE_DISABLE");
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT
146bf215546Sopenharmony_ci   /* With SHADER_CACHE_DISABLE_BY_DEFAULT, ensure that with
147bf215546Sopenharmony_ci    * MESA_SHADER_CACHE_DISABLE set to nothing, disk_cache_create returns NULL.
148bf215546Sopenharmony_ci    */
149bf215546Sopenharmony_ci   unsetenv("MESA_SHADER_CACHE_DISABLE");
150bf215546Sopenharmony_ci   cache = disk_cache_create("test", "make_check", 0);
151bf215546Sopenharmony_ci   EXPECT_EQ(cache, nullptr)
152bf215546Sopenharmony_ci      << "disk_cache_create with MESA_SHADER_CACHE_DISABLE unset "
153bf215546Sopenharmony_ci         "and SHADER_CACHE_DISABLE_BY_DEFAULT build option";
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   /* For remaining tests, ensure that the cache is enabled. */
156bf215546Sopenharmony_ci   setenv("MESA_SHADER_CACHE_DISABLE", "false", 1);
157bf215546Sopenharmony_ci#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_ci   /* For the first real disk_cache_create() clear these environment
160bf215546Sopenharmony_ci    * variables to test creation of cache in home directory.
161bf215546Sopenharmony_ci    */
162bf215546Sopenharmony_ci   unsetenv("MESA_SHADER_CACHE_DIR");
163bf215546Sopenharmony_ci   unsetenv("XDG_CACHE_HOME");
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   cache = disk_cache_create("test", "make_check", 0);
166bf215546Sopenharmony_ci   EXPECT_NE(cache, nullptr) << "disk_cache_create with no environment variables";
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci   disk_cache_destroy(cache);
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci#ifdef ANDROID
171bf215546Sopenharmony_ci   /* Android doesn't try writing to disk (just calls the cache callbacks), so
172bf215546Sopenharmony_ci    * the directory tests below don't apply.
173bf215546Sopenharmony_ci    */
174bf215546Sopenharmony_ci   return;
175bf215546Sopenharmony_ci#endif
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   /* Test with XDG_CACHE_HOME set */
178bf215546Sopenharmony_ci   setenv("XDG_CACHE_HOME", CACHE_TEST_TMP "/xdg-cache-home", 1);
179bf215546Sopenharmony_ci   cache = disk_cache_create("test", "make_check", 0);
180bf215546Sopenharmony_ci   EXPECT_FALSE(cache_exists(cache))
181bf215546Sopenharmony_ci      << "disk_cache_create with XDG_CACHE_HOME set with a non-existing parent directory";
182bf215546Sopenharmony_ci
183bf215546Sopenharmony_ci   err = mkdir(CACHE_TEST_TMP, 0755);
184bf215546Sopenharmony_ci   if (err != 0) {
185bf215546Sopenharmony_ci      fprintf(stderr, "Error creating %s: %s\n", CACHE_TEST_TMP, strerror(errno));
186bf215546Sopenharmony_ci      GTEST_FAIL();
187bf215546Sopenharmony_ci   }
188bf215546Sopenharmony_ci   disk_cache_destroy(cache);
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci   cache = disk_cache_create("test", "make_check", 0);
191bf215546Sopenharmony_ci   EXPECT_TRUE(cache_exists(cache))
192bf215546Sopenharmony_ci      << "disk_cache_create with XDG_CACHE_HOME set";
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci   char *path = ralloc_asprintf(
195bf215546Sopenharmony_ci      mem_ctx, "%s%s", CACHE_TEST_TMP "/xdg-cache-home/", cache_dir_name);
196bf215546Sopenharmony_ci   check_directories_created(mem_ctx, path);
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci   disk_cache_destroy(cache);
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci   /* Test with MESA_SHADER_CACHE_DIR set */
201bf215546Sopenharmony_ci   err = rmrf_local(CACHE_TEST_TMP);
202bf215546Sopenharmony_ci   EXPECT_EQ(err, 0) << "Removing " CACHE_TEST_TMP;
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   setenv("MESA_SHADER_CACHE_DIR", CACHE_TEST_TMP "/mesa-shader-cache-dir", 1);
205bf215546Sopenharmony_ci   cache = disk_cache_create("test", "make_check", 0);
206bf215546Sopenharmony_ci   EXPECT_FALSE(cache_exists(cache))
207bf215546Sopenharmony_ci      << "disk_cache_create with MESA_SHADER_CACHE_DIR set with a non-existing parent directory";
208bf215546Sopenharmony_ci
209bf215546Sopenharmony_ci   err = mkdir(CACHE_TEST_TMP, 0755);
210bf215546Sopenharmony_ci   if (err != 0) {
211bf215546Sopenharmony_ci      fprintf(stderr, "Error creating %s: %s\n", CACHE_TEST_TMP, strerror(errno));
212bf215546Sopenharmony_ci      GTEST_FAIL();
213bf215546Sopenharmony_ci   }
214bf215546Sopenharmony_ci   disk_cache_destroy(cache);
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci   cache = disk_cache_create("test", "make_check", 0);
217bf215546Sopenharmony_ci   EXPECT_TRUE(cache_exists(cache)) << "disk_cache_create with MESA_SHADER_CACHE_DIR set";
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci   path = ralloc_asprintf(
220bf215546Sopenharmony_ci      mem_ctx, "%s%s", CACHE_TEST_TMP "/mesa-shader-cache-dir/", cache_dir_name);
221bf215546Sopenharmony_ci   check_directories_created(mem_ctx, path);
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci   disk_cache_destroy(cache);
224bf215546Sopenharmony_ci}
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_cistatic void
227bf215546Sopenharmony_citest_put_and_get(bool test_cache_size_limit)
228bf215546Sopenharmony_ci{
229bf215546Sopenharmony_ci   struct disk_cache *cache;
230bf215546Sopenharmony_ci   char blob[] = "This is a blob of thirty-seven bytes";
231bf215546Sopenharmony_ci   uint8_t blob_key[20];
232bf215546Sopenharmony_ci   char string[] = "While this string has thirty-four";
233bf215546Sopenharmony_ci   uint8_t string_key[20];
234bf215546Sopenharmony_ci   char *result;
235bf215546Sopenharmony_ci   size_t size;
236bf215546Sopenharmony_ci   uint8_t *one_KB, *one_MB;
237bf215546Sopenharmony_ci   uint8_t one_KB_key[20], one_MB_key[20];
238bf215546Sopenharmony_ci   int count;
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT
241bf215546Sopenharmony_ci   setenv("MESA_SHADER_CACHE_DISABLE", "false", 1);
242bf215546Sopenharmony_ci#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ci   cache = disk_cache_create("test", "make_check", 0);
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci   disk_cache_compute_key(cache, blob, sizeof(blob), blob_key);
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   /* Ensure that disk_cache_get returns nothing before anything is added. */
249bf215546Sopenharmony_ci   result = (char *) disk_cache_get(cache, blob_key, &size);
250bf215546Sopenharmony_ci   EXPECT_EQ(result, nullptr) << "disk_cache_get with non-existent item (pointer)";
251bf215546Sopenharmony_ci   EXPECT_EQ(size, 0) << "disk_cache_get with non-existent item (size)";
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci   /* Simple test of put and get. */
254bf215546Sopenharmony_ci   disk_cache_put(cache, blob_key, blob, sizeof(blob), NULL);
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci   /* disk_cache_put() hands things off to a thread so wait for it. */
257bf215546Sopenharmony_ci   disk_cache_wait_for_idle(cache);
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci   result = (char *) disk_cache_get(cache, blob_key, &size);
260bf215546Sopenharmony_ci   EXPECT_STREQ(blob, result) << "disk_cache_get of existing item (pointer)";
261bf215546Sopenharmony_ci   EXPECT_EQ(size, sizeof(blob)) << "disk_cache_get of existing item (size)";
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci   free(result);
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci   /* Test put and get of a second item. */
266bf215546Sopenharmony_ci   disk_cache_compute_key(cache, string, sizeof(string), string_key);
267bf215546Sopenharmony_ci   disk_cache_put(cache, string_key, string, sizeof(string), NULL);
268bf215546Sopenharmony_ci
269bf215546Sopenharmony_ci   /* disk_cache_put() hands things off to a thread so wait for it. */
270bf215546Sopenharmony_ci   disk_cache_wait_for_idle(cache);
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_ci   result = (char *) disk_cache_get(cache, string_key, &size);
273bf215546Sopenharmony_ci   EXPECT_STREQ(result, string) << "2nd disk_cache_get of existing item (pointer)";
274bf215546Sopenharmony_ci   EXPECT_EQ(size, sizeof(string)) << "2nd disk_cache_get of existing item (size)";
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   free(result);
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci   /* Set the cache size to 1KB and add a 1KB item to force an eviction. */
279bf215546Sopenharmony_ci   disk_cache_destroy(cache);
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   if (!test_cache_size_limit)
282bf215546Sopenharmony_ci      return;
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci   setenv("MESA_SHADER_CACHE_MAX_SIZE", "1K", 1);
285bf215546Sopenharmony_ci   cache = disk_cache_create("test", "make_check", 0);
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci   one_KB = (uint8_t *) calloc(1, 1024);
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   /* Obviously the SHA-1 hash of 1024 zero bytes isn't particularly
290bf215546Sopenharmony_ci    * interesting. But we do have want to take some special care with
291bf215546Sopenharmony_ci    * the hash we use here. The issue is that in this artificial case,
292bf215546Sopenharmony_ci    * (with only three files in the cache), the probability is good
293bf215546Sopenharmony_ci    * that each of the three files will end up in their own
294bf215546Sopenharmony_ci    * directory. Then, if the directory containing the .tmp file for
295bf215546Sopenharmony_ci    * the new item being added for disk_cache_put() is the chosen victim
296bf215546Sopenharmony_ci    * directory for eviction, then no suitable file will be found and
297bf215546Sopenharmony_ci    * nothing will be evicted.
298bf215546Sopenharmony_ci    *
299bf215546Sopenharmony_ci    * That's actually expected given how the eviction code is
300bf215546Sopenharmony_ci    * implemented, (which expects to only evict once things are more
301bf215546Sopenharmony_ci    * interestingly full than that).
302bf215546Sopenharmony_ci    *
303bf215546Sopenharmony_ci    * For this test, we force this signature to land in the same
304bf215546Sopenharmony_ci    * directory as the original blob first written to the cache.
305bf215546Sopenharmony_ci    */
306bf215546Sopenharmony_ci   disk_cache_compute_key(cache, one_KB, 1024, one_KB_key);
307bf215546Sopenharmony_ci   one_KB_key[0] = blob_key[0];
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_ci   disk_cache_put(cache, one_KB_key, one_KB, 1024, NULL);
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci   free(one_KB);
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci   /* disk_cache_put() hands things off to a thread so wait for it. */
314bf215546Sopenharmony_ci   disk_cache_wait_for_idle(cache);
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_ci   result = (char *) disk_cache_get(cache, one_KB_key, &size);
317bf215546Sopenharmony_ci   EXPECT_NE(result, nullptr) << "3rd disk_cache_get of existing item (pointer)";
318bf215546Sopenharmony_ci   EXPECT_EQ(size, 1024) << "3rd disk_cache_get of existing item (size)";
319bf215546Sopenharmony_ci
320bf215546Sopenharmony_ci   free(result);
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci   /* Ensure eviction happened by checking that both of the previous
323bf215546Sopenharmony_ci    * cache itesm were evicted.
324bf215546Sopenharmony_ci    */
325bf215546Sopenharmony_ci   bool contains_1KB_file = false;
326bf215546Sopenharmony_ci   count = 0;
327bf215546Sopenharmony_ci   if (does_cache_contain(cache, blob_key))
328bf215546Sopenharmony_ci       count++;
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci   if (does_cache_contain(cache, string_key))
331bf215546Sopenharmony_ci       count++;
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ci   if (does_cache_contain(cache, one_KB_key)) {
334bf215546Sopenharmony_ci      count++;
335bf215546Sopenharmony_ci      contains_1KB_file = true;
336bf215546Sopenharmony_ci   }
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci   EXPECT_TRUE(contains_1KB_file)
339bf215546Sopenharmony_ci      << "disk_cache_put eviction last file == MAX_SIZE (1KB)";
340bf215546Sopenharmony_ci   EXPECT_EQ(count, 1) << "disk_cache_put eviction with MAX_SIZE=1K";
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci   /* Now increase the size to 1M, add back both items, and ensure all
343bf215546Sopenharmony_ci    * three that have been added are available via disk_cache_get.
344bf215546Sopenharmony_ci    */
345bf215546Sopenharmony_ci   disk_cache_destroy(cache);
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci   setenv("MESA_SHADER_CACHE_MAX_SIZE", "1M", 1);
348bf215546Sopenharmony_ci   cache = disk_cache_create("test", "make_check", 0);
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_ci   disk_cache_put(cache, blob_key, blob, sizeof(blob), NULL);
351bf215546Sopenharmony_ci   disk_cache_put(cache, string_key, string, sizeof(string), NULL);
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci   /* disk_cache_put() hands things off to a thread so wait for it. */
354bf215546Sopenharmony_ci   disk_cache_wait_for_idle(cache);
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci   count = 0;
357bf215546Sopenharmony_ci   if (does_cache_contain(cache, blob_key))
358bf215546Sopenharmony_ci       count++;
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_ci   if (does_cache_contain(cache, string_key))
361bf215546Sopenharmony_ci       count++;
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci   if (does_cache_contain(cache, one_KB_key))
364bf215546Sopenharmony_ci       count++;
365bf215546Sopenharmony_ci
366bf215546Sopenharmony_ci   EXPECT_EQ(count, 3) << "no eviction before overflow with MAX_SIZE=1M";
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci   /* Finally, check eviction again after adding an object of size 1M. */
369bf215546Sopenharmony_ci   one_MB = (uint8_t *) calloc(1024, 1024);
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ci   disk_cache_compute_key(cache, one_MB, 1024 * 1024, one_MB_key);
372bf215546Sopenharmony_ci   one_MB_key[0] = blob_key[0];
373bf215546Sopenharmony_ci
374bf215546Sopenharmony_ci   disk_cache_put(cache, one_MB_key, one_MB, 1024 * 1024, NULL);
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci   free(one_MB);
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_ci   /* disk_cache_put() hands things off to a thread so wait for it. */
379bf215546Sopenharmony_ci   disk_cache_wait_for_idle(cache);
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci   bool contains_1MB_file = false;
382bf215546Sopenharmony_ci   count = 0;
383bf215546Sopenharmony_ci   if (does_cache_contain(cache, blob_key))
384bf215546Sopenharmony_ci       count++;
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci   if (does_cache_contain(cache, string_key))
387bf215546Sopenharmony_ci       count++;
388bf215546Sopenharmony_ci
389bf215546Sopenharmony_ci   if (does_cache_contain(cache, one_KB_key))
390bf215546Sopenharmony_ci       count++;
391bf215546Sopenharmony_ci
392bf215546Sopenharmony_ci   if (does_cache_contain(cache, one_MB_key)) {
393bf215546Sopenharmony_ci      count++;
394bf215546Sopenharmony_ci      contains_1MB_file = true;
395bf215546Sopenharmony_ci   }
396bf215546Sopenharmony_ci
397bf215546Sopenharmony_ci   EXPECT_TRUE(contains_1MB_file)
398bf215546Sopenharmony_ci      << "disk_cache_put eviction last file == MAX_SIZE (1MB)";
399bf215546Sopenharmony_ci   EXPECT_EQ(count, 1) << "eviction after overflow with MAX_SIZE=1M";
400bf215546Sopenharmony_ci
401bf215546Sopenharmony_ci   disk_cache_destroy(cache);
402bf215546Sopenharmony_ci}
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_cistatic void
405bf215546Sopenharmony_citest_put_key_and_get_key(void)
406bf215546Sopenharmony_ci{
407bf215546Sopenharmony_ci   struct disk_cache *cache;
408bf215546Sopenharmony_ci   bool result;
409bf215546Sopenharmony_ci
410bf215546Sopenharmony_ci   uint8_t key_a[20] = {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
411bf215546Sopenharmony_ci                         10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
412bf215546Sopenharmony_ci   uint8_t key_b[20] = { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
413bf215546Sopenharmony_ci                         30, 33, 32, 33, 34, 35, 36, 37, 38, 39};
414bf215546Sopenharmony_ci   uint8_t key_a_collide[20] =
415bf215546Sopenharmony_ci                        { 0,  1, 42, 43, 44, 45, 46, 47, 48, 49,
416bf215546Sopenharmony_ci                         50, 55, 52, 53, 54, 55, 56, 57, 58, 59};
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT
419bf215546Sopenharmony_ci   setenv("MESA_SHADER_CACHE_DISABLE", "false", 1);
420bf215546Sopenharmony_ci#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */
421bf215546Sopenharmony_ci
422bf215546Sopenharmony_ci   cache = disk_cache_create("test", "make_check", 0);
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_ci   /* First test that disk_cache_has_key returns false before disk_cache_put_key */
425bf215546Sopenharmony_ci   result = disk_cache_has_key(cache, key_a);
426bf215546Sopenharmony_ci   EXPECT_EQ(result, 0) << "disk_cache_has_key before key added";
427bf215546Sopenharmony_ci
428bf215546Sopenharmony_ci   /* Then a couple of tests of disk_cache_put_key followed by disk_cache_has_key */
429bf215546Sopenharmony_ci   disk_cache_put_key(cache, key_a);
430bf215546Sopenharmony_ci   result = disk_cache_has_key(cache, key_a);
431bf215546Sopenharmony_ci   EXPECT_EQ(result, 1) << "disk_cache_has_key after key added";
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   disk_cache_put_key(cache, key_b);
434bf215546Sopenharmony_ci   result = disk_cache_has_key(cache, key_b);
435bf215546Sopenharmony_ci   EXPECT_EQ(result, 1) << "2nd disk_cache_has_key after key added";
436bf215546Sopenharmony_ci
437bf215546Sopenharmony_ci   /* Test that a key with the same two bytes as an existing key
438bf215546Sopenharmony_ci    * forces an eviction.
439bf215546Sopenharmony_ci    */
440bf215546Sopenharmony_ci   disk_cache_put_key(cache, key_a_collide);
441bf215546Sopenharmony_ci   result = disk_cache_has_key(cache, key_a_collide);
442bf215546Sopenharmony_ci   EXPECT_EQ(result, 1) << "put_key of a colliding key lands in the cache";
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_ci   result = disk_cache_has_key(cache, key_a);
445bf215546Sopenharmony_ci   EXPECT_EQ(result, 0) << "put_key of a colliding key evicts from the cache";
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_ci   /* And finally test that we can re-add the original key to re-evict
448bf215546Sopenharmony_ci    * the colliding key.
449bf215546Sopenharmony_ci    */
450bf215546Sopenharmony_ci   disk_cache_put_key(cache, key_a);
451bf215546Sopenharmony_ci   result = disk_cache_has_key(cache, key_a);
452bf215546Sopenharmony_ci   EXPECT_EQ(result, 1) << "put_key of original key lands again";
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_ci   result = disk_cache_has_key(cache, key_a_collide);
455bf215546Sopenharmony_ci   EXPECT_EQ(result, 0) << "put_key of orginal key evicts the colliding key";
456bf215546Sopenharmony_ci
457bf215546Sopenharmony_ci   disk_cache_destroy(cache);
458bf215546Sopenharmony_ci}
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_ci/* To make sure we are not just using the inmemory cache index for the single
461bf215546Sopenharmony_ci * file cache we test adding and retriving cache items between two different
462bf215546Sopenharmony_ci * cache instances.
463bf215546Sopenharmony_ci */
464bf215546Sopenharmony_cistatic void
465bf215546Sopenharmony_citest_put_and_get_between_instances()
466bf215546Sopenharmony_ci{
467bf215546Sopenharmony_ci   char blob[] = "This is a blob of thirty-seven bytes";
468bf215546Sopenharmony_ci   uint8_t blob_key[20];
469bf215546Sopenharmony_ci   char string[] = "While this string has thirty-four";
470bf215546Sopenharmony_ci   uint8_t string_key[20];
471bf215546Sopenharmony_ci   char *result;
472bf215546Sopenharmony_ci   size_t size;
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_ci#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT
475bf215546Sopenharmony_ci   setenv("MESA_SHADER_CACHE_DISABLE", "false", 1);
476bf215546Sopenharmony_ci#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */
477bf215546Sopenharmony_ci
478bf215546Sopenharmony_ci   struct disk_cache *cache1 = disk_cache_create("test_between_instances",
479bf215546Sopenharmony_ci                                                 "make_check", 0);
480bf215546Sopenharmony_ci   struct disk_cache *cache2 = disk_cache_create("test_between_instances",
481bf215546Sopenharmony_ci                                                 "make_check", 0);
482bf215546Sopenharmony_ci
483bf215546Sopenharmony_ci   disk_cache_compute_key(cache1, blob, sizeof(blob), blob_key);
484bf215546Sopenharmony_ci
485bf215546Sopenharmony_ci   /* Ensure that disk_cache_get returns nothing before anything is added. */
486bf215546Sopenharmony_ci   result = (char *) disk_cache_get(cache1, blob_key, &size);
487bf215546Sopenharmony_ci   EXPECT_EQ(result, nullptr) << "disk_cache_get(cache1) with non-existent item (pointer)";
488bf215546Sopenharmony_ci   EXPECT_EQ(size, 0) << "disk_cache_get(cach1) with non-existent item (size)";
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_ci   result = (char *) disk_cache_get(cache2, blob_key, &size);
491bf215546Sopenharmony_ci   EXPECT_EQ(result, nullptr) << "disk_cache_get(cache2) with non-existent item (pointer)";
492bf215546Sopenharmony_ci   EXPECT_EQ(size, 0) << "disk_cache_get(cache2) with non-existent item (size)";
493bf215546Sopenharmony_ci
494bf215546Sopenharmony_ci   /* Simple test of put and get. */
495bf215546Sopenharmony_ci   disk_cache_put(cache1, blob_key, blob, sizeof(blob), NULL);
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci   /* disk_cache_put() hands things off to a thread so wait for it. */
498bf215546Sopenharmony_ci   disk_cache_wait_for_idle(cache1);
499bf215546Sopenharmony_ci
500bf215546Sopenharmony_ci   result = (char *) disk_cache_get(cache2, blob_key, &size);
501bf215546Sopenharmony_ci   EXPECT_STREQ(blob, result) << "disk_cache_get(cache2) of existing item (pointer)";
502bf215546Sopenharmony_ci   EXPECT_EQ(size, sizeof(blob)) << "disk_cache_get of(cache2) existing item (size)";
503bf215546Sopenharmony_ci
504bf215546Sopenharmony_ci   free(result);
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci   /* Test put and get of a second item, via the opposite instances */
507bf215546Sopenharmony_ci   disk_cache_compute_key(cache2, string, sizeof(string), string_key);
508bf215546Sopenharmony_ci   disk_cache_put(cache2, string_key, string, sizeof(string), NULL);
509bf215546Sopenharmony_ci
510bf215546Sopenharmony_ci   /* disk_cache_put() hands things off to a thread so wait for it. */
511bf215546Sopenharmony_ci   disk_cache_wait_for_idle(cache2);
512bf215546Sopenharmony_ci
513bf215546Sopenharmony_ci   result = (char *) disk_cache_get(cache1, string_key, &size);
514bf215546Sopenharmony_ci   EXPECT_STREQ(result, string) << "2nd disk_cache_get(cache1) of existing item (pointer)";
515bf215546Sopenharmony_ci   EXPECT_EQ(size, sizeof(string)) << "2nd disk_cache_get(cache1) of existing item (size)";
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_ci   free(result);
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_ci   disk_cache_destroy(cache1);
520bf215546Sopenharmony_ci   disk_cache_destroy(cache2);
521bf215546Sopenharmony_ci}
522bf215546Sopenharmony_ci#endif /* ENABLE_SHADER_CACHE */
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_ciclass Cache : public ::testing::Test {
525bf215546Sopenharmony_ciprotected:
526bf215546Sopenharmony_ci   void *mem_ctx;
527bf215546Sopenharmony_ci
528bf215546Sopenharmony_ci   Cache() {
529bf215546Sopenharmony_ci      mem_ctx = ralloc_context(NULL);
530bf215546Sopenharmony_ci   }
531bf215546Sopenharmony_ci   ~Cache() {
532bf215546Sopenharmony_ci      ralloc_free(mem_ctx);
533bf215546Sopenharmony_ci   }
534bf215546Sopenharmony_ci};
535bf215546Sopenharmony_ci
536bf215546Sopenharmony_ciTEST_F(Cache, MultiFile)
537bf215546Sopenharmony_ci{
538bf215546Sopenharmony_ci#ifndef ENABLE_SHADER_CACHE
539bf215546Sopenharmony_ci   GTEST_SKIP() << "ENABLE_SHADER_CACHE not defined.";
540bf215546Sopenharmony_ci#else
541bf215546Sopenharmony_ci   test_disk_cache_create(mem_ctx, CACHE_DIR_NAME);
542bf215546Sopenharmony_ci
543bf215546Sopenharmony_ci   test_put_and_get(true);
544bf215546Sopenharmony_ci
545bf215546Sopenharmony_ci   test_put_key_and_get_key();
546bf215546Sopenharmony_ci
547bf215546Sopenharmony_ci   int err = rmrf_local(CACHE_TEST_TMP);
548bf215546Sopenharmony_ci   EXPECT_EQ(err, 0) << "Removing " CACHE_TEST_TMP " again";
549bf215546Sopenharmony_ci#endif
550bf215546Sopenharmony_ci}
551bf215546Sopenharmony_ci
552bf215546Sopenharmony_ciTEST_F(Cache, SingleFile)
553bf215546Sopenharmony_ci{
554bf215546Sopenharmony_ci#ifndef ENABLE_SHADER_CACHE
555bf215546Sopenharmony_ci   GTEST_SKIP() << "ENABLE_SHADER_CACHE not defined.";
556bf215546Sopenharmony_ci#else
557bf215546Sopenharmony_ci   setenv("MESA_DISK_CACHE_SINGLE_FILE", "true", 1);
558bf215546Sopenharmony_ci
559bf215546Sopenharmony_ci   test_disk_cache_create(mem_ctx, CACHE_DIR_NAME_SF);
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci   /* We skip testing cache size limit as the single file cache currently
562bf215546Sopenharmony_ci    * doesn't have any functionality to enforce cache size limits.
563bf215546Sopenharmony_ci    */
564bf215546Sopenharmony_ci   test_put_and_get(false);
565bf215546Sopenharmony_ci
566bf215546Sopenharmony_ci   test_put_key_and_get_key();
567bf215546Sopenharmony_ci
568bf215546Sopenharmony_ci   test_put_and_get_between_instances();
569bf215546Sopenharmony_ci
570bf215546Sopenharmony_ci   setenv("MESA_DISK_CACHE_SINGLE_FILE", "false", 1);
571bf215546Sopenharmony_ci
572bf215546Sopenharmony_ci   int err = rmrf_local(CACHE_TEST_TMP);
573bf215546Sopenharmony_ci   EXPECT_EQ(err, 0) << "Removing " CACHE_TEST_TMP " again";
574bf215546Sopenharmony_ci#endif
575bf215546Sopenharmony_ci}
576