[Mesa-dev] [PATCH] vkpipeline_db: add support for multi-threading

Timothy Arceri tarceri at itsqueeze.com
Sat Jun 9 01:23:14 UTC 2018


---
 CMakeLists.txt |   1 +
 run.c          | 169 +++++++++++++++++++++++++++++++++++--------------
 2 files changed, 121 insertions(+), 49 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3e1546c..c1d86c8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,7 @@ project(vkpipeline-db)
 
 find_package(Vulkan REQUIRED)
 
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp")
 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall")
 set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall")
 if(CMAKE_COMPILER_IS_GNUCXX)
diff --git a/run.c b/run.c
index 1d641a0..eafbd7d 100644
--- a/run.c
+++ b/run.c
@@ -31,16 +31,47 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <pthread.h>
+#include <signal.h>
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <ftw.h>
 #include <time.h>
+#include <omp.h>
 
 #include "serialize.h"
 
 #define unlikely(x) __builtin_expect(!!(x), 0)
 
+int max_threads;
+const char **current_pipeline_names;
+static pthread_mutex_t printf_mutex;
+
+#define sigputs(str) write(STDERR_FILENO, str, strlen(str))
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-result"
+static void
+abort_handler(int signo)
+{
+    if (current_pipeline_names) {
+        sigputs("\n => CRASHED <= while processing these pipelines:\n\n");
+        for (int i = 0; i < max_threads; i++) {
+            if (current_pipeline_names[i]) {
+                sigputs("    ");
+                sigputs(current_pipeline_names[i]);
+                sigputs("\n");
+            }
+        }
+    } else {
+       sigputs("\n => CRASHED <= during final teardown.\n");
+    }
+    sigputs("\n");
+    _exit(-1);
+}
+#pragma GCC diagnostic pop
+
 /* Pipeline tests. */
 static unsigned pipeline_test_size = 1 << 15; /* next-pow-2(num pipelines in db) */
 static unsigned pipeline_test_length;
@@ -94,7 +125,7 @@ struct shader_stats
 };
 
 #define PARSE_STAT(key, value) \
-    line = strtok(NULL, "\n"); \
+    line = strtok_r(NULL, "\n", &saveptr); \
     if (sscanf(line, key, value) != 1) \
         return -1;
 
