[Mesa-dev] [PATCH 3/4] radeonsi: add support for an on-disk shader cache

Marek Olšák maraeo at gmail.com
Thu Mar 2 16:14:42 UTC 2017


Reviewed-by: Marek Olšák <marek.olsak at amd.com>

Marek

On Wed, Mar 1, 2017 at 6:25 AM, Timothy Arceri <tarceri at itsqueeze.com> wrote:
> V2:
> - when loading from disk cache also binary insert into memory cache.
> - check that the binary loaded from disk is the correct size. If not
>   delete the cache item and skip loading from cache.
>
> V3:
> - remove unrequired variable
>
> Tested-by: Michel Dänzer <michel.daenzer at amd.com>
> ---
>  src/gallium/drivers/radeonsi/si_state_shaders.c | 67 ++++++++++++++++++++++---
>  1 file changed, 60 insertions(+), 7 deletions(-)
>
> diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.c b/src/gallium/drivers/radeonsi/si_state_shaders.c
> index 750cdd6..a82e38e 100644
> --- a/src/gallium/drivers/radeonsi/si_state_shaders.c
> +++ b/src/gallium/drivers/radeonsi/si_state_shaders.c
> @@ -29,20 +29,23 @@
>  #include "sid.h"
>  #include "radeon/r600_cs.h"
>
>  #include "tgsi/tgsi_parse.h"
>  #include "tgsi/tgsi_ureg.h"
>  #include "util/hash_table.h"
>  #include "util/crc32.h"
>  #include "util/u_memory.h"
>  #include "util/u_prim.h"
>
> +#include "util/disk_cache.h"
> +#include "util/mesa-sha1.h"
> +
>  /* SHADER_CACHE */
>
>  /**
>   * Return the TGSI binary in a buffer. The first 4 bytes contain its size as
>   * integer.
>   */
>  static void *si_get_tgsi_binary(struct si_shader_selector *sel)
>  {
>         unsigned tgsi_size = tgsi_num_tokens(sel->tokens) *
>                              sizeof(struct tgsi_token);
> @@ -175,54 +178,104 @@ static bool si_load_shader_binary(struct si_shader *shader, void *binary)
>  }
>
>  /**
>   * Insert a shader into the cache. It's assumed the shader is not in the cache.
>   * Use si_shader_cache_load_shader before calling this.
>   *
>   * Returns false on failure, in which case the tgsi_binary should be freed.
>   */
>  static bool si_shader_cache_insert_shader(struct si_screen *sscreen,
>                                           void *tgsi_binary,
> -                                         struct si_shader *shader)
> +                                         struct si_shader *shader,
> +                                         bool insert_into_disk_cache)
>  {
>         void *hw_binary;
>         struct hash_entry *entry;
> +       uint8_t key[CACHE_KEY_SIZE];
>
>         entry = _mesa_hash_table_search(sscreen->shader_cache, tgsi_binary);
>         if (entry)
>                 return false; /* already added */
>
>         hw_binary = si_get_shader_binary(shader);
>         if (!hw_binary)
>                 return false;
>
>         if (_mesa_hash_table_insert(sscreen->shader_cache, tgsi_binary,
>                                     hw_binary) == NULL) {
>                 FREE(hw_binary);
>                 return false;
>         }
>
> +       if (sscreen->b.disk_shader_cache && insert_into_disk_cache) {
> +               _mesa_sha1_compute(tgsi_binary, *((uint32_t *)tgsi_binary), key);
> +               disk_cache_put(sscreen->b.disk_shader_cache, key, hw_binary,
> +                              *((uint32_t *) hw_binary));
> +       }
> +
>         return true;
>  }
>
>  static bool si_shader_cache_load_shader(struct si_screen *sscreen,
>                                         void *tgsi_binary,
>                                         struct si_shader *shader)
>  {
>         struct hash_entry *entry =
>                 _mesa_hash_table_search(sscreen->shader_cache, tgsi_binary);
> -       if (!entry)
> -               return false;
> +       if (!entry) {
> +               if (sscreen->b.disk_shader_cache) {
> +                       unsigned char sha1[CACHE_KEY_SIZE];
> +                       size_t tg_size = *((uint32_t *) tgsi_binary);
> +
> +                       _mesa_sha1_compute(tgsi_binary, tg_size, sha1);
> +
> +                       size_t binary_size;
> +                       uint8_t *buffer =
> +                               disk_cache_get(sscreen->b.disk_shader_cache,
> +                                              sha1, &binary_size);
> +                       if (!buffer)
> +                               return false;
>
> -       if (!si_load_shader_binary(shader, entry->data))
> -               return false;
> +                       if (binary_size < sizeof(uint32_t) ||
> +                           *((uint32_t*)buffer) != binary_size) {
> +                                /* Something has gone wrong discard the item
> +                                 * from the cache and rebuild/link from
> +                                 * source.
> +                                 */
> +                               assert(!"Invalid radeonsi shader disk cache "
> +                                      "item!");
> +
> +                               disk_cache_remove(sscreen->b.disk_shader_cache,
> +                                                 sha1);
> +                               free(buffer);
> +
> +                               return false;
> +                       }
> +
> +                       if (!si_load_shader_binary(shader, buffer)) {
> +                               free(buffer);
> +                               return false;
> +                       }
> +                       free(buffer);
>
> +                       if (!si_shader_cache_insert_shader(sscreen, tgsi_binary,
> +                                                          shader, false))
> +                               FREE(tgsi_binary);
> +               } else {
> +                       return false;
> +               }
> +       } else {
> +               if (si_load_shader_binary(shader, entry->data))
> +                       FREE(tgsi_binary);
> +               else
> +                       return false;
> +       }
>         p_atomic_inc(&sscreen->b.num_shader_cache_hits);
>         return true;
>  }
>
>  static uint32_t si_shader_cache_key_hash(const void *key)
>  {
>         /* The first dword is the key size. */
>         return util_hash_crc32(key, *(uint32_t*)key);
>  }
>
> @@ -244,20 +297,21 @@ static void si_destroy_shader_cache_entry(struct hash_entry *entry)
>         FREE(entry->data);
>  }
>
>  bool si_init_shader_cache(struct si_screen *sscreen)
>  {
>         pipe_mutex_init(sscreen->shader_cache_mutex);
>         sscreen->shader_cache =
>                 _mesa_hash_table_create(NULL,
>                                         si_shader_cache_key_hash,
>                                         si_shader_cache_key_equals);
> +
>         return sscreen->shader_cache != NULL;
>  }
>
>  void si_destroy_shader_cache(struct si_screen *sscreen)
>  {
>         if (sscreen->shader_cache)
>                 _mesa_hash_table_destroy(sscreen->shader_cache,
>                                          si_destroy_shader_cache_entry);
>         pipe_mutex_destroy(sscreen->shader_cache_mutex);
>  }
> @@ -1400,37 +1454,36 @@ void si_init_shader_selector_async(void *job, int thread_index)
>                 shader->selector = sel;
>                 si_parse_next_shader_property(&sel->info, &shader->key);
>
>                 tgsi_binary = si_get_tgsi_binary(sel);
>
>                 /* Try to load the shader from the shader cache. */
>                 pipe_mutex_lock(sscreen->shader_cache_mutex);
>
>                 if (tgsi_binary &&
>                     si_shader_cache_load_shader(sscreen, tgsi_binary, shader)) {
> -                       FREE(tgsi_binary);
>                         pipe_mutex_unlock(sscreen->shader_cache_mutex);
>                 } else {
>                         pipe_mutex_unlock(sscreen->shader_cache_mutex);
>
>                         /* Compile the shader if it hasn't been loaded from the cache. */
>                         if (si_compile_tgsi_shader(sscreen, tm, shader, false,
>                                                    debug) != 0) {
>                                 FREE(shader);
>                                 FREE(tgsi_binary);
>                                 fprintf(stderr, "radeonsi: can't compile a main shader part\n");
>                                 return;
>                         }
>
>                         if (tgsi_binary) {
>                                 pipe_mutex_lock(sscreen->shader_cache_mutex);
> -                               if (!si_shader_cache_insert_shader(sscreen, tgsi_binary, shader))
> +                               if (!si_shader_cache_insert_shader(sscreen, tgsi_binary, shader, true))
>                                         FREE(tgsi_binary);
>                                 pipe_mutex_unlock(sscreen->shader_cache_mutex);
>                         }
>                 }
>
>                 *si_get_main_shader_part(sel, &shader->key) = shader;
>
>                 /* Unset "outputs_written" flags for outputs converted to
>                  * DEFAULT_VAL, so that later inter-shader optimizations don't
>                  * try to eliminate outputs that don't exist in the final
> --
> 2.9.3
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list