From 64bc227b4942e8be394f73d98e32d84e09f6d550 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Tue, 3 Sep 2024 13:51:18 +0300 Subject: [PATCH] util/mesa-db-multipart: Open one cache part at a time Open one cache DB part at a time for a multi-part cache to reduce number of FDs used by the cache. Previously multi-part DB cache instance was consuming 100 FDs, now it's 2 and cache files are opened when cache is read or written instead of opening them at the init time. Fixes: fd9f7b748e2e ("util/mesa-db: Introduce multipart mesa-db cache") Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/11776 Signed-off-by: Dmitry Osipenko Acked-by: Timothy Arceri Part-of: (cherry picked from commit 2a9378a0f97c9eddaba4dba32a24be699916f482) --- .pick_status.json | 2 +- src/util/mesa_cache_db_multipart.c | 142 ++++++++++++++++++++--------- src/util/mesa_cache_db_multipart.h | 6 +- 3 files changed, 106 insertions(+), 44 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index e34cf9dfabc..f67a3cd56c0 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -544,7 +544,7 @@ "description": "util/mesa-db-multipart: Open one cache part at a time", "nominated": true, "nomination_type": 1, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": "fd9f7b748e2e2fa57b39bb800305d2fb3d665079", "notes": null diff --git a/src/util/mesa_cache_db_multipart.c b/src/util/mesa_cache_db_multipart.c index 15257eaa50f..d6cc5ab0a6f 100644 --- a/src/util/mesa_cache_db_multipart.c +++ b/src/util/mesa_cache_db_multipart.c @@ -18,67 +18,109 @@ mesa_cache_db_multipart_open(struct mesa_cache_db_multipart *db, #if DETECT_OS_WINDOWS return false; #else - char *part_path = NULL; - unsigned int i; - db->num_parts = debug_get_num_option("MESA_DISK_CACHE_DATABASE_NUM_PARTS", 50); - + db->cache_path = cache_path; db->parts = calloc(db->num_parts, sizeof(*db->parts)); if (!db->parts) return false; - for (i = 0; i < db->num_parts; i++) { - bool db_opened = false; - - if (asprintf(&part_path, "%s/part%u", cache_path, i) == -1) - goto close_db; - - if (mkdir(part_path, 0755) == -1 && errno != EEXIST) - goto free_path; - - /* DB opening may fail only in a case of a severe problem, - * like IO error. - */ - db_opened = mesa_cache_db_open(&db->parts[i], part_path); - if (!db_opened) - goto free_path; - - free(part_path); - } - - /* remove old pre multi-part cache */ - mesa_db_wipe_path(cache_path); + simple_mtx_init(&db->lock, mtx_plain); return true; +#endif +} + +static bool +mesa_cache_db_multipart_init_part_locked(struct mesa_cache_db_multipart *db, + unsigned int part) +{ +#if DETECT_OS_WINDOWS + return false; +#else + struct mesa_cache_db *db_part; + bool db_opened = false; + char *part_path = NULL; + + if (db->parts[part]) + return true; + + if (asprintf(&part_path, "%s/part%u", db->cache_path, part) == -1) + return false; + + if (mkdir(part_path, 0755) == -1 && errno != EEXIST) + goto free_path; + + db_part = calloc(1, sizeof(*db_part)); + if (!db_part) + goto free_path; + + /* DB opening may fail only in a case of a severe problem, + * like IO error. + */ + db_opened = mesa_cache_db_open(db_part, part_path); + if (!db_opened) { + free(db_part); + goto free_path; + } + + if (db->max_cache_size) + mesa_cache_db_set_size_limit(db_part, db->max_cache_size / db->num_parts); + + /* remove old pre multi-part cache */ + mesa_db_wipe_path(db->cache_path); + + __sync_synchronize(); + + db->parts[part] = db_part; free_path: free(part_path); -close_db: - while (i--) - mesa_cache_db_close(&db->parts[i]); - free(db->parts); - - return false; + return db_opened; #endif } +static bool +mesa_cache_db_multipart_init_part(struct mesa_cache_db_multipart *db, + unsigned int part) +{ + bool ret; + + if (db->parts[part]) + return true; + + simple_mtx_lock(&db->lock); + ret = mesa_cache_db_multipart_init_part_locked(db, part); + simple_mtx_unlock(&db->lock); + + return ret; +} + void mesa_cache_db_multipart_close(struct mesa_cache_db_multipart *db) { - while (db->num_parts--) - mesa_cache_db_close(&db->parts[db->num_parts]); + while (db->num_parts--) { + if (db->parts[db->num_parts]) { + mesa_cache_db_close(db->parts[db->num_parts]); + free(db->parts[db->num_parts]); + } + } free(db->parts); + simple_mtx_destroy(&db->lock); } void mesa_cache_db_multipart_set_size_limit(struct mesa_cache_db_multipart *db, uint64_t max_cache_size) { - for (unsigned int i = 0; i < db->num_parts; i++) - mesa_cache_db_set_size_limit(&db->parts[i], - max_cache_size / db->num_parts); + for (unsigned int part = 0; part < db->num_parts; part++) { + if (db->parts[part]) + mesa_cache_db_set_size_limit(db->parts[part], + max_cache_size / db->num_parts); + } + + db->max_cache_size = max_cache_size; } void * @@ -91,7 +133,10 @@ mesa_cache_db_multipart_read_entry(struct mesa_cache_db_multipart *db, for (unsigned int i = 0; i < db->num_parts; i++) { unsigned int part = (last_read_part + i) % db->num_parts; - void *cache_item = mesa_cache_db_read_entry(&db->parts[part], + if (!mesa_cache_db_multipart_init_part(db, part)) + break; + + void *cache_item = mesa_cache_db_read_entry(db->parts[part], cache_key_160bit, size); if (cache_item) { /* Likely that the next entry lookup will hit the same DB part. */ @@ -110,7 +155,10 @@ mesa_cache_db_multipart_select_victim_part(struct mesa_cache_db_multipart *db) unsigned victim = 0; for (unsigned int i = 0; i < db->num_parts; i++) { - score = mesa_cache_db_eviction_score(&db->parts[i]); + if (!mesa_cache_db_multipart_init_part(db, i)) + continue; + + score = mesa_cache_db_eviction_score(db->parts[i]); if (score > best_score) { best_score = score; victim = i; @@ -131,8 +179,11 @@ mesa_cache_db_multipart_entry_write(struct mesa_cache_db_multipart *db, for (unsigned int i = 0; i < db->num_parts; i++) { unsigned int part = (last_written_part + i) % db->num_parts; + if (!mesa_cache_db_multipart_init_part(db, part)) + break; + /* Note that each DB part has own locking. */ - if (mesa_cache_db_has_space(&db->parts[part], blob_size)) { + if (mesa_cache_db_has_space(db->parts[part], blob_size)) { wpart = part; break; } @@ -145,9 +196,12 @@ mesa_cache_db_multipart_entry_write(struct mesa_cache_db_multipart *db, if (wpart < 0) wpart = mesa_cache_db_multipart_select_victim_part(db); + if (!mesa_cache_db_multipart_init_part(db, wpart)) + return false; + db->last_written_part = wpart; - return mesa_cache_db_entry_write(&db->parts[wpart], cache_key_160bit, + return mesa_cache_db_entry_write(db->parts[wpart], cache_key_160bit, blob, blob_size); } @@ -155,6 +209,10 @@ void mesa_cache_db_multipart_entry_remove(struct mesa_cache_db_multipart *db, const uint8_t *cache_key_160bit) { - for (unsigned int i = 0; i < db->num_parts; i++) - mesa_cache_db_entry_remove(&db->parts[i], cache_key_160bit); + for (unsigned int i = 0; i < db->num_parts; i++) { + if (!mesa_cache_db_multipart_init_part(db, i)) + continue; + + mesa_cache_db_entry_remove(db->parts[i], cache_key_160bit); + } } diff --git a/src/util/mesa_cache_db_multipart.h b/src/util/mesa_cache_db_multipart.h index 7a1aef5dcb3..d3cca82c2ab 100644 --- a/src/util/mesa_cache_db_multipart.h +++ b/src/util/mesa_cache_db_multipart.h @@ -8,12 +8,16 @@ #define MESA_CACHE_DB_MULTIPART_H #include "mesa_cache_db.h" +#include "simple_mtx.h" struct mesa_cache_db_multipart { - struct mesa_cache_db *parts; + struct mesa_cache_db **parts; unsigned int num_parts; volatile unsigned int last_read_part; volatile unsigned int last_written_part; + const char *cache_path; + uint64_t max_cache_size; + simple_mtx_t lock; }; bool