17ec681f3Smrg/* 27ec681f3Smrg * Copyright © 2015 Intel Corporation 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 217ec681f3Smrg * IN THE SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg/* A collection of unit tests for cache.c */ 257ec681f3Smrg 267ec681f3Smrg#include <stdio.h> 277ec681f3Smrg#include <stdlib.h> 287ec681f3Smrg#include <stdbool.h> 297ec681f3Smrg#include <string.h> 307ec681f3Smrg#include <ftw.h> 317ec681f3Smrg#include <errno.h> 327ec681f3Smrg#include <stdarg.h> 337ec681f3Smrg#include <inttypes.h> 347ec681f3Smrg#include <limits.h> 357ec681f3Smrg#include <time.h> 367ec681f3Smrg#include <unistd.h> 377ec681f3Smrg 387ec681f3Smrg#include "util/mesa-sha1.h" 397ec681f3Smrg#include "util/disk_cache.h" 407ec681f3Smrg 417ec681f3Smrgbool error = false; 427ec681f3Smrg 437ec681f3Smrg#ifdef ENABLE_SHADER_CACHE 447ec681f3Smrg 457ec681f3Smrgstatic void 467ec681f3Smrgexpect_true(bool result, const char *test) 477ec681f3Smrg{ 487ec681f3Smrg if (!result) { 497ec681f3Smrg fprintf(stderr, "Error: Test '%s' failed: Expected=true" 507ec681f3Smrg ", Actual=false\n", test); 517ec681f3Smrg error = true; 527ec681f3Smrg } 537ec681f3Smrg} 547ec681f3Smrgstatic void 557ec681f3Smrgexpect_false(bool result, const char *test) 567ec681f3Smrg{ 577ec681f3Smrg if (result) { 587ec681f3Smrg fprintf(stderr, "Error: Test '%s' failed: Expected=false" 597ec681f3Smrg ", Actual=true\n", test); 607ec681f3Smrg error = true; 617ec681f3Smrg } 627ec681f3Smrg} 637ec681f3Smrg 647ec681f3Smrgstatic void 657ec681f3Smrgexpect_equal(uint64_t actual, uint64_t expected, const char *test) 667ec681f3Smrg{ 677ec681f3Smrg if (actual != expected) { 687ec681f3Smrg fprintf(stderr, "Error: Test '%s' failed: Expected=%" PRIu64 697ec681f3Smrg ", Actual=%" PRIu64 "\n", 707ec681f3Smrg test, expected, actual); 717ec681f3Smrg error = true; 727ec681f3Smrg } 737ec681f3Smrg} 747ec681f3Smrg 757ec681f3Smrgstatic void 767ec681f3Smrgexpect_null(void *ptr, const char *test) 777ec681f3Smrg{ 787ec681f3Smrg if (ptr != NULL) { 797ec681f3Smrg fprintf(stderr, "Error: Test '%s' failed: Result=%p, but expected NULL.\n", 807ec681f3Smrg test, ptr); 817ec681f3Smrg error = true; 827ec681f3Smrg } 837ec681f3Smrg} 847ec681f3Smrg 857ec681f3Smrgstatic void 867ec681f3Smrgexpect_non_null(void *ptr, const char *test) 877ec681f3Smrg{ 887ec681f3Smrg if (ptr == NULL) { 897ec681f3Smrg fprintf(stderr, "Error: Test '%s' failed: Result=NULL, but expected something else.\n", 907ec681f3Smrg test); 917ec681f3Smrg error = true; 927ec681f3Smrg } 937ec681f3Smrg} 947ec681f3Smrg 957ec681f3Smrgstatic void 967ec681f3Smrgexpect_equal_str(const char *actual, const char *expected, const char *test) 977ec681f3Smrg{ 987ec681f3Smrg if (strcmp(actual, expected)) { 997ec681f3Smrg fprintf(stderr, "Error: Test '%s' failed:\n\t" 1007ec681f3Smrg "Expected=\"%s\", Actual=\"%s\"\n", 1017ec681f3Smrg test, expected, actual); 1027ec681f3Smrg error = true; 1037ec681f3Smrg } 1047ec681f3Smrg} 1057ec681f3Smrg 1067ec681f3Smrg/* Callback for nftw used in rmrf_local below. 1077ec681f3Smrg */ 1087ec681f3Smrgstatic int 1097ec681f3Smrgremove_entry(const char *path, 1107ec681f3Smrg const struct stat *sb, 1117ec681f3Smrg int typeflag, 1127ec681f3Smrg struct FTW *ftwbuf) 1137ec681f3Smrg{ 1147ec681f3Smrg int err = remove(path); 1157ec681f3Smrg 1167ec681f3Smrg if (err) 1177ec681f3Smrg fprintf(stderr, "Error removing %s: %s\n", path, strerror(errno)); 1187ec681f3Smrg 1197ec681f3Smrg return err; 1207ec681f3Smrg} 1217ec681f3Smrg 1227ec681f3Smrg/* Recursively remove a directory. 1237ec681f3Smrg * 1247ec681f3Smrg * This is equivalent to "rm -rf <dir>" with one bit of protection 1257ec681f3Smrg * that the directory name must begin with "." to ensure we don't 1267ec681f3Smrg * wander around deleting more than intended. 1277ec681f3Smrg * 1287ec681f3Smrg * Returns 0 on success, -1 on any error. 1297ec681f3Smrg */ 1307ec681f3Smrgstatic int 1317ec681f3Smrgrmrf_local(const char *path) 1327ec681f3Smrg{ 1337ec681f3Smrg if (path == NULL || *path == '\0' || *path != '.') 1347ec681f3Smrg return -1; 1357ec681f3Smrg 1367ec681f3Smrg return nftw(path, remove_entry, 64, FTW_DEPTH | FTW_PHYS); 1377ec681f3Smrg} 1387ec681f3Smrg 1397ec681f3Smrgstatic void 1407ec681f3Smrgcheck_directories_created(const char *cache_dir) 1417ec681f3Smrg{ 1427ec681f3Smrg bool sub_dirs_created = false; 1437ec681f3Smrg 1447ec681f3Smrg char buf[PATH_MAX]; 1457ec681f3Smrg if (getcwd(buf, PATH_MAX)) { 1467ec681f3Smrg char *full_path = NULL; 1477ec681f3Smrg if (asprintf(&full_path, "%s%s", buf, ++cache_dir) != -1 ) { 1487ec681f3Smrg struct stat sb; 1497ec681f3Smrg if (stat(full_path, &sb) != -1 && S_ISDIR(sb.st_mode)) 1507ec681f3Smrg sub_dirs_created = true; 1517ec681f3Smrg 1527ec681f3Smrg free(full_path); 1537ec681f3Smrg } 1547ec681f3Smrg } 1557ec681f3Smrg 1567ec681f3Smrg expect_true(sub_dirs_created, "create sub dirs"); 1577ec681f3Smrg} 1587ec681f3Smrg 1597ec681f3Smrgstatic bool 1607ec681f3Smrgdoes_cache_contain(struct disk_cache *cache, const cache_key key) 1617ec681f3Smrg{ 1627ec681f3Smrg void *result; 1637ec681f3Smrg 1647ec681f3Smrg result = disk_cache_get(cache, key, NULL); 1657ec681f3Smrg 1667ec681f3Smrg if (result) { 1677ec681f3Smrg free(result); 1687ec681f3Smrg return true; 1697ec681f3Smrg } 1707ec681f3Smrg 1717ec681f3Smrg return false; 1727ec681f3Smrg} 1737ec681f3Smrg 1747ec681f3Smrgstatic bool 1757ec681f3Smrgcache_exists(struct disk_cache *cache) 1767ec681f3Smrg{ 1777ec681f3Smrg uint8_t key[20]; 1787ec681f3Smrg char data[] = "some test data"; 1797ec681f3Smrg 1807ec681f3Smrg if (!cache) 1817ec681f3Smrg return NULL; 1827ec681f3Smrg 1837ec681f3Smrg disk_cache_compute_key(cache, data, sizeof(data), key); 1847ec681f3Smrg disk_cache_put(cache, key, data, sizeof(data), NULL); 1857ec681f3Smrg disk_cache_wait_for_idle(cache); 1867ec681f3Smrg void *result = disk_cache_get(cache, key, NULL); 1877ec681f3Smrg 1887ec681f3Smrg free(result); 1897ec681f3Smrg return result != NULL; 1907ec681f3Smrg} 1917ec681f3Smrg 1927ec681f3Smrg#define CACHE_TEST_TMP "./cache-test-tmp" 1937ec681f3Smrg 1947ec681f3Smrgstatic void 1957ec681f3Smrgtest_disk_cache_create(const char *cache_dir_name) 1967ec681f3Smrg{ 1977ec681f3Smrg struct disk_cache *cache; 1987ec681f3Smrg int err; 1997ec681f3Smrg 2007ec681f3Smrg /* Before doing anything else, ensure that with 2017ec681f3Smrg * MESA_GLSL_CACHE_DISABLE set to true, that disk_cache_create returns NULL. 2027ec681f3Smrg */ 2037ec681f3Smrg setenv("MESA_GLSL_CACHE_DISABLE", "true", 1); 2047ec681f3Smrg cache = disk_cache_create("test", "make_check", 0); 2057ec681f3Smrg expect_null(cache, "disk_cache_create with MESA_GLSL_CACHE_DISABLE set"); 2067ec681f3Smrg 2077ec681f3Smrg unsetenv("MESA_GLSL_CACHE_DISABLE"); 2087ec681f3Smrg 2097ec681f3Smrg#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT 2107ec681f3Smrg /* With SHADER_CACHE_DISABLE_BY_DEFAULT, ensure that with 2117ec681f3Smrg * MESA_GLSL_CACHE_DISABLE set to nothing, disk_cache_create returns NULL. 2127ec681f3Smrg */ 2137ec681f3Smrg unsetenv("MESA_GLSL_CACHE_DISABLE"); 2147ec681f3Smrg cache = disk_cache_create("test", "make_check", 0); 2157ec681f3Smrg expect_null(cache, "disk_cache_create with MESA_GLSL_CACHE_DISABLE unset " 2167ec681f3Smrg " and SHADER_CACHE_DISABLE_BY_DEFAULT build option"); 2177ec681f3Smrg 2187ec681f3Smrg /* For remaining tests, ensure that the cache is enabled. */ 2197ec681f3Smrg setenv("MESA_GLSL_CACHE_DISABLE", "false", 1); 2207ec681f3Smrg#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */ 2217ec681f3Smrg 2227ec681f3Smrg /* For the first real disk_cache_create() clear these environment 2237ec681f3Smrg * variables to test creation of cache in home directory. 2247ec681f3Smrg */ 2257ec681f3Smrg unsetenv("MESA_GLSL_CACHE_DIR"); 2267ec681f3Smrg unsetenv("XDG_CACHE_HOME"); 2277ec681f3Smrg 2287ec681f3Smrg cache = disk_cache_create("test", "make_check", 0); 2297ec681f3Smrg expect_non_null(cache, "disk_cache_create with no environment variables"); 2307ec681f3Smrg 2317ec681f3Smrg disk_cache_destroy(cache); 2327ec681f3Smrg 2337ec681f3Smrg#ifdef ANDROID 2347ec681f3Smrg /* Android doesn't try writing to disk (just calls the cache callbacks), so 2357ec681f3Smrg * the directory tests below don't apply. 2367ec681f3Smrg */ 2377ec681f3Smrg exit(error ? 1 : 0); 2387ec681f3Smrg#endif 2397ec681f3Smrg 2407ec681f3Smrg /* Test with XDG_CACHE_HOME set */ 2417ec681f3Smrg setenv("XDG_CACHE_HOME", CACHE_TEST_TMP "/xdg-cache-home", 1); 2427ec681f3Smrg cache = disk_cache_create("test", "make_check", 0); 2437ec681f3Smrg expect_false(cache_exists(cache), "disk_cache_create with XDG_CACHE_HOME set " 2447ec681f3Smrg "with a non-existing parent directory"); 2457ec681f3Smrg 2467ec681f3Smrg err = mkdir(CACHE_TEST_TMP, 0755); 2477ec681f3Smrg if (err != 0) { 2487ec681f3Smrg fprintf(stderr, "Error creating %s: %s\n", CACHE_TEST_TMP, strerror(errno)); 2497ec681f3Smrg error = true; 2507ec681f3Smrg return; 2517ec681f3Smrg } 2527ec681f3Smrg disk_cache_destroy(cache); 2537ec681f3Smrg 2547ec681f3Smrg cache = disk_cache_create("test", "make_check", 0); 2557ec681f3Smrg expect_true(cache_exists(cache), "disk_cache_create with XDG_CACHE_HOME " 2567ec681f3Smrg "set"); 2577ec681f3Smrg 2587ec681f3Smrg char *path; 2597ec681f3Smrg asprintf(&path, "%s%s", CACHE_TEST_TMP "/xdg-cache-home/", cache_dir_name); 2607ec681f3Smrg check_directories_created(path); 2617ec681f3Smrg free(path); 2627ec681f3Smrg 2637ec681f3Smrg disk_cache_destroy(cache); 2647ec681f3Smrg 2657ec681f3Smrg /* Test with MESA_GLSL_CACHE_DIR set */ 2667ec681f3Smrg err = rmrf_local(CACHE_TEST_TMP); 2677ec681f3Smrg expect_equal(err, 0, "Removing " CACHE_TEST_TMP); 2687ec681f3Smrg 2697ec681f3Smrg setenv("MESA_GLSL_CACHE_DIR", CACHE_TEST_TMP "/mesa-glsl-cache-dir", 1); 2707ec681f3Smrg cache = disk_cache_create("test", "make_check", 0); 2717ec681f3Smrg expect_false(cache_exists(cache), "disk_cache_create with MESA_GLSL_CACHE_DIR" 2727ec681f3Smrg " set with a non-existing parent directory"); 2737ec681f3Smrg 2747ec681f3Smrg err = mkdir(CACHE_TEST_TMP, 0755); 2757ec681f3Smrg if (err != 0) { 2767ec681f3Smrg fprintf(stderr, "Error creating %s: %s\n", CACHE_TEST_TMP, strerror(errno)); 2777ec681f3Smrg error = true; 2787ec681f3Smrg return; 2797ec681f3Smrg } 2807ec681f3Smrg disk_cache_destroy(cache); 2817ec681f3Smrg 2827ec681f3Smrg cache = disk_cache_create("test", "make_check", 0); 2837ec681f3Smrg expect_true(cache_exists(cache), "disk_cache_create with " 2847ec681f3Smrg "MESA_GLSL_CACHE_DIR set"); 2857ec681f3Smrg 2867ec681f3Smrg asprintf(&path, "%s%s", CACHE_TEST_TMP "/mesa-glsl-cache-dir/", 2877ec681f3Smrg cache_dir_name); 2887ec681f3Smrg check_directories_created(path); 2897ec681f3Smrg free(path); 2907ec681f3Smrg 2917ec681f3Smrg disk_cache_destroy(cache); 2927ec681f3Smrg} 2937ec681f3Smrg 2947ec681f3Smrgstatic void 2957ec681f3Smrgtest_put_and_get(bool test_cache_size_limit) 2967ec681f3Smrg{ 2977ec681f3Smrg struct disk_cache *cache; 2987ec681f3Smrg char blob[] = "This is a blob of thirty-seven bytes"; 2997ec681f3Smrg uint8_t blob_key[20]; 3007ec681f3Smrg char string[] = "While this string has thirty-four"; 3017ec681f3Smrg uint8_t string_key[20]; 3027ec681f3Smrg char *result; 3037ec681f3Smrg size_t size; 3047ec681f3Smrg uint8_t *one_KB, *one_MB; 3057ec681f3Smrg uint8_t one_KB_key[20], one_MB_key[20]; 3067ec681f3Smrg int count; 3077ec681f3Smrg 3087ec681f3Smrg#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT 3097ec681f3Smrg setenv("MESA_GLSL_CACHE_DISABLE", "false", 1); 3107ec681f3Smrg#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */ 3117ec681f3Smrg 3127ec681f3Smrg cache = disk_cache_create("test", "make_check", 0); 3137ec681f3Smrg 3147ec681f3Smrg disk_cache_compute_key(cache, blob, sizeof(blob), blob_key); 3157ec681f3Smrg 3167ec681f3Smrg /* Ensure that disk_cache_get returns nothing before anything is added. */ 3177ec681f3Smrg result = disk_cache_get(cache, blob_key, &size); 3187ec681f3Smrg expect_null(result, "disk_cache_get with non-existent item (pointer)"); 3197ec681f3Smrg expect_equal(size, 0, "disk_cache_get with non-existent item (size)"); 3207ec681f3Smrg 3217ec681f3Smrg /* Simple test of put and get. */ 3227ec681f3Smrg disk_cache_put(cache, blob_key, blob, sizeof(blob), NULL); 3237ec681f3Smrg 3247ec681f3Smrg /* disk_cache_put() hands things off to a thread so wait for it. */ 3257ec681f3Smrg disk_cache_wait_for_idle(cache); 3267ec681f3Smrg 3277ec681f3Smrg result = disk_cache_get(cache, blob_key, &size); 3287ec681f3Smrg expect_equal_str(blob, result, "disk_cache_get of existing item (pointer)"); 3297ec681f3Smrg expect_equal(size, sizeof(blob), "disk_cache_get of existing item (size)"); 3307ec681f3Smrg 3317ec681f3Smrg free(result); 3327ec681f3Smrg 3337ec681f3Smrg /* Test put and get of a second item. */ 3347ec681f3Smrg disk_cache_compute_key(cache, string, sizeof(string), string_key); 3357ec681f3Smrg disk_cache_put(cache, string_key, string, sizeof(string), NULL); 3367ec681f3Smrg 3377ec681f3Smrg /* disk_cache_put() hands things off to a thread so wait for it. */ 3387ec681f3Smrg disk_cache_wait_for_idle(cache); 3397ec681f3Smrg 3407ec681f3Smrg result = disk_cache_get(cache, string_key, &size); 3417ec681f3Smrg expect_equal_str(result, string, "2nd disk_cache_get of existing item (pointer)"); 3427ec681f3Smrg expect_equal(size, sizeof(string), "2nd disk_cache_get of existing item (size)"); 3437ec681f3Smrg 3447ec681f3Smrg free(result); 3457ec681f3Smrg 3467ec681f3Smrg /* Set the cache size to 1KB and add a 1KB item to force an eviction. */ 3477ec681f3Smrg disk_cache_destroy(cache); 3487ec681f3Smrg 3497ec681f3Smrg if (!test_cache_size_limit) 3507ec681f3Smrg return; 3517ec681f3Smrg 3527ec681f3Smrg setenv("MESA_GLSL_CACHE_MAX_SIZE", "1K", 1); 3537ec681f3Smrg cache = disk_cache_create("test", "make_check", 0); 3547ec681f3Smrg 3557ec681f3Smrg one_KB = calloc(1, 1024); 3567ec681f3Smrg 3577ec681f3Smrg /* Obviously the SHA-1 hash of 1024 zero bytes isn't particularly 3587ec681f3Smrg * interesting. But we do have want to take some special care with 3597ec681f3Smrg * the hash we use here. The issue is that in this artificial case, 3607ec681f3Smrg * (with only three files in the cache), the probability is good 3617ec681f3Smrg * that each of the three files will end up in their own 3627ec681f3Smrg * directory. Then, if the directory containing the .tmp file for 3637ec681f3Smrg * the new item being added for disk_cache_put() is the chosen victim 3647ec681f3Smrg * directory for eviction, then no suitable file will be found and 3657ec681f3Smrg * nothing will be evicted. 3667ec681f3Smrg * 3677ec681f3Smrg * That's actually expected given how the eviction code is 3687ec681f3Smrg * implemented, (which expects to only evict once things are more 3697ec681f3Smrg * interestingly full than that). 3707ec681f3Smrg * 3717ec681f3Smrg * For this test, we force this signature to land in the same 3727ec681f3Smrg * directory as the original blob first written to the cache. 3737ec681f3Smrg */ 3747ec681f3Smrg disk_cache_compute_key(cache, one_KB, 1024, one_KB_key); 3757ec681f3Smrg one_KB_key[0] = blob_key[0]; 3767ec681f3Smrg 3777ec681f3Smrg disk_cache_put(cache, one_KB_key, one_KB, 1024, NULL); 3787ec681f3Smrg 3797ec681f3Smrg free(one_KB); 3807ec681f3Smrg 3817ec681f3Smrg /* disk_cache_put() hands things off to a thread so wait for it. */ 3827ec681f3Smrg disk_cache_wait_for_idle(cache); 3837ec681f3Smrg 3847ec681f3Smrg result = disk_cache_get(cache, one_KB_key, &size); 3857ec681f3Smrg expect_non_null(result, "3rd disk_cache_get of existing item (pointer)"); 3867ec681f3Smrg expect_equal(size, 1024, "3rd disk_cache_get of existing item (size)"); 3877ec681f3Smrg 3887ec681f3Smrg free(result); 3897ec681f3Smrg 3907ec681f3Smrg /* Ensure eviction happened by checking that both of the previous 3917ec681f3Smrg * cache itesm were evicted. 3927ec681f3Smrg */ 3937ec681f3Smrg bool contains_1KB_file = false; 3947ec681f3Smrg count = 0; 3957ec681f3Smrg if (does_cache_contain(cache, blob_key)) 3967ec681f3Smrg count++; 3977ec681f3Smrg 3987ec681f3Smrg if (does_cache_contain(cache, string_key)) 3997ec681f3Smrg count++; 4007ec681f3Smrg 4017ec681f3Smrg if (does_cache_contain(cache, one_KB_key)) { 4027ec681f3Smrg count++; 4037ec681f3Smrg contains_1KB_file = true; 4047ec681f3Smrg } 4057ec681f3Smrg 4067ec681f3Smrg expect_true(contains_1KB_file, 4077ec681f3Smrg "disk_cache_put eviction last file == MAX_SIZE (1KB)"); 4087ec681f3Smrg expect_equal(count, 1, "disk_cache_put eviction with MAX_SIZE=1K"); 4097ec681f3Smrg 4107ec681f3Smrg /* Now increase the size to 1M, add back both items, and ensure all 4117ec681f3Smrg * three that have been added are available via disk_cache_get. 4127ec681f3Smrg */ 4137ec681f3Smrg disk_cache_destroy(cache); 4147ec681f3Smrg 4157ec681f3Smrg setenv("MESA_GLSL_CACHE_MAX_SIZE", "1M", 1); 4167ec681f3Smrg cache = disk_cache_create("test", "make_check", 0); 4177ec681f3Smrg 4187ec681f3Smrg disk_cache_put(cache, blob_key, blob, sizeof(blob), NULL); 4197ec681f3Smrg disk_cache_put(cache, string_key, string, sizeof(string), NULL); 4207ec681f3Smrg 4217ec681f3Smrg /* disk_cache_put() hands things off to a thread so wait for it. */ 4227ec681f3Smrg disk_cache_wait_for_idle(cache); 4237ec681f3Smrg 4247ec681f3Smrg count = 0; 4257ec681f3Smrg if (does_cache_contain(cache, blob_key)) 4267ec681f3Smrg count++; 4277ec681f3Smrg 4287ec681f3Smrg if (does_cache_contain(cache, string_key)) 4297ec681f3Smrg count++; 4307ec681f3Smrg 4317ec681f3Smrg if (does_cache_contain(cache, one_KB_key)) 4327ec681f3Smrg count++; 4337ec681f3Smrg 4347ec681f3Smrg expect_equal(count, 3, "no eviction before overflow with MAX_SIZE=1M"); 4357ec681f3Smrg 4367ec681f3Smrg /* Finally, check eviction again after adding an object of size 1M. */ 4377ec681f3Smrg one_MB = calloc(1024, 1024); 4387ec681f3Smrg 4397ec681f3Smrg disk_cache_compute_key(cache, one_MB, 1024 * 1024, one_MB_key); 4407ec681f3Smrg one_MB_key[0] = blob_key[0]; 4417ec681f3Smrg 4427ec681f3Smrg disk_cache_put(cache, one_MB_key, one_MB, 1024 * 1024, NULL); 4437ec681f3Smrg 4447ec681f3Smrg free(one_MB); 4457ec681f3Smrg 4467ec681f3Smrg /* disk_cache_put() hands things off to a thread so wait for it. */ 4477ec681f3Smrg disk_cache_wait_for_idle(cache); 4487ec681f3Smrg 4497ec681f3Smrg bool contains_1MB_file = false; 4507ec681f3Smrg count = 0; 4517ec681f3Smrg if (does_cache_contain(cache, blob_key)) 4527ec681f3Smrg count++; 4537ec681f3Smrg 4547ec681f3Smrg if (does_cache_contain(cache, string_key)) 4557ec681f3Smrg count++; 4567ec681f3Smrg 4577ec681f3Smrg if (does_cache_contain(cache, one_KB_key)) 4587ec681f3Smrg count++; 4597ec681f3Smrg 4607ec681f3Smrg if (does_cache_contain(cache, one_MB_key)) { 4617ec681f3Smrg count++; 4627ec681f3Smrg contains_1MB_file = true; 4637ec681f3Smrg } 4647ec681f3Smrg 4657ec681f3Smrg expect_true(contains_1MB_file, 4667ec681f3Smrg "disk_cache_put eviction last file == MAX_SIZE (1MB)"); 4677ec681f3Smrg expect_equal(count, 1, "eviction after overflow with MAX_SIZE=1M"); 4687ec681f3Smrg 4697ec681f3Smrg disk_cache_destroy(cache); 4707ec681f3Smrg} 4717ec681f3Smrg 4727ec681f3Smrgstatic void 4737ec681f3Smrgtest_put_key_and_get_key(void) 4747ec681f3Smrg{ 4757ec681f3Smrg struct disk_cache *cache; 4767ec681f3Smrg bool result; 4777ec681f3Smrg 4787ec681f3Smrg uint8_t key_a[20] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 4797ec681f3Smrg 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; 4807ec681f3Smrg uint8_t key_b[20] = { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 4817ec681f3Smrg 30, 33, 32, 33, 34, 35, 36, 37, 38, 39}; 4827ec681f3Smrg uint8_t key_a_collide[20] = 4837ec681f3Smrg { 0, 1, 42, 43, 44, 45, 46, 47, 48, 49, 4847ec681f3Smrg 50, 55, 52, 53, 54, 55, 56, 57, 58, 59}; 4857ec681f3Smrg 4867ec681f3Smrg#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT 4877ec681f3Smrg setenv("MESA_GLSL_CACHE_DISABLE", "false", 1); 4887ec681f3Smrg#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */ 4897ec681f3Smrg 4907ec681f3Smrg cache = disk_cache_create("test", "make_check", 0); 4917ec681f3Smrg 4927ec681f3Smrg /* First test that disk_cache_has_key returns false before disk_cache_put_key */ 4937ec681f3Smrg result = disk_cache_has_key(cache, key_a); 4947ec681f3Smrg expect_equal(result, 0, "disk_cache_has_key before key added"); 4957ec681f3Smrg 4967ec681f3Smrg /* Then a couple of tests of disk_cache_put_key followed by disk_cache_has_key */ 4977ec681f3Smrg disk_cache_put_key(cache, key_a); 4987ec681f3Smrg result = disk_cache_has_key(cache, key_a); 4997ec681f3Smrg expect_equal(result, 1, "disk_cache_has_key after key added"); 5007ec681f3Smrg 5017ec681f3Smrg disk_cache_put_key(cache, key_b); 5027ec681f3Smrg result = disk_cache_has_key(cache, key_b); 5037ec681f3Smrg expect_equal(result, 1, "2nd disk_cache_has_key after key added"); 5047ec681f3Smrg 5057ec681f3Smrg /* Test that a key with the same two bytes as an existing key 5067ec681f3Smrg * forces an eviction. 5077ec681f3Smrg */ 5087ec681f3Smrg disk_cache_put_key(cache, key_a_collide); 5097ec681f3Smrg result = disk_cache_has_key(cache, key_a_collide); 5107ec681f3Smrg expect_equal(result, 1, "put_key of a colliding key lands in the cache"); 5117ec681f3Smrg 5127ec681f3Smrg result = disk_cache_has_key(cache, key_a); 5137ec681f3Smrg expect_equal(result, 0, "put_key of a colliding key evicts from the cache"); 5147ec681f3Smrg 5157ec681f3Smrg /* And finally test that we can re-add the original key to re-evict 5167ec681f3Smrg * the colliding key. 5177ec681f3Smrg */ 5187ec681f3Smrg disk_cache_put_key(cache, key_a); 5197ec681f3Smrg result = disk_cache_has_key(cache, key_a); 5207ec681f3Smrg expect_equal(result, 1, "put_key of original key lands again"); 5217ec681f3Smrg 5227ec681f3Smrg result = disk_cache_has_key(cache, key_a_collide); 5237ec681f3Smrg expect_equal(result, 0, "put_key of orginal key evicts the colliding key"); 5247ec681f3Smrg 5257ec681f3Smrg disk_cache_destroy(cache); 5267ec681f3Smrg} 5277ec681f3Smrg 5287ec681f3Smrg/* To make sure we are not just using the inmemory cache index for the single 5297ec681f3Smrg * file cache we test adding and retriving cache items between two different 5307ec681f3Smrg * cache instances. 5317ec681f3Smrg */ 5327ec681f3Smrgstatic void 5337ec681f3Smrgtest_put_and_get_between_instances() 5347ec681f3Smrg{ 5357ec681f3Smrg char blob[] = "This is a blob of thirty-seven bytes"; 5367ec681f3Smrg uint8_t blob_key[20]; 5377ec681f3Smrg char string[] = "While this string has thirty-four"; 5387ec681f3Smrg uint8_t string_key[20]; 5397ec681f3Smrg char *result; 5407ec681f3Smrg size_t size; 5417ec681f3Smrg 5427ec681f3Smrg#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT 5437ec681f3Smrg setenv("MESA_GLSL_CACHE_DISABLE", "false", 1); 5447ec681f3Smrg#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */ 5457ec681f3Smrg 5467ec681f3Smrg struct disk_cache *cache1 = disk_cache_create("test_between_instances", 5477ec681f3Smrg "make_check", 0); 5487ec681f3Smrg struct disk_cache *cache2 = disk_cache_create("test_between_instances", 5497ec681f3Smrg "make_check", 0); 5507ec681f3Smrg 5517ec681f3Smrg disk_cache_compute_key(cache1, blob, sizeof(blob), blob_key); 5527ec681f3Smrg 5537ec681f3Smrg /* Ensure that disk_cache_get returns nothing before anything is added. */ 5547ec681f3Smrg result = disk_cache_get(cache1, blob_key, &size); 5557ec681f3Smrg expect_null(result, "disk_cache_get(cache1) with non-existent item (pointer)"); 5567ec681f3Smrg expect_equal(size, 0, "disk_cache_get(cach1) with non-existent item (size)"); 5577ec681f3Smrg 5587ec681f3Smrg result = disk_cache_get(cache2, blob_key, &size); 5597ec681f3Smrg expect_null(result, "disk_cache_get(cache2) with non-existent item (pointer)"); 5607ec681f3Smrg expect_equal(size, 0, "disk_cache_get(cache2) with non-existent item (size)"); 5617ec681f3Smrg 5627ec681f3Smrg /* Simple test of put and get. */ 5637ec681f3Smrg disk_cache_put(cache1, blob_key, blob, sizeof(blob), NULL); 5647ec681f3Smrg 5657ec681f3Smrg /* disk_cache_put() hands things off to a thread so wait for it. */ 5667ec681f3Smrg disk_cache_wait_for_idle(cache1); 5677ec681f3Smrg 5687ec681f3Smrg result = disk_cache_get(cache2, blob_key, &size); 5697ec681f3Smrg expect_equal_str(blob, result, "disk_cache_get(cache2) of existing item (pointer)"); 5707ec681f3Smrg expect_equal(size, sizeof(blob), "disk_cache_get of(cache2) existing item (size)"); 5717ec681f3Smrg 5727ec681f3Smrg free(result); 5737ec681f3Smrg 5747ec681f3Smrg /* Test put and get of a second item, via the opposite instances */ 5757ec681f3Smrg disk_cache_compute_key(cache2, string, sizeof(string), string_key); 5767ec681f3Smrg disk_cache_put(cache2, string_key, string, sizeof(string), NULL); 5777ec681f3Smrg 5787ec681f3Smrg /* disk_cache_put() hands things off to a thread so wait for it. */ 5797ec681f3Smrg disk_cache_wait_for_idle(cache2); 5807ec681f3Smrg 5817ec681f3Smrg result = disk_cache_get(cache1, string_key, &size); 5827ec681f3Smrg expect_equal_str(result, string, "2nd disk_cache_get(cache1) of existing item (pointer)"); 5837ec681f3Smrg expect_equal(size, sizeof(string), "2nd disk_cache_get(cache1) of existing item (size)"); 5847ec681f3Smrg 5857ec681f3Smrg free(result); 5867ec681f3Smrg 5877ec681f3Smrg disk_cache_destroy(cache1); 5887ec681f3Smrg disk_cache_destroy(cache2); 5897ec681f3Smrg} 5907ec681f3Smrg#endif /* ENABLE_SHADER_CACHE */ 5917ec681f3Smrg 5927ec681f3Smrgstatic void 5937ec681f3Smrgtest_multi_file_cache(void) 5947ec681f3Smrg{ 5957ec681f3Smrg int err; 5967ec681f3Smrg 5977ec681f3Smrg printf("Test multi file disk cache - Start\n"); 5987ec681f3Smrg 5997ec681f3Smrg test_disk_cache_create(CACHE_DIR_NAME); 6007ec681f3Smrg 6017ec681f3Smrg test_put_and_get(true); 6027ec681f3Smrg 6037ec681f3Smrg test_put_key_and_get_key(); 6047ec681f3Smrg 6057ec681f3Smrg printf("Test multi file disk cache - End\n"); 6067ec681f3Smrg 6077ec681f3Smrg err = rmrf_local(CACHE_TEST_TMP); 6087ec681f3Smrg expect_equal(err, 0, "Removing " CACHE_TEST_TMP " again"); 6097ec681f3Smrg} 6107ec681f3Smrg 6117ec681f3Smrgstatic void 6127ec681f3Smrgtest_single_file_cache(void) 6137ec681f3Smrg{ 6147ec681f3Smrg int err; 6157ec681f3Smrg 6167ec681f3Smrg printf("Test single file disk cache - Start\n"); 6177ec681f3Smrg 6187ec681f3Smrg setenv("MESA_DISK_CACHE_SINGLE_FILE", "true", 1); 6197ec681f3Smrg 6207ec681f3Smrg test_disk_cache_create(CACHE_DIR_NAME_SF); 6217ec681f3Smrg 6227ec681f3Smrg /* We skip testing cache size limit as the single file cache currently 6237ec681f3Smrg * doesn't have any functionality to enforce cache size limits. 6247ec681f3Smrg */ 6257ec681f3Smrg test_put_and_get(false); 6267ec681f3Smrg 6277ec681f3Smrg test_put_key_and_get_key(); 6287ec681f3Smrg 6297ec681f3Smrg test_put_and_get_between_instances(); 6307ec681f3Smrg 6317ec681f3Smrg setenv("MESA_DISK_CACHE_SINGLE_FILE", "false", 1); 6327ec681f3Smrg 6337ec681f3Smrg printf("Test single file disk cache - End\n"); 6347ec681f3Smrg 6357ec681f3Smrg err = rmrf_local(CACHE_TEST_TMP); 6367ec681f3Smrg expect_equal(err, 0, "Removing " CACHE_TEST_TMP " again"); 6377ec681f3Smrg} 6387ec681f3Smrg 6397ec681f3Smrgint 6407ec681f3Smrgmain(void) 6417ec681f3Smrg{ 6427ec681f3Smrg#ifdef ENABLE_SHADER_CACHE 6437ec681f3Smrg 6447ec681f3Smrg test_multi_file_cache(); 6457ec681f3Smrg 6467ec681f3Smrg test_single_file_cache(); 6477ec681f3Smrg 6487ec681f3Smrg#endif /* ENABLE_SHADER_CACHE */ 6497ec681f3Smrg 6507ec681f3Smrg return error ? 1 : 0; 6517ec681f3Smrg} 652