util/disk_cache: Support combined foz ro and non-foz rw caches
Mesa utilizes only one type of cache at a time. This patch enables support for combined reading from read-only Fossilize cache + non-foz read-write caches. From now on, a non-foz read-write caches will first try to retrieve data from a read-only foz cache if new MESA_DISK_CACHE_COMBINE_RW_WITH_RO_FOZ environment variable is set to true, otherwise the caching behaviour is unchanged. The new flag has no effect when MESA_DISK_CACHE_SINGLE_FILE=1, i.e. when the single-file foz cache is used. This change allows us to ship a prebuilt RO caches for a certain applications, while the rest of applications will benefit from the regular RW caching that supports cache-size limitation. This feature will be used by ChromeOS. Usage example #1: MESA_DISK_CACHE_DATABASE=0 MESA_DISK_CACHE_SINGLE_FILE=0 MESA_DISK_CACHE_COMBINE_RW_WITH_RO_FOZ=1 MESA_DISK_CACHE_READ_ONLY_FOZ_DBS=rocache1,rocache2 Usage example #2: MESA_DISK_CACHE_DATABASE=1 MESA_DISK_CACHE_SINGLE_FILE=0 MESA_DISK_CACHE_COMBINE_RW_WITH_RO_FOZ=1 MESA_DISK_CACHE_READ_ONLY_FOZ_DBS=rocache1,rocache2 Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18551>
This commit is contained in:

committed by
Marge Bot

