[Mesa-dev] [PATCH 2/3] draw/llvm: cache LLVM compilation
Jose Fonseca
jfonseca at vmware.com
Fri Jul 12 11:12:30 PDT 2013
The series looks alright AFAICT.
The only request I have is the ability to disable the cache, so that we can iron out any eventual bugs.
Another thing we eventually need to think about is thread safety. Though that's not a new problem, so it can be addressed in a follow-on change.
Jose
----- Original Message -----
> Shader variants now get their LLVM-made code from a cache if possible
> instead of compiling every time. The cache key consists of the TGSI
> tokens plus the variant key. Cache items are deleted when no longer
> used by any variant.
> ---
> src/gallium/auxiliary/draw/draw_llvm.c | 126
> +++++++++++++++++++++++++++++++--
> src/gallium/auxiliary/draw/draw_llvm.h | 15 ++++
> 2 files changed, 137 insertions(+), 4 deletions(-)
>
> diff --git a/src/gallium/auxiliary/draw/draw_llvm.c
> b/src/gallium/auxiliary/draw/draw_llvm.c
> index 6225e53..a90b471 100644
> --- a/src/gallium/auxiliary/draw/draw_llvm.c
> +++ b/src/gallium/auxiliary/draw/draw_llvm.c
> @@ -49,7 +49,10 @@
>
> #include "tgsi/tgsi_exec.h"
> #include "tgsi/tgsi_dump.h"
> +#include "tgsi/tgsi_parse.h"
>
> +#include "util/u_hash.h"
> +#include "util/u_hash_table.h"
> #include "util/u_math.h"
> #include "util/u_pointer.h"
> #include "util/u_string.h"
> @@ -59,6 +62,16 @@
> #define DEBUG_STORE 0
>
>
> +static struct llvm_cache llvm_cache = { NULL };
> +
> +static struct llvm_cache_item *
> +llvm_cache_item_create(struct draw_llvm_variant *variant,
> + unsigned num_inputs,
> + struct llvm_cache_key *key);
> +
> +static void
> +llvm_cache_item_destroy(struct llvm_cache_item *item);
> +
> static void
> draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *var,
> boolean elts);
> @@ -551,15 +564,117 @@ draw_llvm_destroy(struct draw_llvm *llvm)
> }
>
>
> +static unsigned
> +llvm_cache_key_hash(void *v)
> +{
> + return ((struct llvm_cache_key *)v)->hash;
> +}
> +
> +
> +static int
> +llvm_cache_key_compare(void *v1, void *v2)
> +{
> + struct llvm_cache_key *k1 = (struct llvm_cache_key *)v1;
> + struct llvm_cache_key *k2 = (struct llvm_cache_key *)v2;
> + if (k1->size < k2->size)
> + return -1;
> + if (k1->size > k2->size)
> + return 1;
> + return memcmp(k1->data, k2->data, k2->size);
> +}
> +
> +
> +static boolean
> +llvm_cache_key_make(struct draw_llvm_variant *variant,
> + struct llvm_cache_key *key)
> +{
> + struct tgsi_token const *tokens = variant->shader->base.state.tokens;
> + unsigned tsz = tgsi_num_tokens(tokens) * sizeof(*tokens);
> + unsigned ksz = variant->shader->variant_key_size;
> + key->size = tsz + ksz;
> + key->data = MALLOC(key->size);
> + if (!key->data)
> + return false;
> + memcpy(key->data, tokens, tsz);
> + memcpy(((char *)key->data) + tsz, &variant->key, ksz);
> + key->hash = util_hash_crc32(key->data, key->size);
> + return true;
> +}
> +
> +
> +static void
> +llvm_cache_key_free(struct llvm_cache_key *key)
> +{
> + FREE(key->data);
> +}
> +
> +
> +static void
> +llvm_cache_item_ref(struct llvm_cache_item *item)
> +{
> + ++item->ref_count;
> +}
> +
> +
> +static void
> +llvm_cache_item_unref(struct llvm_cache_item *item)
> +{
> + assert(item->ref_count > 0);
> + --item->ref_count;
> + if (item->ref_count == 0) {
> + llvm_cache_item_destroy(item);
> + }
> +}
> +
> +
> +/**
> + * Get LLVM-generated code from cache or make it if needed.
> + */
> static struct llvm_cache_item *
> -llvm_cache_item_create(struct draw_llvm_variant *variant, unsigned
> num_inputs)
> +llvm_cache_item_get(struct draw_llvm_variant *variant, unsigned num_inputs)
> +{
> + struct llvm_cache_item *item;
> + struct llvm_cache_key key;
> +
> + if (!llvm_cache.ht)
> + llvm_cache.ht = util_hash_table_create(&llvm_cache_key_hash,
> + &llvm_cache_key_compare);
> + if (!llvm_cache.ht)
> + return NULL;
> +
> + if (!llvm_cache_key_make(variant, &key)) {
> + return NULL;
> + }
> +
> + item = (struct llvm_cache_item *) util_hash_table_get(llvm_cache.ht,
> &key);
> + if (item) {
> + llvm_cache_key_free(&key);
> + llvm_cache_item_ref(item);
> + } else {
> + item = llvm_cache_item_create(variant, num_inputs, &key);
> + if (item) {
> + item->ref_count = 1;
> + util_hash_table_set(llvm_cache.ht, &item->key, item);
> + }
> + }
> +
> + return item;
> +}
> +
> +
> +static struct llvm_cache_item *
> +llvm_cache_item_create(struct draw_llvm_variant *variant,
> + unsigned num_inputs,
> + struct llvm_cache_key *key)
> {
> struct llvm_cache_item *item;
> LLVMTypeRef vertex_header;
>
> item = MALLOC(sizeof *item);
> - if (item == NULL)
> + if (item == NULL) {
> + llvm_cache_key_free(key);
> return NULL;
> + }
>
> variant->llvm_item = item;
>
> @@ -590,6 +705,8 @@ llvm_cache_item_create(struct draw_llvm_variant *variant,
> unsigned num_inputs)
>
> gallivm_teardown(item->gallivm);
>
> + memcpy(&item->key, key, sizeof(*key));
> +
> return item;
> }
>
> @@ -617,7 +734,7 @@ draw_llvm_create_variant(struct draw_llvm *llvm,
>
> memcpy(&variant->key, key, shader->variant_key_size);
>
> - variant->llvm_item = llvm_cache_item_create(variant, num_inputs);
> + variant->llvm_item = llvm_cache_item_get(variant, num_inputs);
> if (variant->llvm_item == NULL) {
> FREE(variant);
> return NULL;
> @@ -1966,6 +2083,7 @@ llvm_cache_item_destroy(struct llvm_cache_item *item)
> {
> gallivm_free_code(item->gallivm);
> FREE(item->gallivm);
> + llvm_cache_key_free(&item->key);
> FREE(item);
> }
>
> @@ -1973,7 +2091,7 @@ llvm_cache_item_destroy(struct llvm_cache_item *item)
> void
> draw_llvm_destroy_variant(struct draw_llvm_variant *variant)
> {
> - llvm_cache_item_destroy(variant->llvm_item);
> + llvm_cache_item_unref(variant->llvm_item);
>
> remove_from_list(&variant->list_item_local);
> variant->shader->variants_cached--;
> diff --git a/src/gallium/auxiliary/draw/draw_llvm.h
> b/src/gallium/auxiliary/draw/draw_llvm.h
> index d979dcf..95796f1 100644
> --- a/src/gallium/auxiliary/draw/draw_llvm.h
> +++ b/src/gallium/auxiliary/draw/draw_llvm.h
> @@ -372,12 +372,27 @@ struct draw_gs_llvm_variant_list_item
> };
>
>
> +struct llvm_cache
> +{
> + struct util_hash_table *ht;
> +};
> +
> +struct llvm_cache_key
> +{
> + void *data;
> + unsigned size;
> + unsigned hash;
> +};
> +
> struct llvm_cache_item
> {
> struct gallivm_state *gallivm;
>
> draw_jit_vert_func jit_func;
> draw_jit_vert_func_elts jit_func_elts;
> +
> + struct llvm_cache_key key;
> + unsigned ref_count;
> };
>
> struct draw_llvm_variant
> --
> 1.8.3
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
More information about the mesa-dev
mailing list