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