util/disk_cache: use a thread queue to write to shader cache
authorTimothy Arceri <tarceri@itsqueeze.com>
Mon, 13 Mar 2017 00:07:30 +0000 (11:07 +1100)
committerTimothy Arceri <tarceri@itsqueeze.com>
Wed, 15 Mar 2017 00:15:11 +0000 (11:15 +1100)
This should help reduce any overhead added by the shader cache
when programs are not found in the cache.

To avoid creating any special function just for the sake of the
tests we add a one second delay whenever we call dick_cache_put()
to give it time to finish.

V2: poll for file when waiting for thread in test
V3: fix poll delay to really be 100ms, and simplify the wait function

Reviewed-by: Grazvydas Ignotas <notasas@gmail.com>
src/compiler/glsl/tests/cache_test.c
src/util/disk_cache.c

index 7a1ff0ac5bc65d3c0b325e1cf39166d8ad261db4..61ee630395ae45b5263c0f21bcc8f61aebea3c1a 100644 (file)
@@ -32,6 +32,7 @@
 #include <stdarg.h>
 #include <inttypes.h>
 #include <limits.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "util/mesa-sha1.h"
@@ -230,6 +231,26 @@ does_cache_contain(struct disk_cache *cache, cache_key key)
    return false;
 }
 
+static void
+wait_until_file_written(struct disk_cache *cache, cache_key key)
+{
+   struct timespec req;
+   struct timespec rem;
+
+   /* Set 100ms delay */
+   req.tv_sec = 0;
+   req.tv_nsec = 100000000;
+
+   unsigned retries = 0;
+   while (retries++ < 20) {
+      if (does_cache_contain(cache, key)) {
+         break;
+      }
+
+      nanosleep(&req, &rem);
+   }
+}
+
 static void
 test_put_and_get(void)
 {
@@ -260,6 +281,11 @@ test_put_and_get(void)
    /* Simple test of put and get. */
    disk_cache_put(cache, blob_key, blob, sizeof(blob));
 
+   /* disk_cache_put() hands things off to a thread give it some time to
+    * finish.
+    */
+   wait_until_file_written(cache, blob_key);
+
    result = disk_cache_get(cache, blob_key, &size);
    expect_equal_str(blob, result, "disk_cache_get of existing item (pointer)");
    expect_equal(size, sizeof(blob), "disk_cache_get of existing item (size)");
@@ -270,6 +296,11 @@ test_put_and_get(void)
    _mesa_sha1_compute(string, sizeof(string), string_key);
    disk_cache_put(cache, string_key, string, sizeof(string));
 
+   /* disk_cache_put() hands things off to a thread give it some time to
+    * finish.
+    */
+   wait_until_file_written(cache, string_key);
+
    result = disk_cache_get(cache, string_key, &size);
    expect_equal_str(result, string, "2nd disk_cache_get of existing item (pointer)");
    expect_equal(size, sizeof(string), "2nd disk_cache_get of existing item (size)");
@@ -308,6 +339,11 @@ test_put_and_get(void)
 
    free(one_KB);
 
+   /* disk_cache_put() hands things off to a thread give it some time to
+    * finish.
+    */
+   wait_until_file_written(cache, one_KB_key);
+
    result = disk_cache_get(cache, one_KB_key, &size);
    expect_non_null(result, "3rd disk_cache_get of existing item (pointer)");
    expect_equal(size, 1024, "3rd disk_cache_get of existing item (size)");
@@ -337,6 +373,12 @@ test_put_and_get(void)
    disk_cache_put(cache, blob_key, blob, sizeof(blob));
    disk_cache_put(cache, string_key, string, sizeof(string));
 
+   /* disk_cache_put() hands things off to a thread give it some time to
+    * finish.
+    */
+   wait_until_file_written(cache, blob_key);
+   wait_until_file_written(cache, string_key);
+
    count = 0;
    if (does_cache_contain(cache, blob_key))
        count++;
@@ -359,6 +401,11 @@ test_put_and_get(void)
 
    free(one_MB);
 
+   /* disk_cache_put() hands things off to a thread give it some time to
+    * finish.
+    */
+   wait_until_file_written(cache, one_MB_key);
+
    count = 0;
    if (does_cache_contain(cache, blob_key))
        count++;
index ae2861d656e06fad17a52ea5585fb991936d1694..2d37f45e3384bba84049edcb8812ccb01ac19a43 100644 (file)
@@ -780,17 +780,17 @@ struct cache_entry_file_data {
    uint32_t uncompressed_size;
 };
 
-void
-disk_cache_put(struct disk_cache *cache,
-          const cache_key key,
-          const void *data,
-          size_t size)
+static void
+cache_put(void *job, int thread_index)
 {
+   assert(job);
+
    int fd = -1, fd_final = -1, err, ret;
    size_t len;
    char *filename = NULL, *filename_tmp = NULL;
+   struct disk_cache_put_job *dc_job = (struct disk_cache_put_job *) job;
 
-   filename = get_cache_file(cache, key);
+   filename = get_cache_file(dc_job->cache, dc_job->key);
    if (filename == NULL)
       goto done;
 
@@ -808,7 +808,7 @@ disk_cache_put(struct disk_cache *cache,
       if (errno != ENOENT)
          goto done;
 
-      make_cache_file_directory(cache, key);
+      make_cache_file_directory(dc_job->cache, dc_job->key);
 
       fd = open(filename_tmp, O_WRONLY | O_CLOEXEC | O_CREAT, 0644);
       if (fd == -1)
@@ -841,15 +841,15 @@ disk_cache_put(struct disk_cache *cache,
     * Before we do that, if the cache is too large, evict something
     * else first.
     */
-   if (*cache->size + size > cache->max_size)
-      evict_random_item(cache);
+   if (*dc_job->cache->size + dc_job->size > dc_job->cache->max_size)
+      evict_random_item(dc_job->cache);
 
    /* Create CRC of the data and store at the start of the file. We will
     * read this when restoring the cache and use it to check for corruption.
     */
    struct cache_entry_file_data cf_data;
-   cf_data.crc32 = util_hash_crc32(data, size);
-   cf_data.uncompressed_size = size;
+   cf_data.crc32 = util_hash_crc32(dc_job->data, dc_job->size);
+   cf_data.uncompressed_size = dc_job->size;
 
    size_t cf_data_size = sizeof(cf_data);
    for (len = 0; len < cf_data_size; len += ret) {
@@ -864,7 +864,8 @@ disk_cache_put(struct disk_cache *cache,
     * rename them atomically to the destination filename, and also
     * perform an atomic increment of the total cache size.
     */
-   size_t file_size = deflate_and_write_to_disk(data, size, fd, filename_tmp);
+   size_t file_size = deflate_and_write_to_disk(dc_job->data, dc_job->size,
+                                                fd, filename_tmp);
    if (file_size == 0) {
       unlink(filename_tmp);
       goto done;
@@ -872,7 +873,7 @@ disk_cache_put(struct disk_cache *cache,
    rename(filename_tmp, filename);
 
    file_size += cf_data_size;
-   p_atomic_add(cache->size, file_size);
+   p_atomic_add(dc_job->cache->size, file_size);
 
  done:
    if (fd_final != -1)
@@ -888,6 +889,20 @@ disk_cache_put(struct disk_cache *cache,
       free(filename);
 }
 
+void
+disk_cache_put(struct disk_cache *cache, const cache_key key,
+               const void *data, size_t size)
+{
+   struct disk_cache_put_job *dc_job =
+      create_put_job(cache, key, data, size);
+
+   if (dc_job) {
+      util_queue_fence_init(&dc_job->fence);
+      util_queue_add_job(&cache->cache_queue, dc_job, &dc_job->fence,
+                         cache_put, destroy_put_job);
+   }
+}
+
 /**
  * Decompresses cache entry, returns true if successful.
  */