[Mesa-dev] [PATCH] vkpipeline_db: add support for multi-threading
Samuel Pitoiset
samuel.pitoiset at gmail.com
Tue Jun 12 12:54:23 UTC 2018
Very nice. :-)
Reviewed-by: Samuel Pitoiset <samuel.pitoiset at gmail.com>
On 06/09/2018 03:23 AM, Timothy Arceri wrote:
> ---
> 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);
>
More information about the mesa-dev
mailing list