@@ -102,12 +133,13 @@ static int
 parse_shader_stats(char *buf, struct shader_stats *stats)
 {
     char *line;
+    char *saveptr;
 
-    line = strtok(buf, "\n");
+    line = strtok_r(buf, "\n", &saveptr);
     while(line) {
         if (!strcmp(line, "*** SHADER STATS ***"))
             break;
-        line = strtok(NULL, "\n");
+        line = strtok_r(NULL, "\n", &saveptr);
     }
 
     if (unlikely(!line))
@@ -200,6 +232,7 @@ static void
 print_shader_stats(const char *pipeline_name, VkShaderStageFlagBits stage,
                    const struct shader_stats *stats)
 {
+    pthread_mutex_lock(&printf_mutex);
     printf("%s (%s) - ", pipeline_name, get_shader_stage_name(stage));
     printf("Shader Stats: ");
     printf("SGPRS: %d ", stats->num_sgprs);
@@ -212,6 +245,7 @@ print_shader_stats(const char *pipeline_name, VkShaderStageFlagBits stage,
     printf("Spilled VGPRs: %d ", stats->num_spilled_vgprs);
     printf("PrivMem VGPRs: %d ", stats->priv_mem_vgprs);
     printf("\n");
+    pthread_mutex_unlock(&printf_mutex);
 }
 
 static VkResult
@@ -401,7 +435,8 @@ static void
 print_usage(const char *prog_name)
 {
     fprintf(stderr,
-            "Usage: %s <directories and *.pipeline_test files>\n",
+            "Usage: %s [-j <max_threads>] "
+            "<directories and *.pipeline_test files>\n",
             prog_name);
 }
 
@@ -410,16 +445,31 @@ int main(int argc, char **argv)
     const char *extensionNames[] = { "VK_AMD_shader_info" };
     VkQueueFamilyProperties queue_family;
     VkPhysicalDevice *physical_devices;
-    struct timespec start, end;
     uint32_t device_count;
     uint32_t queue_count = 1;
     VkInstance instance;
-    VkDevice device;
     VkResult result;
     int ret = 0;
+    int opt;
+
+    pthread_mutex_init(&printf_mutex, NULL);
+
+    max_threads = omp_get_max_threads();
+
+    while ((opt = getopt(argc, argv, "j:")) != -1) {
+        switch(opt) {
+        case 'j':
+            max_threads = atoi(optarg);
+            break;
+        default:
+            fprintf(stderr, "Unknown option: %x\n", opt);
+            print_usage(argv[0]);
+            return -1;
+        }
+    }
 
-    if (argc < 2) {
-        fprintf(stderr, "No directories specified!\n");
+    if (unlikely(optind >= argc)) {
+        fprintf(stderr, "No directories specified\n");
         print_usage(argv[0]);
         return -1;
     }
@@ -464,6 +514,7 @@ int main(int argc, char **argv)
     assert(queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT);
 
     /* Create logical device. */
+    VkDevice device;
     VkDeviceQueueCreateInfo queueCreateInfo = {};
     queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
     queueCreateInfo.queueFamilyIndex = 0;
@@ -494,54 +545,74 @@ int main(int argc, char **argv)
      */
     /* Gather all pipeline tests. */
     pipeline_test = malloc(pipeline_test_size * sizeof(struct pipeline_test));
-    for (int i = 1; i < argc; i++) {
+    for (int i = optind; i < argc; i++) {
         ftw(argv[i], gather_pipeline_test, 100);
     }
 
-    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
-
-    /* Process each pipeline tests. */
-    for (unsigned i = 0; i < pipeline_test_length; i++) {
-        const char *current_pipeline_name = pipeline_test[i].filename;
-        off_t filesize = pipeline_test[i].filesize;
-        char *data;
-        int fd;
-
-        fprintf(stderr, "--> %s\n", current_pipeline_name);
-
-        fd = open(current_pipeline_name, O_RDONLY);
-        if (unlikely(fd == -1)) {
-            perror("open");
-            continue;
+    unsigned *pipline_counts = calloc(max_threads, sizeof(unsigned));
+    current_pipeline_names = calloc(max_threads, sizeof(const char *));
+    omp_set_num_threads(max_threads);
+
+    if (signal(SIGABRT, abort_handler) == SIG_ERR)
+        fprintf(stderr, "WARNING: could not install SIGABRT handler.\n");
+    if (signal(SIGSEGV, abort_handler) == SIG_ERR)
+        fprintf(stderr, "WARNING: could not install SIGSEGV handler.\n");
+
+    #pragma omp parallel if(max_threads > 1 && pipeline_test_length > max_threads)
+    {
+        struct timespec start, end;
+        clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
+
+        /* Process each pipeline tests. */
+        #pragma omp for schedule(dynamic)
+        for (unsigned i = 0; i < pipeline_test_length; i++) {
+            const char *current_pipeline_name = pipeline_test[i].filename;
+            off_t filesize = pipeline_test[i].filesize;
+            char *data;
+            int fd;
+
+            current_pipeline_names[omp_get_thread_num()] = current_pipeline_name;
+
+            fprintf(stderr, "--> %s\n", current_pipeline_name);
+
+            fd = open(current_pipeline_name, O_RDONLY);
+            if (unlikely(fd == -1)) {
+                perror("open");
+                continue;
+            }
+
+            data = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
+            if (unlikely(data == MAP_FAILED)) {
+                perror("mmap");
+                continue;
+            }
+
+            if (unlikely(close(fd) == -1)) {
+                perror("close");
+                continue;
+            }
+
+            if (unlikely(run(device, current_pipeline_name, data, filesize) < 0))
+                continue;
+
+            pipline_counts[omp_get_thread_num()]++;
+
+            if (unlikely(munmap(data, filesize) == -1)) {
+                perror("munmap");
+                continue;
+            }
+
+            current_pipeline_names[omp_get_thread_num()] = NULL;
+            free(pipeline_test[i].filename);
         }
 
-        data = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
-        if (unlikely(data == MAP_FAILED)) {
-            perror("mmap");
-            continue;
-        }
-
-        if (unlikely(close(fd) == -1)) {
-            perror("close");
-            continue;
-        }
-
-        if (unlikely(run(device, current_pipeline_name, data, filesize) < 0))
-            continue;
-
-        if (unlikely(munmap(data, filesize) == -1)) {
-            perror("munmap");
-            continue;
-        }
-
-        free(pipeline_test[i].filename);
+        clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
+        printf("Thread %d took %.2lf seconds and compiled %u pipelines\n",
+               omp_get_thread_num(),
+               (end.tv_sec - start.tv_sec) + 10e-9 * (end.tv_nsec - start.tv_nsec),
+               pipline_counts[omp_get_thread_num()]);
     }
 
-    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
-    printf("Process took %.2lf seconds and compiled %u pipelines\n",
-           (end.tv_sec - start.tv_sec) + 10e-9 * (end.tv_nsec - start.tv_nsec),
-           pipeline_test_length);
-
     free(pipeline_test);
 
     vkDestroyDevice(device, NULL);
-- 
2.17.1



More information about the mesa-dev mailing list