[Mesa-dev] [PATCH 2/3] draw/llvm: cache LLVM compilation

Frank Henigman fjhenigman at google.com
Sun Jun 16 10:59:04 PDT 2013


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



More information about the mesa-dev mailing list