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

Timothy Arceri tarceri at itsqueeze.com
Thu Mar 2 00:09:34 UTC 2017



On 02/03/17 10:33, Axel Davy wrote:
> On 02/03/2017 00:27, Timothy Arceri wrote:
>>
>>
>> On 01/03/17 18:36, Axel Davy wrote:
>>> My understanding of the code is that the disk cache just depends on the
>>> sscreen->b.disk_shader_cache being initialized, and it looks like this
>>> is always
>>> initialized.
>>> Thus the disk cache is always enabled.
>>>
>>> Could you add a RADEON_DEBUG env var to disable it, please ?
>>
>> Replying here for completeness but as discussed on irc the entire
>> cache can be turned off with MESA_GLSL_CACHE_DISABLE=1. I don't think
>> there is much justification for a RADEON_DEBUG flag to disable only
>> the radeonsi cache.
>>
> I get a different view from our irc discussion.
>
> In my understanding, MESA_GLSL_CACHE_DISABLE only affects the glsl->tgsi
> cache.

No. sscreen->b.disk_shader_cache points to the same memory used by the 
st/mesa, and the MESA_GLSL_CACHE_DISABLE check is done inside 
disk_cache_create() so even if radeonsi did a separate initialisation it 
would still be disabled.

> The radeon tgsi->asm cache is always enabled and cannot be disabled.
> But it is fine with me, because the cache is discarded if the buildtime
> of llvm or mesa changes.
>
> Axel
>>>
>>> Thanks,
>>>
>>> Axel Davy
>>>
>>> On 01/03/2017 06:25, Timothy Arceri 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
>>>
>>>
>>> _______________________________________________
>>> 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