diff options
author | Christian Gmeiner <christian.gmeiner@gmail.com> | 2020-08-08 17:44:15 +0200 |
---|---|---|
committer | Marge Bot <eric+marge@anholt.net> | 2020-09-18 07:45:11 +0000 |
commit | 77af1ca690f4f49e305c095d97b9af798bfea307 (patch) | |
tree | 28960c279b397815dabde68b878b60dfe227f47a | |
parent | 6a0d7f6316c60b480f4439ecef50de422a9175a6 (diff) |
etnaviv: add disk cache
Adds a shader disk-cache for shader variants. Note that builds with
`-Dshader-cache=false` have no-op stubs with `disk_cache_create()` that
returns NULL.
This shader disk-cache gets used when using NIR only. Helps to save
about 1-2 minutes for a deqp run on gc2000.
Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6669>
-rw-r--r-- | src/gallium/drivers/etnaviv/Makefile.sources | 2 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_compiler.c | 5 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_compiler.h | 24 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_debug.h | 1 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_disk_cache.c | 186 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_disk_cache.h | 45 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_screen.c | 13 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_shader.c | 9 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_shader.h | 3 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/meson.build | 2 |
10 files changed, 282 insertions, 8 deletions
diff --git a/src/gallium/drivers/etnaviv/Makefile.sources b/src/gallium/drivers/etnaviv/Makefile.sources index 32fcd799ac1..3fc86072c6f 100644 --- a/src/gallium/drivers/etnaviv/Makefile.sources +++ b/src/gallium/drivers/etnaviv/Makefile.sources @@ -28,6 +28,8 @@ C_SOURCES := \ etnaviv_debug.h \ etnaviv_disasm.c \ etnaviv_disasm.h \ + etnaviv_disk_cache.c \ + etnaviv_disk_cache.h \ etnaviv_emit.c \ etnaviv_emit.h \ etnaviv_etc2.c \ diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.c b/src/gallium/drivers/etnaviv/etnaviv_compiler.c index 0cb07c03cd7..119a0e21e41 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_compiler.c +++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.c @@ -27,10 +27,11 @@ #include "etnaviv_compiler.h" #include "etnaviv_compiler_nir.h" #include "etnaviv_debug.h" +#include "etnaviv_disk_cache.h" #include "util/ralloc.h" struct etna_compiler * -etna_compiler_create(void) +etna_compiler_create(const char *renderer) { struct etna_compiler *compiler = rzalloc(NULL, struct etna_compiler); @@ -43,6 +44,8 @@ etna_compiler_create(void) compiler = NULL; } + etna_disk_cache_init(compiler, renderer); + return compiler; } diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.h b/src/gallium/drivers/etnaviv/etnaviv_compiler.h index 8aaebab9f9f..734d5b1ee1b 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_compiler.h +++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.h @@ -33,6 +33,7 @@ #include "pipe/p_compiler.h" #include "pipe/p_shader_tokens.h" #include "compiler/shader_enums.h" +#include "util/disk_cache.h" /* XXX some of these are pretty arbitrary limits, may be better to switch * to dynamic allocation at some point. @@ -51,6 +52,8 @@ struct etna_compiler { uint32_t shader_count; struct ra_regs *regs; + + struct disk_cache *disk_cache; }; /* compiler output per input/output */ @@ -84,14 +87,27 @@ struct etna_shader_variant { struct etna_bo *bo; /* cached code memory bo handle (for icache) */ + /* + * Below here is serialized when written to disk cache: + */ + uint32_t *code; + struct etna_shader_uniform_info uniforms; + + /* + * The following macros are used by the shader disk cache save/ + * restore paths to serialize/deserialize the variant. Any + * pointers that require special handling in store_variant() + * and retrieve_variant() should go above here. + */ +#define VARIANT_CACHE_START offsetof(struct etna_shader_variant, stage) +#define VARIANT_CACHE_PTR(v) (((char *)v) + VARIANT_CACHE_START) +#define VARIANT_CACHE_SIZE (sizeof(struct etna_shader_variant) - VARIANT_CACHE_START) + gl_shader_stage stage; uint32_t code_size; /* code size in uint32 words */ - uint32_t *code; unsigned num_loops; unsigned num_temps; - struct etna_shader_uniform_info uniforms; - /* ETNA_DIRTY_* flags that, when set in context dirty, mean that the * uniforms have to get (partial) reloaded. */ uint32_t uniforms_dirty_bits; @@ -134,7 +150,7 @@ struct etna_shader_link_info { }; struct etna_compiler * -etna_compiler_create(void); +etna_compiler_create(const char *renderer); void etna_compiler_destroy(const struct etna_compiler *compiler); diff --git a/src/gallium/drivers/etnaviv/etnaviv_debug.h b/src/gallium/drivers/etnaviv/etnaviv_debug.h index 79e6ebaedd8..6070f2ca189 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_debug.h +++ b/src/gallium/drivers/etnaviv/etnaviv_debug.h @@ -55,6 +55,7 @@ #define ETNA_DBG_NO_SINGLEBUF 0x1000000 /* disable single buffer feature */ #define ETNA_DBG_NIR 0x2000000 /* use new NIR compiler */ #define ETNA_DBG_DEQP 0x4000000 /* Hacks to run dEQP GLES3 tests */ +#define ETNA_DBG_NOCACHE 0x8000000 /* Disable shader cache */ extern int etna_mesa_debug; /* set in etna_screen.c from ETNA_DEBUG */ diff --git a/src/gallium/drivers/etnaviv/etnaviv_disk_cache.c b/src/gallium/drivers/etnaviv/etnaviv_disk_cache.c new file mode 100644 index 00000000000..5b1844d8ebc --- /dev/null +++ b/src/gallium/drivers/etnaviv/etnaviv_disk_cache.c @@ -0,0 +1,186 @@ +/* + * Copyright © 2020 Google, Inc. + * Copyright (c) 2020 Etnaviv Project + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Christian Gmeiner <christian.gmeiner@gmail.com> + */ + +#include "etnaviv_debug.h" +#include "etnaviv_disk_cache.h" +#include "nir_serialize.h" + +#define debug 0 + +void +etna_disk_cache_init(struct etna_compiler *compiler, const char *renderer) +{ + if (!(etna_mesa_debug & ETNA_DBG_NIR)) + return; + + if (etna_mesa_debug & ETNA_DBG_NOCACHE) + return; + + const struct build_id_note *note = + build_id_find_nhdr_for_addr(etna_disk_cache_init); + assert(note && build_id_length(note) == 20); /* sha1 */ + + const uint8_t *id_sha1 = build_id_data(note); + assert(id_sha1); + + char timestamp[41]; + _mesa_sha1_format(timestamp, id_sha1); + + compiler->disk_cache = disk_cache_create(renderer, timestamp, etna_mesa_debug); +} + +void +etna_disk_cache_init_shader_key(struct etna_compiler *compiler, struct etna_shader *shader) +{ + if (!compiler->disk_cache) + return; + + struct mesa_sha1 ctx; + + _mesa_sha1_init(&ctx); + + /* Serialize the NIR to a binary blob that we can hash for the disk + * cache. Drop unnecessary information (like variable names) + * so the serialized NIR is smaller, and also to let us detect more + * isomorphic shaders when hashing, increasing cache hits. + */ + struct blob blob; + + blob_init(&blob); + nir_serialize(&blob, shader->nir, true); + _mesa_sha1_update(&ctx, blob.data, blob.size); + blob_finish(&blob); + + _mesa_sha1_final(&ctx, shader->cache_key); +} + +static void +compute_variant_key(struct etna_compiler *compiler, struct etna_shader_variant *v, + cache_key cache_key) +{ + struct blob blob; + + blob_init(&blob); + + blob_write_bytes(&blob, &v->shader->cache_key, sizeof(v->shader->cache_key)); + blob_write_bytes(&blob, &v->key, sizeof(v->key)); + + disk_cache_compute_key(compiler->disk_cache, blob.data, blob.size, cache_key); + + blob_finish(&blob); +} + +static void +retrieve_variant(struct blob_reader *blob, struct etna_shader_variant *v) +{ + blob_copy_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE); + + v->code = malloc(4 * v->code_size); + blob_copy_bytes(blob, v->code, 4 * v->code_size); + + blob_copy_bytes(blob, &v->uniforms.imm_count, sizeof(v->uniforms.imm_count)); + v->uniforms.imm_contents = malloc(v->uniforms.imm_count * sizeof(v->uniforms.imm_contents)); + v->uniforms.imm_data = malloc(v->uniforms.imm_count * sizeof(v->uniforms.imm_data)); + + blob_copy_bytes(blob, v->uniforms.imm_contents, v->uniforms.imm_count * sizeof(v->uniforms.imm_contents)); + blob_copy_bytes(blob, v->uniforms.imm_data, v->uniforms.imm_count * sizeof(v->uniforms.imm_data)); +} + +static void +store_variant(struct blob *blob, const struct etna_shader_variant *v) +{ + const uint32_t imm_count = v->uniforms.imm_count; + + blob_write_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE); + blob_write_bytes(blob, v->code, 4 * v->code_size); + + blob_write_bytes(blob, &v->uniforms.imm_count, sizeof(v->uniforms.imm_count)); + blob_write_bytes(blob, v->uniforms.imm_contents, imm_count * sizeof(v->uniforms.imm_contents)); + blob_write_bytes(blob, v->uniforms.imm_data, imm_count * sizeof(v->uniforms.imm_data)); +} + +bool +etna_disk_cache_retrieve(struct etna_compiler *compiler, struct etna_shader_variant *v) +{ + if (!compiler->disk_cache) + return false; + + cache_key cache_key; + + compute_variant_key(compiler, v, cache_key); + + if (debug) { + char sha1[41]; + + _mesa_sha1_format(sha1, cache_key); + fprintf(stderr, "[mesa disk cache] retrieving variant %s: ", sha1); + } + + size_t size; + void *buffer = disk_cache_get(compiler->disk_cache, cache_key, &size); + + if (debug) + fprintf(stderr, "%s\n", buffer ? "found" : "missing"); + + if (!buffer) + return false; + + struct blob_reader blob; + blob_reader_init(&blob, buffer, size); + + retrieve_variant(&blob, v); + + free(buffer); + + return true; +} + +void +etna_disk_cache_store(struct etna_compiler *compiler, struct etna_shader_variant *v) +{ + if (!compiler->disk_cache) + return; + + cache_key cache_key; + + compute_variant_key(compiler, v, cache_key); + + if (debug) { + char sha1[41]; + + _mesa_sha1_format(sha1, cache_key); + fprintf(stderr, "[mesa disk cache] storing variant %s\n", sha1); + } + + struct blob blob; + blob_init(&blob); + + store_variant(&blob, v); + + disk_cache_put(compiler->disk_cache, cache_key, blob.data, blob.size, NULL); + blob_finish(&blob); +} diff --git a/src/gallium/drivers/etnaviv/etnaviv_disk_cache.h b/src/gallium/drivers/etnaviv/etnaviv_disk_cache.h new file mode 100644 index 00000000000..61fa302fffa --- /dev/null +++ b/src/gallium/drivers/etnaviv/etnaviv_disk_cache.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2020 Google, Inc. + * Copyright (c) 2020 Etnaviv Project + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Christian Gmeiner <christian.gmeiner@gmail.com> + */ + +#ifndef H_ETNAVIV_DISK_CACHE +#define H_ETNAVIV_DISK_CACHE + +#include "etnaviv_compiler.h" + +void +etna_disk_cache_init(struct etna_compiler *compiler, const char *renderer); + +void +etna_disk_cache_init_shader_key(struct etna_compiler *compiler, struct etna_shader *shader); + +bool +etna_disk_cache_retrieve(struct etna_compiler *compiler, struct etna_shader_variant *v); + +void +etna_disk_cache_store(struct etna_compiler *compiler, struct etna_shader_variant *v); + +#endif diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.c b/src/gallium/drivers/etnaviv/etnaviv_screen.c index 269089868ed..1637eaa3f5f 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_screen.c +++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c @@ -74,6 +74,7 @@ static const struct debug_named_value debug_options[] = { {"no_singlebuffer",ETNA_DBG_NO_SINGLEBUF, "Disable single buffer feature"}, {"nir", ETNA_DBG_NIR, "use new NIR compiler"}, {"deqp", ETNA_DBG_DEQP, "Hacks to run dEQP GLES3 tests"}, /* needs MESA_GLES_VERSION_OVERRIDE=3.0 */ + {"nocache", ETNA_DBG_NOCACHE, "Disable shader cache"}, DEBUG_NAMED_VALUE_END }; @@ -883,6 +884,15 @@ etna_get_compiler_options(struct pipe_screen *pscreen, return &etna_screen(pscreen)->options; } +static struct disk_cache * +etna_get_disk_shader_cache(struct pipe_screen *pscreen) +{ + struct etna_screen *screen = etna_screen(pscreen); + struct etna_compiler *compiler = screen->compiler; + + return compiler->disk_cache; +} + struct pipe_screen * etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu, struct renderonly *ro) @@ -1027,6 +1037,7 @@ etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu, pscreen->get_paramf = etna_screen_get_paramf; pscreen->get_shader_param = etna_screen_get_shader_param; pscreen->get_compiler_options = etna_get_compiler_options; + pscreen->get_disk_shader_cache = etna_get_disk_shader_cache; pscreen->get_name = etna_screen_get_name; pscreen->get_vendor = etna_screen_get_vendor; @@ -1037,7 +1048,7 @@ etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu, pscreen->is_format_supported = etna_screen_is_format_supported; pscreen->query_dmabuf_modifiers = etna_screen_query_dmabuf_modifiers; - screen->compiler = etna_compiler_create(); + screen->compiler = etna_compiler_create(etna_screen_get_name(pscreen)); if (!screen->compiler) goto fail; diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c index b44354483ae..47becee5eb5 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_shader.c +++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c @@ -29,6 +29,7 @@ #include "etnaviv_compiler.h" #include "etnaviv_context.h" #include "etnaviv_debug.h" +#include "etnaviv_disk_cache.h" #include "etnaviv_screen.h" #include "etnaviv_util.h" @@ -353,6 +354,10 @@ create_variant(struct etna_shader *shader, struct etna_shader_key key) v->shader = shader; v->key = key; + v->id = ++shader->variant_count; + + if (etna_disk_cache_retrieve(shader->compiler, v)) + return v; ret = etna_compile_shader(v); if (!ret) { @@ -360,7 +365,7 @@ create_variant(struct etna_shader *shader, struct etna_shader_key key) goto fail; } - v->id = ++shader->variant_count; + etna_disk_cache_store(shader->compiler, v); return v; @@ -412,7 +417,7 @@ etna_create_shader_state(struct pipe_context *pctx, else shader->tokens = tgsi_dup_tokens(pss->tokens); - + etna_disk_cache_init_shader_key(compiler, shader); if (etna_mesa_debug & ETNA_DBG_SHADERDB) { /* if shader-db run, create a standard variant immediately diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.h b/src/gallium/drivers/etnaviv/etnaviv_shader.h index c1ea785a135..ccba5c858db 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_shader.h +++ b/src/gallium/drivers/etnaviv/etnaviv_shader.h @@ -28,6 +28,7 @@ #define H_ETNAVIV_SHADER #include "pipe/p_state.h" +#include "util/disk_cache.h" struct etna_context; struct etna_shader_variant; @@ -69,6 +70,8 @@ struct etna_shader { struct etna_compiler *compiler; struct etna_shader_variant *variants; + + cache_key cache_key; /* shader disk-cache key */ }; bool diff --git a/src/gallium/drivers/etnaviv/meson.build b/src/gallium/drivers/etnaviv/meson.build index 7b7ce26056e..8805fcc7ef2 100644 --- a/src/gallium/drivers/etnaviv/meson.build +++ b/src/gallium/drivers/etnaviv/meson.build @@ -47,6 +47,8 @@ files_etnaviv = files( 'etnaviv_debug.h', 'etnaviv_disasm.c', 'etnaviv_disasm.h', + 'etnaviv_disk_cache.c', + 'etnaviv_disk_cache.h', 'etnaviv_emit.c', 'etnaviv_emit.h', 'etnaviv_etc2.c', |