parent
75dae4f8e3
commit
32fe60e8c4
@@ -278,6 +278,23 @@ disk_cache_create(const char *gpu_name, const char *driver_id,
|
||||
if (!cache)
|
||||
return NULL;
|
||||
|
||||
/* If MESA_DISK_CACHE_SINGLE_FILE is unset and MESA_DISK_CACHE_COMBINE_RW_WITH_RO_FOZ
|
||||
* is set, then enable additional Fossilize RO caches together with the RW
|
||||
* cache. At first we will check cache entry presence in the RO caches and
|
||||
* if entry isn't found there, then we'll fall back to the RW cache.
|
||||
*/
|
||||
if (cache_type != DISK_CACHE_SINGLE_FILE && !cache->path_init_failed &&
|
||||
debug_get_bool_option("MESA_DISK_CACHE_COMBINE_RW_WITH_RO_FOZ", false)) {
|
||||
|
||||
/* Create read-only cache used for sharing prebuilt shaders.
|
||||
* If cache entry will be found in this cache, then the main cache
|
||||
* will be bypassed.
|
||||
*/
|
||||
cache->foz_ro_cache = disk_cache_type_create(gpu_name, driver_id,
|
||||
driver_flags,
|
||||
DISK_CACHE_SINGLE_FILE);
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
@@ -294,6 +311,9 @@ disk_cache_destroy(struct disk_cache *cache)
|
||||
util_queue_finish(&cache->cache_queue);
|
||||
util_queue_destroy(&cache->cache_queue);
|
||||
|
||||
if (cache->foz_ro_cache)
|
||||
disk_cache_destroy(cache->foz_ro_cache);
|
||||
|
||||
if (cache->type == DISK_CACHE_SINGLE_FILE)
|
||||
foz_destroy(&cache->foz_db);
|
||||
|
||||
@@ -565,6 +585,8 @@ disk_cache_get(struct disk_cache *cache, const cache_key key, size_t *size)
|
||||
|
||||
if (cache->blob_get_cb) {
|
||||
buf = blob_get_compressed(cache, key, size);
|
||||
} else if (cache->foz_ro_cache) {
|
||||
buf = disk_cache_load_item_foz(cache->foz_ro_cache, key, size);
|
||||
} else if (cache->type == DISK_CACHE_SINGLE_FILE) {
|
||||
buf = disk_cache_load_item_foz(cache, key, size);
|
||||
} else if (cache->type == DISK_CACHE_DATABASE) {
|
||||
|
@@ -99,6 +99,9 @@ struct disk_cache {
|
||||
unsigned hits;
|
||||
unsigned misses;
|
||||
} stats;
|
||||
|
||||
/* Internal RO FOZ cache for combined use of RO and RW caches. */
|
||||
struct disk_cache *foz_ro_cache;
|
||||
};
|
||||
|
||||
struct cache_entry_file_data {
|
||||
|
@@ -40,6 +40,8 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util/u_debug.h"
|
||||
|
||||
#include "crc32.h"
|
||||
#include "hash_table.h"
|
||||
#include "mesa-sha1.h"
|
||||
@@ -270,28 +272,32 @@ foz_prepare(struct foz_db *foz_db, char *cache_path)
|
||||
{
|
||||
char *filename = NULL;
|
||||
char *idx_filename = NULL;
|
||||
if (!create_foz_db_filenames(cache_path, "foz_cache", &filename, &idx_filename))
|
||||
goto fail;
|
||||
|
||||
/* Open the default foz dbs for read/write. If the files didn't already exist
|
||||
* create them.
|
||||
*/
|
||||
foz_db->file[0] = fopen(filename, "a+b");
|
||||
foz_db->db_idx = fopen(idx_filename, "a+b");
|
||||
|
||||
free(filename);
|
||||
free(idx_filename);
|
||||
|
||||
if (!check_files_opened_successfully(foz_db->file[0], foz_db->db_idx))
|
||||
goto fail;
|
||||
|
||||
simple_mtx_init(&foz_db->mtx, mtx_plain);
|
||||
simple_mtx_init(&foz_db->flock_mtx, mtx_plain);
|
||||
foz_db->mem_ctx = ralloc_context(NULL);
|
||||
foz_db->index_db = _mesa_hash_table_u64_create(NULL);
|
||||
|
||||
if (!load_foz_dbs(foz_db, foz_db->db_idx, 0, false))
|
||||
goto fail;
|
||||
/* Open the default foz dbs for read/write. If the files didn't already exist
|
||||
* create them.
|
||||
*/
|
||||
if (debug_get_bool_option("MESA_DISK_CACHE_SINGLE_FILE", false)) {
|
||||
if (!create_foz_db_filenames(cache_path, "foz_cache",
|
||||
&filename, &idx_filename))
|
||||
goto fail;
|
||||
|
||||
foz_db->file[0] = fopen(filename, "a+b");
|
||||
foz_db->db_idx = fopen(idx_filename, "a+b");
|
||||
|
||||
free(filename);
|
||||
free(idx_filename);
|
||||
|
||||
if (!check_files_opened_successfully(foz_db->file[0], foz_db->db_idx))
|
||||
goto fail;
|
||||
|
||||
if (!load_foz_dbs(foz_db, foz_db->db_idx, 0, false))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
uint8_t file_idx = 1;
|
||||
char *foz_dbs = getenv("MESA_DISK_CACHE_READ_ONLY_FOZ_DBS");
|
||||
@@ -383,7 +389,7 @@ foz_read_entry(struct foz_db *foz_db, const uint8_t *cache_key_160bit,
|
||||
|
||||
struct foz_db_entry *entry =
|
||||
_mesa_hash_table_u64_search(foz_db->index_db, hash);
|
||||
if (!entry) {
|
||||
if (!entry && foz_db->db_idx) {
|
||||
update_foz_index(foz_db, foz_db->db_idx, 0);
|
||||
entry = _mesa_hash_table_u64_search(foz_db->index_db, hash);
|
||||
}
|
||||
@@ -444,7 +450,7 @@ foz_write_entry(struct foz_db *foz_db, const uint8_t *cache_key_160bit,
|
||||
{
|
||||
uint64_t hash = truncate_hash_to_64bits(cache_key_160bit);
|
||||
|
||||
if (!foz_db->alive)
|
||||
if (!foz_db->alive || !foz_db->file[0])
|
||||
return false;
|
||||
|
||||
/* The flock is per-fd, not per thread, we do it outside of the main mutex to avoid having to
|
||||
|
@@ -773,3 +773,169 @@ TEST_F(Cache, Database)
|
||||
EXPECT_EQ(err, 0) << "Removing " CACHE_TEST_TMP " again";
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(Cache, Combined)
|
||||
{
|
||||
const char *driver_id = "make_check";
|
||||
char blob[] = "This is a RO blob";
|
||||
uint8_t dummy_key[20] = { 0 };
|
||||
uint8_t blob_key[20];
|
||||
char foz_rw_idx_file[1024];
|
||||
char foz_ro_idx_file[1024];
|
||||
char foz_rw_file[1024];
|
||||
char foz_ro_file[1024];
|
||||
char *result;
|
||||
size_t size;
|
||||
|
||||
#ifndef ENABLE_SHADER_CACHE
|
||||
GTEST_SKIP() << "ENABLE_SHADER_CACHE not defined.";
|
||||
#else
|
||||
setenv("MESA_DISK_CACHE_SINGLE_FILE", "true", 1);
|
||||
setenv("MESA_DISK_CACHE_DATABASE", "false", 1);
|
||||
|
||||
#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT
|
||||
setenv("MESA_SHADER_CACHE_DISABLE", "false", 1);
|
||||
#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */
|
||||
|
||||
/* Enable Fossilize read-write cache. */
|
||||
setenv("MESA_DISK_CACHE_COMBINE_RW_WITH_RO_FOZ", "true", 1);
|
||||
|
||||
test_disk_cache_create(mem_ctx, CACHE_DIR_NAME_SF, driver_id);
|
||||
|
||||
/* Create Fossilize writable cache. */
|
||||
struct disk_cache *cache_sf_wr = disk_cache_create("combined_test",
|
||||
driver_id, 0);
|
||||
|
||||
disk_cache_compute_key(cache_sf_wr, blob, sizeof(blob), blob_key);
|
||||
|
||||
/* Ensure that disk_cache_get returns nothing before anything is added. */
|
||||
result = (char *) disk_cache_get(cache_sf_wr, blob_key, &size);
|
||||
EXPECT_EQ(result, nullptr) << "disk_cache_get with non-existent item (pointer)";
|
||||
EXPECT_EQ(size, 0) << "disk_cache_get with non-existent item (size)";
|
||||
|
||||
/* Put blob entry to the cache. */
|
||||
disk_cache_put(cache_sf_wr, blob_key, blob, sizeof(blob), NULL);
|
||||
disk_cache_wait_for_idle(cache_sf_wr);
|
||||
|
||||
result = (char *) disk_cache_get(cache_sf_wr, blob_key, &size);
|
||||
EXPECT_STREQ(blob, result) << "disk_cache_get of existing item (pointer)";
|
||||
EXPECT_EQ(size, sizeof(blob)) << "disk_cache_get of existing item (size)";
|
||||
free(result);
|
||||
|
||||
/* Rename file foz_cache.foz -> ro_cache.foz */
|
||||
sprintf(foz_rw_file, "%s/foz_cache.foz", cache_sf_wr->path);
|
||||
sprintf(foz_ro_file, "%s/ro_cache.foz", cache_sf_wr->path);
|
||||
EXPECT_EQ(rename(foz_rw_file, foz_ro_file), 0) << "foz_cache.foz renaming failed";
|
||||
|
||||
/* Rename file foz_cache_idx.foz -> ro_cache_idx.foz */
|
||||
sprintf(foz_rw_idx_file, "%s/foz_cache_idx.foz", cache_sf_wr->path);
|
||||
sprintf(foz_ro_idx_file, "%s/ro_cache_idx.foz", cache_sf_wr->path);
|
||||
EXPECT_EQ(rename(foz_rw_idx_file, foz_ro_idx_file), 0) << "foz_cache_idx.foz renaming failed";
|
||||
|
||||
disk_cache_destroy(cache_sf_wr);
|
||||
|
||||
/* Disable Fossilize read-write cache. */
|
||||
setenv("MESA_DISK_CACHE_COMBINE_RW_WITH_RO_FOZ", "false", 1);
|
||||
|
||||
/* Set up Fossilize read-only cache. */
|
||||
setenv("MESA_DISK_CACHE_COMBINE_RW_WITH_RO_FOZ", "true", 1);
|
||||
setenv("MESA_DISK_CACHE_READ_ONLY_FOZ_DBS", "ro_cache", 1);
|
||||
|
||||
/* Create FOZ cache that fetches the RO cache. Note that this produces
|
||||
* empty RW cache files. */
|
||||
struct disk_cache *cache_sf_ro = disk_cache_create("combined_test",
|
||||
driver_id, 0);
|
||||
|
||||
/* Blob entry must present because it shall be retrieved from the
|
||||
* ro_cache.foz */
|
||||
result = (char *) disk_cache_get(cache_sf_ro, blob_key, &size);
|
||||
EXPECT_STREQ(blob, result) << "disk_cache_get of existing item (pointer)";
|
||||
EXPECT_EQ(size, sizeof(blob)) << "disk_cache_get of existing item (size)";
|
||||
free(result);
|
||||
|
||||
disk_cache_destroy(cache_sf_ro);
|
||||
|
||||
/* Remove empty FOZ RW cache files created above. We only need RO cache. */
|
||||
EXPECT_EQ(unlink(foz_rw_file), 0);
|
||||
EXPECT_EQ(unlink(foz_rw_idx_file), 0);
|
||||
|
||||
setenv("MESA_DISK_CACHE_SINGLE_FILE", "false", 1);
|
||||
setenv("MESA_DISK_CACHE_DATABASE", "true", 1);
|
||||
|
||||
/* Create MESA-DB cache with enabled retrieval from the read-only
|
||||
* cache. */
|
||||
struct disk_cache *cache_mesa_db = disk_cache_create("combined_test",
|
||||
driver_id, 0);
|
||||
|
||||
/* Dummy entry must not present in any of the caches. Foz cache
|
||||
* reloads index if cache entry is missing. This is a sanity-check
|
||||
* for foz_read_entry(), it should work properly with a disabled
|
||||
* FOZ RW cache. */
|
||||
result = (char *) disk_cache_get(cache_mesa_db, dummy_key, &size);
|
||||
EXPECT_EQ(result, nullptr) << "disk_cache_get with non-existent item (pointer)";
|
||||
EXPECT_EQ(size, 0) << "disk_cache_get with non-existent item (size)";
|
||||
|
||||
/* Blob entry must present because it shall be retrieved from the
|
||||
* read-only cache. */
|
||||
result = (char *) disk_cache_get(cache_mesa_db, blob_key, &size);
|
||||
EXPECT_STREQ(blob, result) << "disk_cache_get of existing item (pointer)";
|
||||
EXPECT_EQ(size, sizeof(blob)) << "disk_cache_get of existing item (size)";
|
||||
free(result);
|
||||
|
||||
disk_cache_destroy(cache_mesa_db);
|
||||
|
||||
/* Disable read-only cache. */
|
||||
setenv("MESA_DISK_CACHE_COMBINE_RW_WITH_RO_FOZ", "false", 1);
|
||||
|
||||
/* Create MESA-DB cache with disabled retrieval from the read-only
|
||||
* cache. */
|
||||
cache_mesa_db = disk_cache_create("combined_test", driver_id, 0);
|
||||
|
||||
/* Blob entry must not present in the cache because we disable the
|
||||
* read-only cache. */
|
||||
result = (char *) disk_cache_get(cache_mesa_db, blob_key, &size);
|
||||
EXPECT_EQ(result, nullptr) << "disk_cache_get with non-existent item (pointer)";
|
||||
EXPECT_EQ(size, 0) << "disk_cache_get with non-existent item (size)";
|
||||
|
||||
disk_cache_destroy(cache_mesa_db);
|
||||
|
||||
/* Create default multi-file cache. */
|
||||
setenv("MESA_DISK_CACHE_DATABASE", "false", 1);
|
||||
|
||||
/* Enable read-only cache. */
|
||||
setenv("MESA_DISK_CACHE_COMBINE_RW_WITH_RO_FOZ", "true", 1);
|
||||
|
||||
/* Create multi-file cache with enabled retrieval from the
|
||||
* read-only cache. */
|
||||
struct disk_cache *cache_multifile = disk_cache_create("combined_test",
|
||||
driver_id, 0);
|
||||
|
||||
/* Blob entry must present because it shall be retrieved from the
|
||||
* read-only cache. */
|
||||
result = (char *) disk_cache_get(cache_multifile, blob_key, &size);
|
||||
EXPECT_STREQ(blob, result) << "disk_cache_get of existing item (pointer)";
|
||||
EXPECT_EQ(size, sizeof(blob)) << "disk_cache_get of existing item (size)";
|
||||
free(result);
|
||||
|
||||
disk_cache_destroy(cache_multifile);
|
||||
|
||||
/* Disable read-only cache. */
|
||||
setenv("MESA_DISK_CACHE_COMBINE_RW_WITH_RO_FOZ", "false", 1);
|
||||
unsetenv("MESA_DISK_CACHE_READ_ONLY_FOZ_DBS");
|
||||
|
||||
/* Create multi-file cache with disabled retrieval from the
|
||||
* read-only cache. */
|
||||
cache_multifile = disk_cache_create("combined_test", driver_id, 0);
|
||||
|
||||
/* Blob entry must not present in the cache because we disabled the
|
||||
* read-only cache. */
|
||||
result = (char *) disk_cache_get(cache_multifile, blob_key, &size);
|
||||
EXPECT_EQ(result, nullptr) << "disk_cache_get with non-existent item (pointer)";
|
||||
EXPECT_EQ(size, 0) << "disk_cache_get with non-existent item (size)";
|
||||
|
||||
disk_cache_destroy(cache_multifile);
|
||||
|
||||
int err = rmrf_local(CACHE_TEST_TMP);
|
||||
EXPECT_EQ(err, 0) << "Removing " CACHE_TEST_TMP " again";
|
||||
#endif
|
||||
}
|
||||
|
Reference in New Issue
Block a user