From 9beecfdd8a889569a9d389ff4fbf621b0bc7d741 Mon Sep 17 00:00:00 2001 From: vano105 Date: Fri, 19 Jul 2024 17:20:10 +0300 Subject: [PATCH 1/8] Add tests from sgemm tutor --- blackbox.simx.cache | 1 + tests/opencl/Makefile | 17 +- tests/opencl/kernel1/Makefile | 17 ++ tests/opencl/kernel1/kernel.cl | 18 ++ tests/opencl/kernel1/main.cc | 339 ++++++++++++++++++++++++++++++++ tests/opencl/kernel2/Makefile | 20 ++ tests/opencl/kernel2/common.h | 6 + tests/opencl/kernel2/kernel.cl | 46 +++++ tests/opencl/kernel2/main.cc | 340 +++++++++++++++++++++++++++++++++ tests/opencl/kernel3/Makefile | 20 ++ tests/opencl/kernel3/common.h | 8 + tests/opencl/kernel3/kernel.cl | 55 ++++++ tests/opencl/kernel3/main.cc | 337 ++++++++++++++++++++++++++++++++ 13 files changed, 1223 insertions(+), 1 deletion(-) create mode 100644 blackbox.simx.cache create mode 100644 tests/opencl/kernel1/Makefile create mode 100644 tests/opencl/kernel1/kernel.cl create mode 100644 tests/opencl/kernel1/main.cc create mode 100644 tests/opencl/kernel2/Makefile create mode 100644 tests/opencl/kernel2/common.h create mode 100644 tests/opencl/kernel2/kernel.cl create mode 100644 tests/opencl/kernel2/main.cc create mode 100644 tests/opencl/kernel3/Makefile create mode 100644 tests/opencl/kernel3/common.h create mode 100644 tests/opencl/kernel3/kernel.cl create mode 100644 tests/opencl/kernel3/main.cc diff --git a/blackbox.simx.cache b/blackbox.simx.cache new file mode 100644 index 000000000..32e551ea1 --- /dev/null +++ b/blackbox.simx.cache @@ -0,0 +1 @@ +-DNUM_CLUSTERS=1 -DNUM_CORES=16 -DNUM_WARPS=16 -DNUM_THREADS=16 +0+0 diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index db8366795..80cb26ee5 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -22,6 +22,9 @@ all: $(MAKE) -C sgemm2 $(MAKE) -C sgemm3 $(MAKE) -C psum + $(MAKE) -C kernel1 + $(MAKE) -C kernel2 + $(MAKE) -C kernel3 run-simx: $(MAKE) -C vecadd run-simx @@ -43,6 +46,9 @@ run-simx: $(MAKE) -C sgemm2 run-simx $(MAKE) -C sgemm3 run-simx $(MAKE) -C psum run-simx + $(MAKE) -C kernel1 run-simx + $(MAKE) -C kernel2 run-simx + $(MAKE) -C kernel3 run-simx run-rtlsim: $(MAKE) -C vecadd run-rtlsim @@ -64,6 +70,9 @@ run-rtlsim: $(MAKE) -C sgemm2 run-rtlsim $(MAKE) -C sgemm3 run-rtlsim $(MAKE) -C psum run-rtlsim + $(MAKE) -C kernel1 run-rtlsim + $(MAKE) -C kernel2 run-rtlsim + $(MAKE) -C kernel3 run-rtlsim run-opae: $(MAKE) -C vecadd run-opae @@ -85,6 +94,9 @@ run-opae: $(MAKE) -C sgemm2 run-opae $(MAKE) -C sgemm3 run-opae $(MAKE) -C psum run-opae + $(MAKE) -C kernel1 run-opae + $(MAKE) -C kernel2 run-opae + $(MAKE) -C kernel3 run-opae clean: $(MAKE) -C vecadd clean @@ -106,4 +118,7 @@ clean: $(MAKE) -C bfs clean $(MAKE) -C sgemm2 clean $(MAKE) -C sgemm3 clean - $(MAKE) -C psum clean \ No newline at end of file + $(MAKE) -C psum clean + $(MAKE) -C kernel1 clean + $(MAKE) -C kernel2 clean + $(MAKE) -C kernel3 clean diff --git a/tests/opencl/kernel1/Makefile b/tests/opencl/kernel1/Makefile new file mode 100644 index 000000000..37ada9b31 --- /dev/null +++ b/tests/opencl/kernel1/Makefile @@ -0,0 +1,17 @@ +ROOT_DIR := $(realpath ../../..) +include $(ROOT_DIR)/config.mk + +PROJECT := kernel1 + +SRC_DIR := $(VORTEX_HOME)/tests/opencl/$(PROJECT) + +SRCS := $(SRC_DIR)/main.cc + +kernel.cl: $(SRC_DIR)/kernel.cl + cp $< $@ + +KERNEL_SRCS := kernel.cl + +OPTS ?= + +include ../common.mk diff --git a/tests/opencl/kernel1/kernel.cl b/tests/opencl/kernel1/kernel.cl new file mode 100644 index 000000000..e5ebd4958 --- /dev/null +++ b/tests/opencl/kernel1/kernel.cl @@ -0,0 +1,18 @@ +__kernel void myGEMM1(const int M, const int N, const int K, + const __global float* A, + const __global float* B, + __global float* C) { + // Thread identifiers + const int globalRow = get_global_id(0); // Row ID of C (0..M) + const int globalCol = get_global_id(1); // Col ID of C (0..N) + + // Compute a single element (loop over K) + float acc = 0.0f; + for (int k=0; k +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int TS = 0; +int M = 0, N = 0, K = 0; + +static void show_usage() { + printf("Usage: [-M number of rows in first matrix] [-N number of columns in first matrix] [-K number of columns in first matrix and rows in second matrix] [-h: help]\n"); +} + +#define CL_CHECK(_expr) \ + do { \ + cl_int _err = _expr; \ + if (_err == CL_SUCCESS) \ + break; \ + printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ + cleanup(); \ + exit(-1); \ + } while (0) + +#define CL_CHECK2(_expr) \ + ({ \ + cl_int _err = CL_INVALID_VALUE; \ + decltype(_expr) _ret = _expr; \ + if (_err != CL_SUCCESS) { \ + printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ + cleanup(); \ + exit(-1); \ + } \ + _ret; \ + }) + +static int read_kernel_file(const char *filename, uint8_t **data, + size_t *size) { + if (NULL == filename || NULL == data || 0 == size) + return -1; + + FILE *fp = fopen(filename, "r"); + if (NULL == fp) { + fprintf(stderr, "Failed to load kernel."); + return -1; + } + + fseek(fp, 0, SEEK_END); + long fsize = ftell(fp); + rewind(fp); + + *data = (uint8_t *)malloc(fsize); + *size = fread(*data, 1, fsize, fp); + + fclose(fp); + + return 0; +} + +static void sgemm_cpu(float *C, const float *A, const float *B, int M, int N, + int K) { + for (int m = 0; m < M; ++m) { + for (int n = 0; n < N; ++n) { + float acc = 0; + for (int k = 0; k < K; ++k) { + acc += A[k * M + m] * B[n * K + k]; + } + C[n * M + m] = acc; + } + } +} + +cl_platform_id platform_id = NULL; +cl_device_id device_id = NULL; +cl_context context = NULL; +cl_command_queue command_queue = NULL; +cl_program program = NULL; +cl_kernel kernel = NULL; +cl_mem a_memobj = NULL; +cl_mem b_memobj = NULL; +cl_mem c_memobj = NULL; +uint8_t *kernel_bin = NULL; + +static void cleanup() { + if (command_queue) + clReleaseCommandQueue(command_queue); + if (kernel) + clReleaseKernel(kernel); + if (program) + clReleaseProgram(program); + if (a_memobj) + clReleaseMemObject(a_memobj); + if (b_memobj) + clReleaseMemObject(b_memobj); + if (c_memobj) + clReleaseMemObject(c_memobj); + if (context) + clReleaseContext(context); + if (device_id) + clReleaseDevice(device_id); + // if (platform_id) + // clReleasePlatform(platform_id); + if (kernel_bin) + free(kernel_bin); +} + +static void parse_args(int argc, char **argv) { + int c; + while ((c = getopt(argc, argv, "T:n:M:N:K:h?")) != -1) { + switch (c) { + case 'T': + TS = atoi(optarg); + break; + case 'n': + M = N = K = atoi(optarg); + break; + case 'M': + M = atoi(optarg); + break; + case 'N': + N = atoi(optarg); + break; + case 'K': + K = atoi(optarg); + break; + case 'h': + case '?': { + show_usage(); + exit(0); + } break; + default: + show_usage(); + exit(-1); + } + } + + if (M < 2 || N < 2 || K < 2 || TS < 2) { + printf("Error: invalid size!\n"); + exit(-1); + } +} + +int main(int argc, char **argv) { + // parse command arguments + parse_args(argc, argv); + //printf("%d", VX_CAPS_NUM_CORES); + +/* + // find device and platform + cl_uint platform_count = 0; + CL_CHECK(clGetPlatformIDs(0, NULL, &platform_count)); + cl_platform_id *platforms = + (cl_platform_id *)malloc(platform_count * sizeof(cl_platform_id)); + if (platforms == NULL) { + printf("Not enough memory"); + cleanup(); + exit(-1); + } + CL_CHECK(clGetPlatformIDs(platform_count, platforms, NULL)); + + bool gpu_device_selected = false; + bool any_device_selected = false; + for (int platform_index = 0; platform_index < (int)platform_count; + ++platform_index) { + cl_platform_id platform = platforms[platform_index]; + cl_uint devices_count = 0; + + CL_CHECK( + clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &devices_count)); + cl_device_id *devices = + (cl_device_id *)malloc(sizeof(cl_device_id) * devices_count); + if (devices == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + CL_CHECK(clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, devices_count, + devices, NULL)); + for (int device_index = 0; device_index < (int)devices_count; ++device_index) { + cl_device_id device = devices[device_index]; + cl_device_type device_type; + CL_CHECK(clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(device_type), + &device_type, NULL)); + + if (device_type & CL_DEVICE_TYPE_GPU) { + gpu_device_selected = true; + any_device_selected = true; + platform_id = platform; + device_id = device; + break; + } + if (device_type & CL_DEVICE_TYPE_CPU) { + any_device_selected = true; + platform_id = platform; + device_id = device; + } + } + if (gpu_device_selected) + break; + } + if (!any_device_selected) { + printf("No device found"); + cleanup(); + return -1; + }*/ + + CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); + CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); + // create context + cl_context_properties context_properties[]{ + CL_CONTEXT_PLATFORM, cl_context_properties(platform_id), 0}; + cl_device_id devices[]{device_id}; + context = CL_CHECK2(clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err)); + + char device_string[1024]; + clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); + printf("Using device: %s\n", device_string); + // create command queue + command_queue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); + + // generate data + float *A, *B, *C; + A = (float *)(malloc(M * K * sizeof(float))); + B = (float *)(malloc(N * K * sizeof(float))); + C = (float *)(malloc(M * N * sizeof(float))); + if (A == NULL || B == NULL || C == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + for (int i = 0; i < M * N; i++) { + A[i] = 1; + B[i] = 1; + } + + // create buffers + a_memobj = + CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, + M * K * sizeof(float), A, &_err)); + b_memobj = + CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, + N * K * sizeof(float), B, &_err)); + c_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, + M * N * sizeof(float), NULL, &_err)); + + // load kernel text + size_t kernel_size; + if (read_kernel_file("kernel.cl", &kernel_bin, &kernel_size) != 0) { + cleanup(); + return -1; + } + program = CL_CHECK2(clCreateProgramWithSource(context, 1, (const char **)&kernel_bin, + &kernel_size, &_err)); + if (program == NULL) { + cleanup(); + return -1; + } + + // build program + cl_int build_status = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); + + // create kernel + kernel = CL_CHECK2(clCreateKernel(program, "myGEMM1", &_err)); + + // check building info + size_t log_size = 0; + CL_CHECK(clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, + NULL, &log_size)); + char *log = (char *)malloc(log_size * sizeof(char)); + if (log == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + CL_CHECK(clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, + log_size, log, NULL)); + if (log_size > 1) { + printf("Log:\n"); + printf("%s", log); + printf("\n"); + } + CL_CHECK(build_status); + + + // set kernel arguments + CL_CHECK(clSetKernelArg(kernel, 0, sizeof(int), &M)); + CL_CHECK(clSetKernelArg(kernel, 1, sizeof(int), &N)); + CL_CHECK(clSetKernelArg(kernel, 2, sizeof(int), &K)); + CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_mem), (void *)&a_memobj)); + CL_CHECK(clSetKernelArg(kernel, 4, sizeof(cl_mem), (void *)&b_memobj)); + CL_CHECK(clSetKernelArg(kernel, 5, sizeof(cl_mem), (void *)&c_memobj)); + + // run kernel + const size_t local[2] = {TS, TS}; + const size_t global[2] = {M, N}; + printf("Execute the kernel\n"); + auto time_start = std::chrono::high_resolution_clock::now(); + CL_CHECK(clEnqueueNDRangeKernel(command_queue, kernel, 2, NULL, global, local, + 0, NULL, NULL)); + CL_CHECK(clFinish(command_queue)); + //CL_CHECK(clWaitForEvents(1, &event)); + auto time_end = std::chrono::high_resolution_clock::now(); + double elapsed = std::chrono::duration_cast( + time_end - time_start) + .count(); + printf("Elapsed time: %lg ms\n", elapsed); + + // get results from VRAM + CL_CHECK(clEnqueueReadBuffer(command_queue, c_memobj, CL_TRUE, 0, + M * N * sizeof(float), C, 0, NULL, NULL)); + CL_CHECK(clFinish(command_queue)); + + // verify results + printf("Verify result\n"); + float *C_cpu = (float *)malloc(M * N * sizeof(float)); + if (C_cpu == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + sgemm_cpu(C_cpu, A, B, M, N, K); + int errors = 0; + + for (size_t i = 0; i < size_t(M * N); i++) + if (C_cpu[i] != C[i]) + errors++; + if (errors != 0) + printf("FAILED! - %d errors\n", errors); + else + printf("PASSED!\n"); + + // free resureses + cleanup(); + return errors; +} \ No newline at end of file diff --git a/tests/opencl/kernel2/Makefile b/tests/opencl/kernel2/Makefile new file mode 100644 index 000000000..fa9b7f379 --- /dev/null +++ b/tests/opencl/kernel2/Makefile @@ -0,0 +1,20 @@ +ROOT_DIR := $(realpath ../../..) +include $(ROOT_DIR)/config.mk + +PROJECT := kernel2 + +SRC_DIR := $(VORTEX_HOME)/tests/opencl/$(PROJECT) + +SRCS := $(SRC_DIR)/main.cc + +kernel.cl: $(SRC_DIR)/kernel.cl + cp $< $@ + +common.h: $(SRC_DIR)/common.h + cp $< $@ + +KERNEL_SRCS := kernel.cl common.h + +OPTS ?= + +include ../common.mk diff --git a/tests/opencl/kernel2/common.h b/tests/opencl/kernel2/common.h new file mode 100644 index 000000000..e51835d3c --- /dev/null +++ b/tests/opencl/kernel2/common.h @@ -0,0 +1,6 @@ +#ifndef COMMON_H +#define COMMON_H + +#define TS 4 + +#endif // COMMON_H \ No newline at end of file diff --git a/tests/opencl/kernel2/kernel.cl b/tests/opencl/kernel2/kernel.cl new file mode 100644 index 000000000..692318cde --- /dev/null +++ b/tests/opencl/kernel2/kernel.cl @@ -0,0 +1,46 @@ +#include "common.h" + +__kernel void myGEMM2(const int M, const int N, const int K, + const __global float* A, + const __global float* B, + __global float* C) { + + // Thread identifiers + const int row = get_local_id(0); // Local row ID (max: TS) + const int col = get_local_id(1); // Local col ID (max: TS) + const int globalRow = TS*get_group_id(0) + row; // Row ID of C (0..M) + const int globalCol = TS*get_group_id(1) + col; // Col ID of C (0..N) + + // Local memory to fit a tile of TS*TS elements of A and B + __local float Asub[TS][TS]; + __local float Bsub[TS][TS]; + + // Initialise the accumulation register + float acc = 0.0f; + + // Loop over all tiles + const int numTiles = K/TS; + for (int t=0; t +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +int M = 256, N = 256, K = 256; + +static void show_usage() { + printf("Usage: [-M number of rows in first matrix] [-N number of columns in first matrix] [-K number of columns in first matrix and rows in second matrix] [-h: help]\n"); +} + +#define CL_CHECK(_expr) \ + do { \ + cl_int _err = _expr; \ + if (_err == CL_SUCCESS) \ + break; \ + printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ + cleanup(); \ + exit(-1); \ + } while (0) + +#define CL_CHECK2(_expr) \ + ({ \ + cl_int _err = CL_INVALID_VALUE; \ + decltype(_expr) _ret = _expr; \ + if (_err != CL_SUCCESS) { \ + printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ + cleanup(); \ + exit(-1); \ + } \ + _ret; \ + }) + +static int read_kernel_file(const char *filename, uint8_t **data, + size_t *size) { + if (NULL == filename || NULL == data || 0 == size) + return -1; + + FILE *fp = fopen(filename, "r"); + if (NULL == fp) { + fprintf(stderr, "Failed to load kernel."); + return -1; + } + + fseek(fp, 0, SEEK_END); + long fsize = ftell(fp); + rewind(fp); + + *data = (uint8_t *)malloc(fsize); + *size = fread(*data, 1, fsize, fp); + + fclose(fp); + + return 0; +} + +static void sgemm_cpu(float *C, const float *A, const float *B, int M, int N, + int K) { + for (int m = 0; m < M; ++m) { + for (int n = 0; n < N; ++n) { + float acc = 0; + for (int k = 0; k < K; ++k) { + acc += A[k * M + m] * B[n * K + k]; + } + C[n * M + m] = acc; + } + } +} + +cl_platform_id platform_id = NULL; +cl_device_id device_id = NULL; +cl_context context = NULL; +cl_command_queue command_queue = NULL; +cl_program program = NULL; +cl_kernel kernel = NULL; +cl_mem a_memobj = NULL; +cl_mem b_memobj = NULL; +cl_mem c_memobj = NULL; +uint8_t *kernel_bin = NULL; + +static void cleanup() { + if (command_queue) + clReleaseCommandQueue(command_queue); + if (kernel) + clReleaseKernel(kernel); + if (program) + clReleaseProgram(program); + if (a_memobj) + clReleaseMemObject(a_memobj); + if (b_memobj) + clReleaseMemObject(b_memobj); + if (c_memobj) + clReleaseMemObject(c_memobj); + if (context) + clReleaseContext(context); + if (device_id) + clReleaseDevice(device_id); + // if (platform_id) + // clReleasePlatform(platform_id); + if (kernel_bin) + free(kernel_bin); +} + +static void parse_args(int argc, char **argv) { + int c; + while ((c = getopt(argc, argv, "T:n:M:N:K:h?")) != -1) { + switch (c) { + case 'T': + TS = atoi(optarg); + break; + case 'n': + M = N = K = atoi(optarg); + break; + case 'M': + M = atoi(optarg); + break; + case 'N': + N = atoi(optarg); + break; + case 'K': + K = atoi(optarg); + break; + case 'h': + case '?': { + show_usage(); + exit(0); + } break; + default: + show_usage(); + exit(-1); + } + } + + if (M < 2 || N < 2 || K < 2 || TS < 2) { + printf("Error: invalid size!\n"); + exit(-1); + } +} + +int main(int argc, char **argv) { + // parse command arguments + parse_args(argc, argv); + //printf("%d", VX_CAPS_NUM_CORES); + +/* + // find device and platform + cl_uint platform_count = 0; + CL_CHECK(clGetPlatformIDs(0, NULL, &platform_count)); + cl_platform_id *platforms = + (cl_platform_id *)malloc(platform_count * sizeof(cl_platform_id)); + if (platforms == NULL) { + printf("Not enough memory"); + cleanup(); + exit(-1); + } + CL_CHECK(clGetPlatformIDs(platform_count, platforms, NULL)); + + bool gpu_device_selected = false; + bool any_device_selected = false; + for (int platform_index = 0; platform_index < (int)platform_count; + ++platform_index) { + cl_platform_id platform = platforms[platform_index]; + cl_uint devices_count = 0; + + CL_CHECK( + clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &devices_count)); + cl_device_id *devices = + (cl_device_id *)malloc(sizeof(cl_device_id) * devices_count); + if (devices == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + CL_CHECK(clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, devices_count, + devices, NULL)); + for (int device_index = 0; device_index < (int)devices_count; ++device_index) { + cl_device_id device = devices[device_index]; + cl_device_type device_type; + CL_CHECK(clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(device_type), + &device_type, NULL)); + + if (device_type & CL_DEVICE_TYPE_GPU) { + gpu_device_selected = true; + any_device_selected = true; + platform_id = platform; + device_id = device; + break; + } + if (device_type & CL_DEVICE_TYPE_CPU) { + any_device_selected = true; + platform_id = platform; + device_id = device; + } + } + if (gpu_device_selected) + break; + } + if (!any_device_selected) { + printf("No device found"); + cleanup(); + return -1; + }*/ + + CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); + CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); + // create context + cl_context_properties context_properties[]{ + CL_CONTEXT_PLATFORM, cl_context_properties(platform_id), 0}; + cl_device_id devices[]{device_id}; + context = CL_CHECK2(clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err)); + + char device_string[1024]; + clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); + printf("Using device: %s\n", device_string); + // create command queue + command_queue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); + + // generate data + float *A, *B, *C; + A = (float *)(malloc(M * K * sizeof(float))); + B = (float *)(malloc(N * K * sizeof(float))); + C = (float *)(malloc(M * N * sizeof(float))); + if (A == NULL || B == NULL || C == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + for (int i = 0; i < M * N; i++) { + A[i] = 1; + B[i] = 1; + } + + // create buffers + a_memobj = + CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, + M * K * sizeof(float), A, &_err)); + b_memobj = + CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, + N * K * sizeof(float), B, &_err)); + c_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, + M * N * sizeof(float), NULL, &_err)); + + // load kernel text + size_t kernel_size; + if (read_kernel_file("kernel.cl", &kernel_bin, &kernel_size) != 0) { + cleanup(); + return -1; + } + program = CL_CHECK2(clCreateProgramWithSource(context, 1, (const char **)&kernel_bin, + &kernel_size, &_err)); + if (program == NULL) { + cleanup(); + return -1; + } + + // build program + cl_int build_status = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); + + // create kernel + kernel = CL_CHECK2(clCreateKernel(program, "myGEMM2", &_err)); + + // check building info + size_t log_size = 0; + CL_CHECK(clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, + NULL, &log_size)); + char *log = (char *)malloc(log_size * sizeof(char)); + if (log == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + CL_CHECK(clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, + log_size, log, NULL)); + if (log_size > 1) { + printf("Log:\n"); + printf("%s", log); + printf("\n"); + } + CL_CHECK(build_status); + + + // set kernel arguments + CL_CHECK(clSetKernelArg(kernel, 0, sizeof(int), &M)); + CL_CHECK(clSetKernelArg(kernel, 1, sizeof(int), &N)); + CL_CHECK(clSetKernelArg(kernel, 2, sizeof(int), &K)); + CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_mem), (void *)&a_memobj)); + CL_CHECK(clSetKernelArg(kernel, 4, sizeof(cl_mem), (void *)&b_memobj)); + CL_CHECK(clSetKernelArg(kernel, 5, sizeof(cl_mem), (void *)&c_memobj)); + + // run kernel + const size_t local[2] = {TS, TS}; + const size_t global[2] = {M, N}; + printf("Execute the kernel\n"); + auto time_start = std::chrono::high_resolution_clock::now(); + CL_CHECK(clEnqueueNDRangeKernel(command_queue, kernel, 2, NULL, global, local, + 0, NULL, NULL)); + CL_CHECK(clFinish(command_queue)); + //CL_CHECK(clWaitForEvents(1, &event)); + auto time_end = std::chrono::high_resolution_clock::now(); + double elapsed = std::chrono::duration_cast( + time_end - time_start) + .count(); + printf("Elapsed time: %lg ms\n", elapsed); + + // get results from VRAM + CL_CHECK(clEnqueueReadBuffer(command_queue, c_memobj, CL_TRUE, 0, + M * N * sizeof(float), C, 0, NULL, NULL)); + CL_CHECK(clFinish(command_queue)); + + // verify results + printf("Verify result\n"); + float *C_cpu = (float *)malloc(M * N * sizeof(float)); + if (C_cpu == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + sgemm_cpu(C_cpu, A, B, M, N, K); + int errors = 0; + + for (size_t i = 0; i < size_t(M * N); i++) + if (C_cpu[i] != C[i]) + errors++; + if (errors != 0) + printf("FAILED! - %d errors\n", errors); + else + printf("PASSED!\n"); + + // free resureses + cleanup(); + return errors; +} \ No newline at end of file diff --git a/tests/opencl/kernel3/Makefile b/tests/opencl/kernel3/Makefile new file mode 100644 index 000000000..b7e0c3133 --- /dev/null +++ b/tests/opencl/kernel3/Makefile @@ -0,0 +1,20 @@ +ROOT_DIR := $(realpath ../../..) +include $(ROOT_DIR)/config.mk + +PROJECT := kernel3 + +SRC_DIR := $(VORTEX_HOME)/tests/opencl/$(PROJECT) + +SRCS := $(SRC_DIR)/main.cc + +kernel.cl: $(SRC_DIR)/kernel.cl + cp $< $@ + +common.h: $(SRC_DIR)/common.h + cp $< $@ + +KERNEL_SRCS := kernel.cl common.h + +OPTS ?= + +include ../common.mk diff --git a/tests/opencl/kernel3/common.h b/tests/opencl/kernel3/common.h new file mode 100644 index 000000000..7ab67c5b2 --- /dev/null +++ b/tests/opencl/kernel3/common.h @@ -0,0 +1,8 @@ +#ifndef COMMON_H +#define COMMON_H + +#define TS 16 +#define WPT 8 +#define RTS (TS/WPT) + +#endif // COMMON_H diff --git a/tests/opencl/kernel3/kernel.cl b/tests/opencl/kernel3/kernel.cl new file mode 100644 index 000000000..fbc30034b --- /dev/null +++ b/tests/opencl/kernel3/kernel.cl @@ -0,0 +1,55 @@ +#include "common.h" + +__kernel void myGEMM3(const int M, const int N, const int K, + const __global float* A, + const __global float* B, + __global float* C) { + + // Thread identifiers + const int row = get_local_id(0); // Local row ID (max: TS) + const int col = get_local_id(1); // Local col ID (max: TS/WPT == RTS) + const int globalRow = TS*get_group_id(0) + row; // Row ID of C (0..M) + const int globalCol = TS*get_group_id(1) + col; // Col ID of C (0..N) + + // Local memory to fit a tile of TS*TS elements of A and B + __local float Asub[TS][TS]; + __local float Bsub[TS][TS]; + + // Initialise the accumulation registers + float acc[WPT]; + for (int w=0; w +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +int M = 256, N = 256, K = 256; + +static void show_usage() { + printf("Usage: [-M number of rows in first matrix] [-N number of columns in first matrix] [-K number of columns in first matrix and rows in second matrix] [-h: help]\n"); +} + +#define CL_CHECK(_expr) \ + do { \ + cl_int _err = _expr; \ + if (_err == CL_SUCCESS) \ + break; \ + printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ + cleanup(); \ + exit(-1); \ + } while (0) + +#define CL_CHECK2(_expr) \ + ({ \ + cl_int _err = CL_INVALID_VALUE; \ + decltype(_expr) _ret = _expr; \ + if (_err != CL_SUCCESS) { \ + printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ + cleanup(); \ + exit(-1); \ + } \ + _ret; \ + }) + +static int read_kernel_file(const char *filename, uint8_t **data, + size_t *size) { + if (NULL == filename || NULL == data || 0 == size) + return -1; + + FILE *fp = fopen(filename, "r"); + if (NULL == fp) { + fprintf(stderr, "Failed to load kernel."); + return -1; + } + + fseek(fp, 0, SEEK_END); + long fsize = ftell(fp); + rewind(fp); + + *data = (uint8_t *)malloc(fsize); + *size = fread(*data, 1, fsize, fp); + + fclose(fp); + + return 0; +} + +static void sgemm_cpu(float *C, const float *A, const float *B, int M, int N, + int K) { + for (int m = 0; m < M; ++m) { + for (int n = 0; n < N; ++n) { + float acc = 0; + for (int k = 0; k < K; ++k) { + acc += A[k * M + m] * B[n * K + k]; + } + C[n * M + m] = acc; + } + } +} + +cl_platform_id platform_id = NULL; +cl_device_id device_id = NULL; +cl_context context = NULL; +cl_command_queue command_queue = NULL; +cl_program program = NULL; +cl_kernel kernel = NULL; +cl_mem a_memobj = NULL; +cl_mem b_memobj = NULL; +cl_mem c_memobj = NULL; +uint8_t *kernel_bin = NULL; + +static void cleanup() { + if (command_queue) + clReleaseCommandQueue(command_queue); + if (kernel) + clReleaseKernel(kernel); + if (program) + clReleaseProgram(program); + if (a_memobj) + clReleaseMemObject(a_memobj); + if (b_memobj) + clReleaseMemObject(b_memobj); + if (c_memobj) + clReleaseMemObject(c_memobj); + if (context) + clReleaseContext(context); + if (device_id) + clReleaseDevice(device_id); + // if (platform_id) + // clReleasePlatform(platform_id); + if (kernel_bin) + free(kernel_bin); +} + +static void parse_args(int argc, char **argv) { + int c; + while ((c = getopt(argc, argv, "n:M:N:K:h?")) != -1) { + switch (c) { + case 'n': + M = N = K = atoi(optarg); + break; + case 'M': + M = atoi(optarg); + break; + case 'N': + N = atoi(optarg); + break; + case 'K': + K = atoi(optarg); + break; + case 'h': + case '?': { + show_usage(); + exit(0); + } break; + default: + show_usage(); + exit(-1); + } + } + + if (M < 2 || N < 2 || K < 2) { + printf("Error: invalid size!\n"); + exit(-1); + } +} + +int main(int argc, char **argv) { + // parse command arguments + parse_args(argc, argv); + //printf("%d", VX_CAPS_NUM_CORES); + +/* + // find device and platform + cl_uint platform_count = 0; + CL_CHECK(clGetPlatformIDs(0, NULL, &platform_count)); + cl_platform_id *platforms = + (cl_platform_id *)malloc(platform_count * sizeof(cl_platform_id)); + if (platforms == NULL) { + printf("Not enough memory"); + cleanup(); + exit(-1); + } + CL_CHECK(clGetPlatformIDs(platform_count, platforms, NULL)); + + bool gpu_device_selected = false; + bool any_device_selected = false; + for (int platform_index = 0; platform_index < (int)platform_count; + ++platform_index) { + cl_platform_id platform = platforms[platform_index]; + cl_uint devices_count = 0; + + CL_CHECK( + clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &devices_count)); + cl_device_id *devices = + (cl_device_id *)malloc(sizeof(cl_device_id) * devices_count); + if (devices == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + CL_CHECK(clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, devices_count, + devices, NULL)); + for (int device_index = 0; device_index < (int)devices_count; ++device_index) { + cl_device_id device = devices[device_index]; + cl_device_type device_type; + CL_CHECK(clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(device_type), + &device_type, NULL)); + + if (device_type & CL_DEVICE_TYPE_GPU) { + gpu_device_selected = true; + any_device_selected = true; + platform_id = platform; + device_id = device; + break; + } + if (device_type & CL_DEVICE_TYPE_CPU) { + any_device_selected = true; + platform_id = platform; + device_id = device; + } + } + if (gpu_device_selected) + break; + } + if (!any_device_selected) { + printf("No device found"); + cleanup(); + return -1; + }*/ + + CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); + CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); + // create context + cl_context_properties context_properties[]{ + CL_CONTEXT_PLATFORM, cl_context_properties(platform_id), 0}; + cl_device_id devices[]{device_id}; + context = CL_CHECK2(clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err)); + + char device_string[1024]; + clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); + printf("Using device: %s\n", device_string); + // create command queue + command_queue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); + + // generate data + float *A, *B, *C; + A = (float *)(malloc(M * K * sizeof(float))); + B = (float *)(malloc(N * K * sizeof(float))); + C = (float *)(malloc(M * N * sizeof(float))); + if (A == NULL || B == NULL || C == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + for (int i = 0; i < M * N; i++) { + A[i] = 1; + B[i] = 1; + } + + // create buffers + a_memobj = + CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, + M * K * sizeof(float), A, &_err)); + b_memobj = + CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, + N * K * sizeof(float), B, &_err)); + c_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, + M * N * sizeof(float), NULL, &_err)); + + // load kernel text + size_t kernel_size; + if (read_kernel_file("kernel.cl", &kernel_bin, &kernel_size) != 0) { + cleanup(); + return -1; + } + program = CL_CHECK2(clCreateProgramWithSource(context, 1, (const char **)&kernel_bin, + &kernel_size, &_err)); + if (program == NULL) { + cleanup(); + return -1; + } + + // build program + cl_int build_status = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); + + // create kernel + kernel = CL_CHECK2(clCreateKernel(program, "myGEMM3", &_err)); + + // check building info + size_t log_size = 0; + CL_CHECK(clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, + NULL, &log_size)); + char *log = (char *)malloc(log_size * sizeof(char)); + if (log == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + CL_CHECK(clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, + log_size, log, NULL)); + if (log_size > 1) { + printf("Log:\n"); + printf("%s", log); + printf("\n"); + } + CL_CHECK(build_status); + + + // set kernel arguments + CL_CHECK(clSetKernelArg(kernel, 0, sizeof(int), &M)); + CL_CHECK(clSetKernelArg(kernel, 1, sizeof(int), &N)); + CL_CHECK(clSetKernelArg(kernel, 2, sizeof(int), &K)); + CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_mem), (void *)&a_memobj)); + CL_CHECK(clSetKernelArg(kernel, 4, sizeof(cl_mem), (void *)&b_memobj)); + CL_CHECK(clSetKernelArg(kernel, 5, sizeof(cl_mem), (void *)&c_memobj)); + + // run kernel + const size_t local[2] = {TS, TS / WPT}; + const size_t global[2] = {M, N / WPT}; + printf("Execute the kernel\n"); + auto time_start = std::chrono::high_resolution_clock::now(); + CL_CHECK(clEnqueueNDRangeKernel(command_queue, kernel, 2, NULL, global, local, + 0, NULL, NULL)); + CL_CHECK(clFinish(command_queue)); + //CL_CHECK(clWaitForEvents(1, &event)); + auto time_end = std::chrono::high_resolution_clock::now(); + double elapsed = std::chrono::duration_cast( + time_end - time_start) + .count(); + printf("Elapsed time: %lg ms\n", elapsed); + + // get results from VRAM + CL_CHECK(clEnqueueReadBuffer(command_queue, c_memobj, CL_TRUE, 0, + M * N * sizeof(float), C, 0, NULL, NULL)); + CL_CHECK(clFinish(command_queue)); + + // verify results + printf("Verify result\n"); + float *C_cpu = (float *)malloc(M * N * sizeof(float)); + if (C_cpu == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + sgemm_cpu(C_cpu, A, B, M, N, K); + int errors = 0; + + for (size_t i = 0; i < size_t(M * N); i++) + if (C_cpu[i] != C[i]) + errors++; + if (errors != 0) + printf("FAILED! - %d errors\n", errors); + else + printf("PASSED!\n"); + + // free resureses + cleanup(); + return errors; +} From 9c2a05773c3e3b8eb654f0eb1762b36c57baa988 Mon Sep 17 00:00:00 2001 From: Ivan Khromov Date: Wed, 24 Jul 2024 15:28:29 +0300 Subject: [PATCH 2/8] Add new kernel --- tests/opencl/kernel4/Makefile | 20 ++ tests/opencl/kernel4/common.h | 7 + tests/opencl/kernel4/kernel.cl | 111 +++++++++++ tests/opencl/kernel4/main.cc | 337 +++++++++++++++++++++++++++++++++ 4 files changed, 475 insertions(+) create mode 100644 tests/opencl/kernel4/Makefile create mode 100644 tests/opencl/kernel4/common.h create mode 100644 tests/opencl/kernel4/kernel.cl create mode 100644 tests/opencl/kernel4/main.cc diff --git a/tests/opencl/kernel4/Makefile b/tests/opencl/kernel4/Makefile new file mode 100644 index 000000000..312ec638d --- /dev/null +++ b/tests/opencl/kernel4/Makefile @@ -0,0 +1,20 @@ +ROOT_DIR := $(realpath ../../..) +include $(ROOT_DIR)/config.mk + +PROJECT := kernel4 + +SRC_DIR := $(VORTEX_HOME)/tests/opencl/$(PROJECT) + +SRCS := $(SRC_DIR)/main.cc + +kernel.cl: $(SRC_DIR)/kernel.cl + cp $< $@ + +common.h: $(SRC_DIR)/common.h + cp $< $@ + +KERNEL_SRCS := kernel.cl common.h + +OPTS ?= + +include ../common.mk diff --git a/tests/opencl/kernel4/common.h b/tests/opencl/kernel4/common.h new file mode 100644 index 000000000..8c390c422 --- /dev/null +++ b/tests/opencl/kernel4/common.h @@ -0,0 +1,7 @@ +#ifndef COMMON_H +#define COMMON_H + +#define TS 16 +#define WIDTH 8 + +#endif // COMMON_H diff --git a/tests/opencl/kernel4/kernel.cl b/tests/opencl/kernel4/kernel.cl new file mode 100644 index 000000000..29ab1ee0d --- /dev/null +++ b/tests/opencl/kernel4/kernel.cl @@ -0,0 +1,111 @@ +#define TS 32 +#define WIDTH 4 + +#if WIDTH == 1 + typedef float floatX; +#elif WIDTH == 2 + typedef float2 floatX; +#elif WIDTH == 4 + typedef float4 floatX; +#elif WIDTH == 8 + typedef float8 floatX; +#endif + +__kernel void myGEMM4(const int M, const int N, const int K, + const __global floatX* A, + const __global floatX* B, + __global floatX* C) { + + // Thread identifiers + const int row = get_local_id(0); // Local row ID (max: TS/WIDTH) + const int col = get_local_id(1); // Local col ID (max: TS) + const int globalRow = (TS/WIDTH)*get_group_id(0) + row; // Row ID of C (0..M/WIDTH) + const int globalCol = TS*get_group_id(1) + col; // Col ID of C (0..N) + + // Local memory to fit a tile of TS*TS elements of A and B + __local floatX Asub[TS][TS/WIDTH]; + __local floatX Bsub[TS][TS/WIDTH]; + + // Initialise the accumulation registers + #if WIDTH == 1 + floatX acc = 0.0f; + #elif WIDTH == 2 + floatX acc = { 0.0f, 0.0f }; + #elif WIDTH == 4 + floatX acc = { 0.0f, 0.0f, 0.0f, 0.0f }; + #elif WIDTH == 8 + floatX acc = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + #endif + + // Loop over all tiles + const int numTiles = K/TS; + for (int tile=0; tile +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +int M = 256, N = 256, K = 256; + +static void show_usage() { + printf("Usage: [-M number of rows in first matrix] [-N number of columns in first matrix] [-K number of columns in first matrix and rows in second matrix] [-h: help]\n"); +} + +#define CL_CHECK(_expr) \ + do { \ + cl_int _err = _expr; \ + if (_err == CL_SUCCESS) \ + break; \ + printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ + cleanup(); \ + exit(-1); \ + } while (0) + +#define CL_CHECK2(_expr) \ + ({ \ + cl_int _err = CL_INVALID_VALUE; \ + decltype(_expr) _ret = _expr; \ + if (_err != CL_SUCCESS) { \ + printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ + cleanup(); \ + exit(-1); \ + } \ + _ret; \ + }) + +static int read_kernel_file(const char *filename, uint8_t **data, + size_t *size) { + if (NULL == filename || NULL == data || 0 == size) + return -1; + + FILE *fp = fopen(filename, "r"); + if (NULL == fp) { + fprintf(stderr, "Failed to load kernel."); + return -1; + } + + fseek(fp, 0, SEEK_END); + long fsize = ftell(fp); + rewind(fp); + + *data = (uint8_t *)malloc(fsize); + *size = fread(*data, 1, fsize, fp); + + fclose(fp); + + return 0; +} + +static void sgemm_cpu(float *C, const float *A, const float *B, int M, int N, + int K) { + for (int m = 0; m < M; ++m) { + for (int n = 0; n < N; ++n) { + float acc = 0; + for (int k = 0; k < K; ++k) { + acc += A[k * M + m] * B[n * K + k]; + } + C[n * M + m] = acc; + } + } +} + +cl_platform_id platform_id = NULL; +cl_device_id device_id = NULL; +cl_context context = NULL; +cl_command_queue command_queue = NULL; +cl_program program = NULL; +cl_kernel kernel = NULL; +cl_mem a_memobj = NULL; +cl_mem b_memobj = NULL; +cl_mem c_memobj = NULL; +uint8_t *kernel_bin = NULL; + +static void cleanup() { + if (command_queue) + clReleaseCommandQueue(command_queue); + if (kernel) + clReleaseKernel(kernel); + if (program) + clReleaseProgram(program); + if (a_memobj) + clReleaseMemObject(a_memobj); + if (b_memobj) + clReleaseMemObject(b_memobj); + if (c_memobj) + clReleaseMemObject(c_memobj); + if (context) + clReleaseContext(context); + if (device_id) + clReleaseDevice(device_id); + // if (platform_id) + // clReleasePlatform(platform_id); + if (kernel_bin) + free(kernel_bin); +} + +static void parse_args(int argc, char **argv) { + int c; + while ((c = getopt(argc, argv, "n:M:N:K:h?")) != -1) { + switch (c) { + case 'n': + M = N = K = atoi(optarg); + break; + case 'M': + M = atoi(optarg); + break; + case 'N': + N = atoi(optarg); + break; + case 'K': + K = atoi(optarg); + break; + case 'h': + case '?': { + show_usage(); + exit(0); + } break; + default: + show_usage(); + exit(-1); + } + } + + if (M < 2 || N < 2 || K < 2) { + printf("Error: invalid size!\n"); + exit(-1); + } +} + +int main(int argc, char **argv) { + // parse command arguments + parse_args(argc, argv); + //printf("%d", VX_CAPS_NUM_CORES); + +/* + // find device and platform + cl_uint platform_count = 0; + CL_CHECK(clGetPlatformIDs(0, NULL, &platform_count)); + cl_platform_id *platforms = + (cl_platform_id *)malloc(platform_count * sizeof(cl_platform_id)); + if (platforms == NULL) { + printf("Not enough memory"); + cleanup(); + exit(-1); + } + CL_CHECK(clGetPlatformIDs(platform_count, platforms, NULL)); + + bool gpu_device_selected = false; + bool any_device_selected = false; + for (int platform_index = 0; platform_index < (int)platform_count; + ++platform_index) { + cl_platform_id platform = platforms[platform_index]; + cl_uint devices_count = 0; + + CL_CHECK( + clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &devices_count)); + cl_device_id *devices = + (cl_device_id *)malloc(sizeof(cl_device_id) * devices_count); + if (devices == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + CL_CHECK(clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, devices_count, + devices, NULL)); + for (int device_index = 0; device_index < (int)devices_count; ++device_index) { + cl_device_id device = devices[device_index]; + cl_device_type device_type; + CL_CHECK(clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(device_type), + &device_type, NULL)); + + if (device_type & CL_DEVICE_TYPE_GPU) { + gpu_device_selected = true; + any_device_selected = true; + platform_id = platform; + device_id = device; + break; + } + if (device_type & CL_DEVICE_TYPE_CPU) { + any_device_selected = true; + platform_id = platform; + device_id = device; + } + } + if (gpu_device_selected) + break; + } + if (!any_device_selected) { + printf("No device found"); + cleanup(); + return -1; + }*/ + + CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); + CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); + // create context + cl_context_properties context_properties[]{ + CL_CONTEXT_PLATFORM, cl_context_properties(platform_id), 0}; + cl_device_id devices[]{device_id}; + context = CL_CHECK2(clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err)); + + char device_string[1024]; + clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); + printf("Using device: %s\n", device_string); + // create command queue + command_queue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); + + // generate data + float *A, *B, *C; + A = (float *)(malloc(M * K * sizeof(float))); + B = (float *)(malloc(N * K * sizeof(float))); + C = (float *)(malloc(M * N * sizeof(float))); + if (A == NULL || B == NULL || C == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + for (int i = 0; i < M * N; i++) { + A[i] = 1; + B[i] = 1; + } + + // create buffers + a_memobj = + CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, + M * K * sizeof(float), A, &_err)); + b_memobj = + CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, + N * K * sizeof(float), B, &_err)); + c_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, + M * N * sizeof(float), NULL, &_err)); + + // load kernel text + size_t kernel_size; + if (read_kernel_file("kernel.cl", &kernel_bin, &kernel_size) != 0) { + cleanup(); + return -1; + } + program = CL_CHECK2(clCreateProgramWithSource(context, 1, (const char **)&kernel_bin, + &kernel_size, &_err)); + if (program == NULL) { + cleanup(); + return -1; + } + + // build program + cl_int build_status = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); + + // create kernel + kernel = CL_CHECK2(clCreateKernel(program, "myGEMM4", &_err)); + + // check building info + size_t log_size = 0; + CL_CHECK(clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, + NULL, &log_size)); + char *log = (char *)malloc(log_size * sizeof(char)); + if (log == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + CL_CHECK(clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, + log_size, log, NULL)); + if (log_size > 1) { + printf("Log:\n"); + printf("%s", log); + printf("\n"); + } + CL_CHECK(build_status); + + + // set kernel arguments + CL_CHECK(clSetKernelArg(kernel, 0, sizeof(int), &M)); + CL_CHECK(clSetKernelArg(kernel, 1, sizeof(int), &N)); + CL_CHECK(clSetKernelArg(kernel, 2, sizeof(int), &K)); + CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_mem), (void *)&a_memobj)); + CL_CHECK(clSetKernelArg(kernel, 4, sizeof(cl_mem), (void *)&b_memobj)); + CL_CHECK(clSetKernelArg(kernel, 5, sizeof(cl_mem), (void *)&c_memobj)); + + // run kernel + const size_t local[2] = {TS / WIDTH, TS}; + const size_t global[2] = {M / WIDTH, N}; + printf("Execute the kernel\n"); + auto time_start = std::chrono::high_resolution_clock::now(); + CL_CHECK(clEnqueueNDRangeKernel(command_queue, kernel, 2, NULL, global, local, + 0, NULL, NULL)); + CL_CHECK(clFinish(command_queue)); + //CL_CHECK(clWaitForEvents(1, &event)); + auto time_end = std::chrono::high_resolution_clock::now(); + double elapsed = std::chrono::duration_cast( + time_end - time_start) + .count(); + printf("Elapsed time: %lg ms\n", elapsed); + + // get results from VRAM + CL_CHECK(clEnqueueReadBuffer(command_queue, c_memobj, CL_TRUE, 0, + M * N * sizeof(float), C, 0, NULL, NULL)); + CL_CHECK(clFinish(command_queue)); + + // verify results + printf("Verify result\n"); + float *C_cpu = (float *)malloc(M * N * sizeof(float)); + if (C_cpu == NULL) { + printf("Not enough memory"); + cleanup(); + return -1; + } + sgemm_cpu(C_cpu, A, B, M, N, K); + int errors = 0; + + for (size_t i = 0; i < size_t(M * N); i++) + if (C_cpu[i] != C[i]) + errors++; + if (errors != 0) + printf("FAILED! - %d errors\n", errors); + else + printf("PASSED!\n"); + + // free resureses + cleanup(); + return errors; +} From 72f2738b00dbb2819d00abe428df7a8de9d8fe59 Mon Sep 17 00:00:00 2001 From: vano105 Date: Wed, 24 Jul 2024 18:22:30 +0300 Subject: [PATCH 3/8] Fix input args function --- tests/opencl/Makefile | 15 --------------- tests/opencl/kernel1/common.h | 6 ++++++ tests/opencl/kernel1/main.cc | 9 +++------ tests/opencl/kernel2/main.cc | 5 +---- tests/opencl/kernel3/common.h | 4 ++-- tests/opencl/kernel4/common.h | 4 ++-- tests/opencl/kernel4/kernel.cl | 3 +-- 7 files changed, 15 insertions(+), 31 deletions(-) create mode 100644 tests/opencl/kernel1/common.h diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index 80cb26ee5..9d05fa158 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -22,9 +22,6 @@ all: $(MAKE) -C sgemm2 $(MAKE) -C sgemm3 $(MAKE) -C psum - $(MAKE) -C kernel1 - $(MAKE) -C kernel2 - $(MAKE) -C kernel3 run-simx: $(MAKE) -C vecadd run-simx @@ -46,9 +43,6 @@ run-simx: $(MAKE) -C sgemm2 run-simx $(MAKE) -C sgemm3 run-simx $(MAKE) -C psum run-simx - $(MAKE) -C kernel1 run-simx - $(MAKE) -C kernel2 run-simx - $(MAKE) -C kernel3 run-simx run-rtlsim: $(MAKE) -C vecadd run-rtlsim @@ -70,9 +64,6 @@ run-rtlsim: $(MAKE) -C sgemm2 run-rtlsim $(MAKE) -C sgemm3 run-rtlsim $(MAKE) -C psum run-rtlsim - $(MAKE) -C kernel1 run-rtlsim - $(MAKE) -C kernel2 run-rtlsim - $(MAKE) -C kernel3 run-rtlsim run-opae: $(MAKE) -C vecadd run-opae @@ -94,9 +85,6 @@ run-opae: $(MAKE) -C sgemm2 run-opae $(MAKE) -C sgemm3 run-opae $(MAKE) -C psum run-opae - $(MAKE) -C kernel1 run-opae - $(MAKE) -C kernel2 run-opae - $(MAKE) -C kernel3 run-opae clean: $(MAKE) -C vecadd clean @@ -119,6 +107,3 @@ clean: $(MAKE) -C sgemm2 clean $(MAKE) -C sgemm3 clean $(MAKE) -C psum clean - $(MAKE) -C kernel1 clean - $(MAKE) -C kernel2 clean - $(MAKE) -C kernel3 clean diff --git a/tests/opencl/kernel1/common.h b/tests/opencl/kernel1/common.h new file mode 100644 index 000000000..e51835d3c --- /dev/null +++ b/tests/opencl/kernel1/common.h @@ -0,0 +1,6 @@ +#ifndef COMMON_H +#define COMMON_H + +#define TS 4 + +#endif // COMMON_H \ No newline at end of file diff --git a/tests/opencl/kernel1/main.cc b/tests/opencl/kernel1/main.cc index 7de0a9b3c..1682113ff 100644 --- a/tests/opencl/kernel1/main.cc +++ b/tests/opencl/kernel1/main.cc @@ -9,7 +9,7 @@ #include #include -int TS = 0; +int TS = 4; int M = 0, N = 0, K = 0; static void show_usage() { @@ -110,11 +110,8 @@ static void cleanup() { static void parse_args(int argc, char **argv) { int c; - while ((c = getopt(argc, argv, "T:n:M:N:K:h?")) != -1) { + while ((c = getopt(argc, argv, "n:M:N:K:h?")) != -1) { switch (c) { - case 'T': - TS = atoi(optarg); - break; case 'n': M = N = K = atoi(optarg); break; @@ -336,4 +333,4 @@ int main(int argc, char **argv) { // free resureses cleanup(); return errors; -} \ No newline at end of file +} diff --git a/tests/opencl/kernel2/main.cc b/tests/opencl/kernel2/main.cc index af29f1c10..fcd5caedf 100644 --- a/tests/opencl/kernel2/main.cc +++ b/tests/opencl/kernel2/main.cc @@ -111,11 +111,8 @@ static void cleanup() { static void parse_args(int argc, char **argv) { int c; - while ((c = getopt(argc, argv, "T:n:M:N:K:h?")) != -1) { + while ((c = getopt(argc, argv, "n:M:N:K:h?")) != -1) { switch (c) { - case 'T': - TS = atoi(optarg); - break; case 'n': M = N = K = atoi(optarg); break; diff --git a/tests/opencl/kernel3/common.h b/tests/opencl/kernel3/common.h index 7ab67c5b2..fda664acb 100644 --- a/tests/opencl/kernel3/common.h +++ b/tests/opencl/kernel3/common.h @@ -1,8 +1,8 @@ #ifndef COMMON_H #define COMMON_H -#define TS 16 -#define WPT 8 +#define TS 8 +#define WPT 4 #define RTS (TS/WPT) #endif // COMMON_H diff --git a/tests/opencl/kernel4/common.h b/tests/opencl/kernel4/common.h index 8c390c422..f304fa17e 100644 --- a/tests/opencl/kernel4/common.h +++ b/tests/opencl/kernel4/common.h @@ -1,7 +1,7 @@ #ifndef COMMON_H #define COMMON_H -#define TS 16 -#define WIDTH 8 +#define TS 8 +#define WIDTH 4 #endif // COMMON_H diff --git a/tests/opencl/kernel4/kernel.cl b/tests/opencl/kernel4/kernel.cl index 29ab1ee0d..179789d97 100644 --- a/tests/opencl/kernel4/kernel.cl +++ b/tests/opencl/kernel4/kernel.cl @@ -1,5 +1,4 @@ -#define TS 32 -#define WIDTH 4 +#include "common.h" #if WIDTH == 1 typedef float floatX; From 0777e5dd4896dc9ef5b5a3a16bf26ac374a3172c Mon Sep 17 00:00:00 2001 From: vano105 Date: Tue, 30 Jul 2024 16:12:23 +0300 Subject: [PATCH 4/8] clean code --- tests/opencl/Makefile | 20 +++++++++ tests/opencl/kernel1/main.cc | 83 +++++++---------------------------- tests/opencl/kernel2/main.cc | 80 ++++++--------------------------- tests/opencl/kernel3/common.h | 6 +-- tests/opencl/kernel3/main.cc | 80 ++++++--------------------------- tests/opencl/kernel4/common.h | 2 +- tests/opencl/kernel4/main.cc | 80 ++++++--------------------------- 7 files changed, 78 insertions(+), 273 deletions(-) diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index 9d05fa158..a2c479784 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -22,6 +22,10 @@ all: $(MAKE) -C sgemm2 $(MAKE) -C sgemm3 $(MAKE) -C psum + $(MAKE) -C kernel1 + $(MAKE) -C kernel2 + $(MAKE) -C kernel3 + $(MAKE) -C kernel4 run-simx: $(MAKE) -C vecadd run-simx @@ -43,6 +47,10 @@ run-simx: $(MAKE) -C sgemm2 run-simx $(MAKE) -C sgemm3 run-simx $(MAKE) -C psum run-simx + $(MAKE) -C kernel1 run-simx + $(MAKE) -C kernel2 run-simx + $(MAKE) -C kernel3 run-simx + $(MAKE) -C kernel4 run-simx run-rtlsim: $(MAKE) -C vecadd run-rtlsim @@ -64,6 +72,10 @@ run-rtlsim: $(MAKE) -C sgemm2 run-rtlsim $(MAKE) -C sgemm3 run-rtlsim $(MAKE) -C psum run-rtlsim + $(MAKE) -C kernel1 run-rtlsimy + $(MAKE) -C kernel2 run-rtlsimy + $(MAKE) -C kernel3 run-rtlsimy + $(MAKE) -C kernel4 run-rtlsimy run-opae: $(MAKE) -C vecadd run-opae @@ -85,6 +97,10 @@ run-opae: $(MAKE) -C sgemm2 run-opae $(MAKE) -C sgemm3 run-opae $(MAKE) -C psum run-opae + $(MAKE) -C kernel1 run-opae + $(MAKE) -C kernel2 run-opae + $(MAKE) -C kernel3 run-opae + $(MAKE) -C kernel4 run-opae clean: $(MAKE) -C vecadd clean @@ -107,3 +123,7 @@ clean: $(MAKE) -C sgemm2 clean $(MAKE) -C sgemm3 clean $(MAKE) -C psum clean + $(MAKE) -C kernel1 clean + $(MAKE) -C kernel2 clean + $(MAKE) -C kernel3 clean + $(MAKE) -C kernel4 clean diff --git a/tests/opencl/kernel1/main.cc b/tests/opencl/kernel1/main.cc index 1682113ff..2fa9da0ed 100644 --- a/tests/opencl/kernel1/main.cc +++ b/tests/opencl/kernel1/main.cc @@ -9,7 +9,8 @@ #include #include -int TS = 4; +#include "common.h" + int M = 0, N = 0, K = 0; static void show_usage() { @@ -102,8 +103,6 @@ static void cleanup() { clReleaseContext(context); if (device_id) clReleaseDevice(device_id); - // if (platform_id) - // clReleasePlatform(platform_id); if (kernel_bin) free(kernel_bin); } @@ -144,69 +143,10 @@ static void parse_args(int argc, char **argv) { int main(int argc, char **argv) { // parse command arguments parse_args(argc, argv); - //printf("%d", VX_CAPS_NUM_CORES); - -/* - // find device and platform - cl_uint platform_count = 0; - CL_CHECK(clGetPlatformIDs(0, NULL, &platform_count)); - cl_platform_id *platforms = - (cl_platform_id *)malloc(platform_count * sizeof(cl_platform_id)); - if (platforms == NULL) { - printf("Not enough memory"); - cleanup(); - exit(-1); - } - CL_CHECK(clGetPlatformIDs(platform_count, platforms, NULL)); - - bool gpu_device_selected = false; - bool any_device_selected = false; - for (int platform_index = 0; platform_index < (int)platform_count; - ++platform_index) { - cl_platform_id platform = platforms[platform_index]; - cl_uint devices_count = 0; - - CL_CHECK( - clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &devices_count)); - cl_device_id *devices = - (cl_device_id *)malloc(sizeof(cl_device_id) * devices_count); - if (devices == NULL) { - printf("Not enough memory"); - cleanup(); - return -1; - } - CL_CHECK(clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, devices_count, - devices, NULL)); - for (int device_index = 0; device_index < (int)devices_count; ++device_index) { - cl_device_id device = devices[device_index]; - cl_device_type device_type; - CL_CHECK(clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(device_type), - &device_type, NULL)); - - if (device_type & CL_DEVICE_TYPE_GPU) { - gpu_device_selected = true; - any_device_selected = true; - platform_id = platform; - device_id = device; - break; - } - if (device_type & CL_DEVICE_TYPE_CPU) { - any_device_selected = true; - platform_id = platform; - device_id = device; - } - } - if (gpu_device_selected) - break; - } - if (!any_device_selected) { - printf("No device found"); - cleanup(); - return -1; - }*/ CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); + // create context cl_context_properties context_properties[]{ CL_CONTEXT_PLATFORM, cl_context_properties(platform_id), 0}; @@ -216,10 +156,11 @@ int main(int argc, char **argv) { char device_string[1024]; clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); printf("Using device: %s\n", device_string); + // create command queue command_queue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); - // generate data + // generate input data float *A, *B, *C; A = (float *)(malloc(M * K * sizeof(float))); B = (float *)(malloc(N * K * sizeof(float))); @@ -229,10 +170,11 @@ int main(int argc, char **argv) { cleanup(); return -1; } - for (int i = 0; i < M * N; i++) { - A[i] = 1; - B[i] = 1; - } + srand(time(NULL)); + for (int i = 0; i < M * K; i++) + A[i] = (int)((float)rand() / (float)RAND_MAX); + for (int i = 0; i < N * K; i++) + B[i] = (int)((float)rand() / (float)RAND_MAX); // create buffers a_memobj = @@ -332,5 +274,10 @@ int main(int argc, char **argv) { // free resureses cleanup(); + free(A); + free(B); + free(C); + free(log); + free(C_cpu); return errors; } diff --git a/tests/opencl/kernel2/main.cc b/tests/opencl/kernel2/main.cc index fcd5caedf..933420964 100644 --- a/tests/opencl/kernel2/main.cc +++ b/tests/opencl/kernel2/main.cc @@ -103,8 +103,6 @@ static void cleanup() { clReleaseContext(context); if (device_id) clReleaseDevice(device_id); - // if (platform_id) - // clReleasePlatform(platform_id); if (kernel_bin) free(kernel_bin); } @@ -145,69 +143,10 @@ static void parse_args(int argc, char **argv) { int main(int argc, char **argv) { // parse command arguments parse_args(argc, argv); - //printf("%d", VX_CAPS_NUM_CORES); - -/* - // find device and platform - cl_uint platform_count = 0; - CL_CHECK(clGetPlatformIDs(0, NULL, &platform_count)); - cl_platform_id *platforms = - (cl_platform_id *)malloc(platform_count * sizeof(cl_platform_id)); - if (platforms == NULL) { - printf("Not enough memory"); - cleanup(); - exit(-1); - } - CL_CHECK(clGetPlatformIDs(platform_count, platforms, NULL)); - - bool gpu_device_selected = false; - bool any_device_selected = false; - for (int platform_index = 0; platform_index < (int)platform_count; - ++platform_index) { - cl_platform_id platform = platforms[platform_index]; - cl_uint devices_count = 0; - - CL_CHECK( - clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &devices_count)); - cl_device_id *devices = - (cl_device_id *)malloc(sizeof(cl_device_id) * devices_count); - if (devices == NULL) { - printf("Not enough memory"); - cleanup(); - return -1; - } - CL_CHECK(clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, devices_count, - devices, NULL)); - for (int device_index = 0; device_index < (int)devices_count; ++device_index) { - cl_device_id device = devices[device_index]; - cl_device_type device_type; - CL_CHECK(clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(device_type), - &device_type, NULL)); - - if (device_type & CL_DEVICE_TYPE_GPU) { - gpu_device_selected = true; - any_device_selected = true; - platform_id = platform; - device_id = device; - break; - } - if (device_type & CL_DEVICE_TYPE_CPU) { - any_device_selected = true; - platform_id = platform; - device_id = device; - } - } - if (gpu_device_selected) - break; - } - if (!any_device_selected) { - printf("No device found"); - cleanup(); - return -1; - }*/ CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); + // create context cl_context_properties context_properties[]{ CL_CONTEXT_PLATFORM, cl_context_properties(platform_id), 0}; @@ -217,10 +156,11 @@ int main(int argc, char **argv) { char device_string[1024]; clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); printf("Using device: %s\n", device_string); + // create command queue command_queue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); - // generate data + // generate input data float *A, *B, *C; A = (float *)(malloc(M * K * sizeof(float))); B = (float *)(malloc(N * K * sizeof(float))); @@ -230,10 +170,11 @@ int main(int argc, char **argv) { cleanup(); return -1; } - for (int i = 0; i < M * N; i++) { - A[i] = 1; - B[i] = 1; - } + srand(time(NULL)); + for (int i = 0; i < M * K; i++) + A[i] = (int)((float)rand() / (float)RAND_MAX); + for (int i = 0; i < N * K; i++) + B[i] = (int)((float)rand() / (float)RAND_MAX); // create buffers a_memobj = @@ -333,5 +274,10 @@ int main(int argc, char **argv) { // free resureses cleanup(); + free(A); + free(B); + free(C); + free(log); + free(C_cpu); return errors; } \ No newline at end of file diff --git a/tests/opencl/kernel3/common.h b/tests/opencl/kernel3/common.h index fda664acb..c922a82eb 100644 --- a/tests/opencl/kernel3/common.h +++ b/tests/opencl/kernel3/common.h @@ -1,8 +1,8 @@ #ifndef COMMON_H #define COMMON_H -#define TS 8 +#define TS 4 #define WPT 4 -#define RTS (TS/WPT) +#define RTS (TS/WPT) -#endif // COMMON_H +#endif // COMMON_H \ No newline at end of file diff --git a/tests/opencl/kernel3/main.cc b/tests/opencl/kernel3/main.cc index 88a942991..8097aaf12 100644 --- a/tests/opencl/kernel3/main.cc +++ b/tests/opencl/kernel3/main.cc @@ -103,8 +103,6 @@ static void cleanup() { clReleaseContext(context); if (device_id) clReleaseDevice(device_id); - // if (platform_id) - // clReleasePlatform(platform_id); if (kernel_bin) free(kernel_bin); } @@ -145,69 +143,10 @@ static void parse_args(int argc, char **argv) { int main(int argc, char **argv) { // parse command arguments parse_args(argc, argv); - //printf("%d", VX_CAPS_NUM_CORES); - -/* - // find device and platform - cl_uint platform_count = 0; - CL_CHECK(clGetPlatformIDs(0, NULL, &platform_count)); - cl_platform_id *platforms = - (cl_platform_id *)malloc(platform_count * sizeof(cl_platform_id)); - if (platforms == NULL) { - printf("Not enough memory"); - cleanup(); - exit(-1); - } - CL_CHECK(clGetPlatformIDs(platform_count, platforms, NULL)); - - bool gpu_device_selected = false; - bool any_device_selected = false; - for (int platform_index = 0; platform_index < (int)platform_count; - ++platform_index) { - cl_platform_id platform = platforms[platform_index]; - cl_uint devices_count = 0; - - CL_CHECK( - clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &devices_count)); - cl_device_id *devices = - (cl_device_id *)malloc(sizeof(cl_device_id) * devices_count); - if (devices == NULL) { - printf("Not enough memory"); - cleanup(); - return -1; - } - CL_CHECK(clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, devices_count, - devices, NULL)); - for (int device_index = 0; device_index < (int)devices_count; ++device_index) { - cl_device_id device = devices[device_index]; - cl_device_type device_type; - CL_CHECK(clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(device_type), - &device_type, NULL)); - - if (device_type & CL_DEVICE_TYPE_GPU) { - gpu_device_selected = true; - any_device_selected = true; - platform_id = platform; - device_id = device; - break; - } - if (device_type & CL_DEVICE_TYPE_CPU) { - any_device_selected = true; - platform_id = platform; - device_id = device; - } - } - if (gpu_device_selected) - break; - } - if (!any_device_selected) { - printf("No device found"); - cleanup(); - return -1; - }*/ CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); + // create context cl_context_properties context_properties[]{ CL_CONTEXT_PLATFORM, cl_context_properties(platform_id), 0}; @@ -217,10 +156,11 @@ int main(int argc, char **argv) { char device_string[1024]; clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); printf("Using device: %s\n", device_string); + // create command queue command_queue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); - // generate data + // generate input data float *A, *B, *C; A = (float *)(malloc(M * K * sizeof(float))); B = (float *)(malloc(N * K * sizeof(float))); @@ -230,10 +170,11 @@ int main(int argc, char **argv) { cleanup(); return -1; } - for (int i = 0; i < M * N; i++) { - A[i] = 1; - B[i] = 1; - } + srand(time(NULL)); + for (int i = 0; i < M * K; i++) + A[i] = (int)((float)rand() / (float)RAND_MAX); + for (int i = 0; i < N * K; i++) + B[i] = (int)((float)rand() / (float)RAND_MAX); // create buffers a_memobj = @@ -333,5 +274,10 @@ int main(int argc, char **argv) { // free resureses cleanup(); + free(A); + free(B); + free(C); + free(log); + free(C_cpu); return errors; } diff --git a/tests/opencl/kernel4/common.h b/tests/opencl/kernel4/common.h index f304fa17e..3ed810585 100644 --- a/tests/opencl/kernel4/common.h +++ b/tests/opencl/kernel4/common.h @@ -4,4 +4,4 @@ #define TS 8 #define WIDTH 4 -#endif // COMMON_H +#endif // COMMON_H \ No newline at end of file diff --git a/tests/opencl/kernel4/main.cc b/tests/opencl/kernel4/main.cc index 6b46af4fb..780541652 100644 --- a/tests/opencl/kernel4/main.cc +++ b/tests/opencl/kernel4/main.cc @@ -103,8 +103,6 @@ static void cleanup() { clReleaseContext(context); if (device_id) clReleaseDevice(device_id); - // if (platform_id) - // clReleasePlatform(platform_id); if (kernel_bin) free(kernel_bin); } @@ -145,69 +143,10 @@ static void parse_args(int argc, char **argv) { int main(int argc, char **argv) { // parse command arguments parse_args(argc, argv); - //printf("%d", VX_CAPS_NUM_CORES); - -/* - // find device and platform - cl_uint platform_count = 0; - CL_CHECK(clGetPlatformIDs(0, NULL, &platform_count)); - cl_platform_id *platforms = - (cl_platform_id *)malloc(platform_count * sizeof(cl_platform_id)); - if (platforms == NULL) { - printf("Not enough memory"); - cleanup(); - exit(-1); - } - CL_CHECK(clGetPlatformIDs(platform_count, platforms, NULL)); - - bool gpu_device_selected = false; - bool any_device_selected = false; - for (int platform_index = 0; platform_index < (int)platform_count; - ++platform_index) { - cl_platform_id platform = platforms[platform_index]; - cl_uint devices_count = 0; - - CL_CHECK( - clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &devices_count)); - cl_device_id *devices = - (cl_device_id *)malloc(sizeof(cl_device_id) * devices_count); - if (devices == NULL) { - printf("Not enough memory"); - cleanup(); - return -1; - } - CL_CHECK(clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, devices_count, - devices, NULL)); - for (int device_index = 0; device_index < (int)devices_count; ++device_index) { - cl_device_id device = devices[device_index]; - cl_device_type device_type; - CL_CHECK(clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(device_type), - &device_type, NULL)); - - if (device_type & CL_DEVICE_TYPE_GPU) { - gpu_device_selected = true; - any_device_selected = true; - platform_id = platform; - device_id = device; - break; - } - if (device_type & CL_DEVICE_TYPE_CPU) { - any_device_selected = true; - platform_id = platform; - device_id = device; - } - } - if (gpu_device_selected) - break; - } - if (!any_device_selected) { - printf("No device found"); - cleanup(); - return -1; - }*/ CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); + // create context cl_context_properties context_properties[]{ CL_CONTEXT_PLATFORM, cl_context_properties(platform_id), 0}; @@ -217,10 +156,11 @@ int main(int argc, char **argv) { char device_string[1024]; clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); printf("Using device: %s\n", device_string); + // create command queue command_queue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); - // generate data + // generate input data float *A, *B, *C; A = (float *)(malloc(M * K * sizeof(float))); B = (float *)(malloc(N * K * sizeof(float))); @@ -230,10 +170,11 @@ int main(int argc, char **argv) { cleanup(); return -1; } - for (int i = 0; i < M * N; i++) { - A[i] = 1; - B[i] = 1; - } + srand(time(NULL)); + for (int i = 0; i < M * K; i++) + A[i] = (int)((float)rand() / (float)RAND_MAX); + for (int i = 0; i < N * K; i++) + B[i] = (int)((float)rand() / (float)RAND_MAX); // create buffers a_memobj = @@ -333,5 +274,10 @@ int main(int argc, char **argv) { // free resureses cleanup(); + free(A); + free(B); + free(C); + free(log); + free(C_cpu); return errors; } From 03630ad4ba19ac69832016106d2eda40d53bf846 Mon Sep 17 00:00:00 2001 From: vano105 Date: Tue, 30 Jul 2024 16:25:38 +0300 Subject: [PATCH 5/8] Add jupiter notebook --- tests/opencl/j_stat/graphics/graph.png | Bin 0 -> 19710 bytes tests/opencl/j_stat/output.txt | 17 ++ tests/opencl/j_stat/perf.txt | 3 + tests/opencl/j_stat/statistic.ipynb | 249 +++++++++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 tests/opencl/j_stat/graphics/graph.png create mode 100644 tests/opencl/j_stat/output.txt create mode 100644 tests/opencl/j_stat/perf.txt create mode 100644 tests/opencl/j_stat/statistic.ipynb diff --git a/tests/opencl/j_stat/graphics/graph.png b/tests/opencl/j_stat/graphics/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..1545b8a69df0d1f06fdee04dcb72e824531cfc05 GIT binary patch literal 19710 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 P-4whk;7t6fOMm str:\n", + " return f\"error in running in {run_params.kernel} : warps={run_params.arch.warps} cores={run_params.arch.cores} threads={run_params.arch.threads}\" \\\n", + " f\" driver={run_params.driver} args=-N{run_params.args['N']} -M{run_params.args['M']} -K{run_params.args['K']} error message - {error_text}/n\"" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def error_verification (run_params: run, number_of_errors: str) -> str:\n", + " return f\"error in verifing results {run_params.kernel} : warps={run_params.arch.warps} cores={run_params.arch.cores} threads={run_params.arch.threads}\" \\\n", + " f\" driver={run_params.driver} args=-N{run_params.args['N']} -M{run_params.args['M']} -K{run_params.args['K']} Number of errors : {number_of_errors}'\\n'\" " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "def create_common_h (params: dict, kernel_name: str):\n", + " file_name = f\"{path_to_vortex}/tests/opencl/{kernel_name}/common.h\"\n", + " with open(file_name, 'w') as file:\n", + " text = \"#ifndef COMMON_H\\n\" + \"#define COMMON_H\\n\" + \"\\n\" \n", + " if tile_size in params:\n", + " text += f\"#define TS {params[tile_size]}\\n\"\n", + " if work_per_thread in params:\n", + " text += f\"#define WPT {params[work_per_thread]}\\n\"\n", + " text += \"#define RTS (TS/WPT)\\n\"\n", + " if width in params:\n", + " text += f\"#define WIDTH {params[width]}\\n\"\n", + " text += '\\n' + \"#endif // COMMON_H\"\n", + " file.write(text)\n", + " # open main.cc file to recompile before run with new common.h\n", + " with open(f\"{path_to_vortex}/tests/opencl/{kernel_name}/main.cc\", 'a') as main:\n", + " main.write('')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def perf (run_params: run, path_to_output_file: str) -> pd.DataFrame:\n", + " # run kernel\n", + " vortex = f\"--warps={run_params.arch.warps} --cores={run_params.arch.cores} --threads={run_params.arch.threads}\"\n", + " run_args = f\"-N{run_params.args['N']} -M{run_params.args['M']} -K{run_params.args['K']}\"\n", + " command = f\"cd {path_to_vortex}/build && ./ci/blackbox.sh {vortex} --driver={run_params.driver} --app={run_params.kernel} --args=\\\"{run_args}\\\"\"\n", + " print(command)\n", + " subprocess.call(f\"{command} > {path_to_output_file}\", shell=True)\n", + "\n", + " # collect statistic \n", + " with open(path_to_output_file, 'r') as file:\n", + " lines = file.readlines()\n", + " error_message = \"\"\n", + " general_perf_stat = \"\"\n", + " for line in lines:\n", + " if \"PERF:\" in line:\n", + " general_perf_stat = line\n", + " # check for errors\n", + " if \"FAILED\" in line: \n", + " error_message = error_verification(run_params, line[line.find(\"FAILED! - \"):])\n", + " if \"Error\" in line:\n", + " error_message = error_running(run_params, line[line.find(\"Error:\"):])\n", + " # pars string with general perf statistic of running kernel\n", + " pairs = general_perf_stat.replace(\"PERF: \", \"\").split(\", \")\n", + " perf_dict = {key_value.split(\"=\")[0]: float(key_value.split(\"=\")[1]) for key_value in pairs}\n", + " if perf_dict[\"cycles\"] <= 0:\n", + " error_message = error_running(run_params, \"Invalid number of cycles\")\n", + " # write result to data frame\n", + " run_result = pd.DataFrame([{\"kernel\": run_params.kernel[-1], \"driver\": run_params.driver, \"cores\": run_params.arch.cores, \n", + " \"warps\": run_params.arch.warps, \"threads\": run_params.arch.threads, \"M\": run_params.args[\"M\"], \n", + " \"N\": run_params.args[\"N\"], \"K\": run_params.args[\"K\"], \"instrs\": perf_dict[\"instrs\"], \"cycles\": perf_dict[\"cycles\"],\n", + " \"IPC\": perf_dict[\"IPC\"], \"error\": error_message}])\n", + " return run_result" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def draw (data_frame: pd.DataFrame, x_label: str, y_label: str, title: str, path: str):\n", + " data_frame.plot(kind = \"bar\", x = x_label, y = y_label)\n", + " plt.title(title)\n", + " plt.xlabel(x_label)\n", + " plt.ylabel(y_label)\n", + " plt.savefig(path)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " 0%| | 0/4 [00:00 37\u001b[0m data_frames\u001b[38;5;241m.\u001b[39mappend(\u001b[43mperf\u001b[49m\u001b[43m(\u001b[49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moutput_file\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[1;32m 38\u001b[0m data_frame \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mconcat(data_frames, ignore_index\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[1;32m 40\u001b[0m \u001b[38;5;66;03m# draw graph based on the recived statistic\u001b[39;00m\n", + "Cell \u001b[0;32mIn[7], line 10\u001b[0m, in \u001b[0;36mperf\u001b[0;34m(run_params, path_to_output_file)\u001b[0m\n\u001b[1;32m 7\u001b[0m subprocess\u001b[38;5;241m.\u001b[39mcall(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m > \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mpath_to_output_file\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m, shell\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[1;32m 9\u001b[0m \u001b[38;5;66;03m# collect statistic \u001b[39;00m\n\u001b[0;32m---> 10\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28;43mopen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mpath_to_output_file\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mr\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m file:\n\u001b[1;32m 11\u001b[0m lines \u001b[38;5;241m=\u001b[39m file\u001b[38;5;241m.\u001b[39mreadlines()\n\u001b[1;32m 12\u001b[0m error_message \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", + "File \u001b[0;32m~/.pyenv/versions/3.11.9/lib/python3.11/site-packages/IPython/core/interactiveshell.py:324\u001b[0m, in \u001b[0;36m_modified_open\u001b[0;34m(file, *args, **kwargs)\u001b[0m\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m file \u001b[38;5;129;01min\u001b[39;00m {\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m}:\n\u001b[1;32m 318\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 319\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIPython won\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt let you open fd=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfile\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m by default \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 320\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mas it is likely to crash IPython. If you know what you are doing, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 321\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124myou can use builtins\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m open.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 322\u001b[0m )\n\u001b[0;32m--> 324\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mio_open\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfile\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[0;31mIsADirectoryError\u001b[0m: [Errno 21] Is a directory: '/home/jblab/ivan_khromov/release/vortex/tests/opencl/j_stat'" + ] + } + ], + "source": [ + "# create common.h files for each kernel\n", + "params1 = {\n", + " tile_size: 4\n", + "}\n", + "create_common_h(params1, \"kernel1\")\n", + "create_common_h(params1, \"kernel2\")\n", + "\n", + "params3 = {\n", + " tile_size: 4,\n", + " work_per_thread: 4\n", + "}\n", + "create_common_h(params3, \"kernel3\")\n", + "\n", + "params4 = {\n", + " tile_size: 8,\n", + " width: 4\n", + "}\n", + "create_common_h(params4, \"kernel4\")\n", + "\n", + "# fill running params data class for each kernel\n", + "run_p = []\n", + "arg = {\n", + " \"M\": 16,\n", + " \"N\": 16,\n", + " \"K\": 16\n", + "}\n", + "arch_p = arch(threads=4, cores=4, warps=4)\n", + "run_p.append(run(arch_p, kernel=\"kernel1\", driver=\"simx\", args=arg))\n", + "run_p.append(run(arch_p, kernel=\"kernel2\", driver=\"simx\", args=arg))\n", + "run_p.append(run(arch_p, kernel=\"kernel3\", driver=\"simx\", args=arg))\n", + "run_p.append(run(arch_p, kernel=\"kernel4\", driver=\"simx\", args=arg))\n", + "\n", + "# run all kernels and collect statistic in data frame\n", + "data_frames = []\n", + "output_file = f\"{path_to_vortex}/tests/opencl/j_stat/output.txt\"\n", + "for params in tqdm(run_p):\n", + " data_frames.append(perf(params, output_file))\n", + "data_frame = pd.concat(data_frames, ignore_index=True)\n", + "\n", + "# draw graph based on the recived statistic\n", + "draw(data_frame, \"kernel\", \"cycles\", \"number of cycles per kernel\", \"graphics/graph.png\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From e004fb82aa29359f4f102b6b6df8b9e8058f1cf9 Mon Sep 17 00:00:00 2001 From: vano105 Date: Tue, 30 Jul 2024 16:32:36 +0300 Subject: [PATCH 6/8] Remove graph from j_stat --- tests/opencl/j_stat/graphics/graph.png | Bin 19710 -> 0 bytes tests/opencl/j_stat/statistic.ipynb | 87 +++++++++++++++++++------ 2 files changed, 66 insertions(+), 21 deletions(-) delete mode 100644 tests/opencl/j_stat/graphics/graph.png diff --git a/tests/opencl/j_stat/graphics/graph.png b/tests/opencl/j_stat/graphics/graph.png deleted file mode 100644 index 1545b8a69df0d1f06fdee04dcb72e824531cfc05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19710 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 P-4whk;7t6fOMm 37\u001b[0m data_frames\u001b[38;5;241m.\u001b[39mappend(\u001b[43mperf\u001b[49m\u001b[43m(\u001b[49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moutput_file\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[1;32m 38\u001b[0m data_frame \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mconcat(data_frames, ignore_index\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[1;32m 40\u001b[0m \u001b[38;5;66;03m# draw graph based on the recived statistic\u001b[39;00m\n", - "Cell \u001b[0;32mIn[7], line 10\u001b[0m, in \u001b[0;36mperf\u001b[0;34m(run_params, path_to_output_file)\u001b[0m\n\u001b[1;32m 7\u001b[0m subprocess\u001b[38;5;241m.\u001b[39mcall(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m > \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mpath_to_output_file\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m, shell\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[1;32m 9\u001b[0m \u001b[38;5;66;03m# collect statistic \u001b[39;00m\n\u001b[0;32m---> 10\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28;43mopen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mpath_to_output_file\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mr\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m file:\n\u001b[1;32m 11\u001b[0m lines \u001b[38;5;241m=\u001b[39m file\u001b[38;5;241m.\u001b[39mreadlines()\n\u001b[1;32m 12\u001b[0m error_message \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", - "File \u001b[0;32m~/.pyenv/versions/3.11.9/lib/python3.11/site-packages/IPython/core/interactiveshell.py:324\u001b[0m, in \u001b[0;36m_modified_open\u001b[0;34m(file, *args, **kwargs)\u001b[0m\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m file \u001b[38;5;129;01min\u001b[39;00m {\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m}:\n\u001b[1;32m 318\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 319\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIPython won\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt let you open fd=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfile\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m by default \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 320\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mas it is likely to crash IPython. If you know what you are doing, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 321\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124myou can use builtins\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m open.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 322\u001b[0m )\n\u001b[0;32m--> 324\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mio_open\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfile\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[0;31mIsADirectoryError\u001b[0m: [Errno 21] Is a directory: '/home/jblab/ivan_khromov/release/vortex/tests/opencl/j_stat'" + "name": "stderr", + "output_type": "stream", + "text": [ + " 25%|██▌ | 1/4 [00:00<00:02, 1.12it/s]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cd /home/jblab/ivan_khromov/release/vortex/build && ./ci/blackbox.sh --warps=4 --cores=4 --threads=4 --driver=simx --app=kernel2 --args=\"-N16 -M16 -K16\"\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " 50%|█████ | 2/4 [00:01<00:01, 1.14it/s]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cd /home/jblab/ivan_khromov/release/vortex/build && ./ci/blackbox.sh --warps=4 --cores=4 --threads=4 --driver=simx --app=kernel3 --args=\"-N16 -M16 -K16\"\n" ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " 75%|███████▌ | 3/4 [00:02<00:00, 1.13it/s]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cd /home/jblab/ivan_khromov/release/vortex/build && ./ci/blackbox.sh --warps=4 --cores=4 --threads=4 --driver=simx --app=kernel4 --args=\"-N16 -M16 -K16\"\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|██████████| 4/4 [00:03<00:00, 1.14it/s]\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ From 7dfaec3598fb0276b2caa20f0faf2f70b3760e42 Mon Sep 17 00:00:00 2001 From: vano105 Date: Tue, 30 Jul 2024 16:39:00 +0300 Subject: [PATCH 7/8] Delete output file in j_stat --- tests/opencl/j_stat/output.txt | 17 ----------------- tests/opencl/j_stat/perf.txt | 3 --- 2 files changed, 20 deletions(-) delete mode 100644 tests/opencl/j_stat/output.txt delete mode 100644 tests/opencl/j_stat/perf.txt diff --git a/tests/opencl/j_stat/output.txt b/tests/opencl/j_stat/output.txt deleted file mode 100644 index 927dea2c4..000000000 --- a/tests/opencl/j_stat/output.txt +++ /dev/null @@ -1,17 +0,0 @@ -CONFIGS=-DNUM_CLUSTERS=1 -DNUM_CORES=4 -DNUM_WARPS=4 -DNUM_THREADS=4 -running: CONFIGS=-DNUM_CLUSTERS=1 -DNUM_CORES=4 -DNUM_WARPS=4 -DNUM_THREADS=4 make -C ./ci/../runtime/simx -running: OPTS=-N16 -M16 -K16 make -C ./ci/../tests/opencl/kernel4 run-simx -make: Entering directory '/home/jblab/ivan_khromov/release/vortex/build/tests/opencl/kernel4' -cp /home/jblab/ivan_khromov/release/vortex/tests/opencl/kernel4/common.h common.h -LD_LIBRARY_PATH=/home/jblab/tools/pocl/lib:/home/jblab/ivan_khromov/release/vortex/build/runtime:/home/jblab/tools/llvm-vortex/lib::/usr/local/lib POCL_VORTEX_XLEN=32 LLVM_PREFIX=/home/jblab/tools/llvm-vortex POCL_VORTEX_BINTOOL="OBJCOPY=/home/jblab/tools/llvm-vortex/bin/llvm-objcopy /home/jblab/ivan_khromov/release/vortex/kernel/scripts/vxbin.py" POCL_VORTEX_CFLAGS="-march=rv32imaf -mabi=ilp32f -O3 -mcmodel=medany --sysroot=/home/jblab/tools/riscv32-gnu-toolchain/riscv32-unknown-elf --gcc-toolchain=/home/jblab/tools/riscv32-gnu-toolchain -fno-rtti -fno-exceptions -nostartfiles -nostdlib -fdata-sections -ffunction-sections -I/home/jblab/ivan_khromov/release/vortex/build/hw -I/home/jblab/ivan_khromov/release/vortex/kernel/include -DXLEN_32 -DNDEBUG -Xclang -target-feature -Xclang +vortex -Xclang -target-feature -Xclang +zicond -mllvm -disable-loop-idiom-all" POCL_VORTEX_LDFLAGS="-Wl,-Bstatic,--gc-sections,-T/home/jblab/ivan_khromov/release/vortex/kernel/scripts/link32.ld,--defsym=STARTUP_ADDR=0x80000000 /home/jblab/ivan_khromov/release/vortex/build/kernel/libvortex.a -L/home/jblab/tools/libc32/lib -lm -lc /home/jblab/tools/libcrt32/lib/baremetal/libclang_rt.builtins-riscv32.a" VORTEX_DRIVER=simx ./kernel4 -N16 -M16 -K16 -Using device: Vortex OpenGPU -Execute the kernel -Elapsed time: 235 ms -Verify result -PASSED! -PERF: core0: instrs=11548, cycles=40923, IPC=0.282189 -PERF: core1: instrs=11548, cycles=41559, IPC=0.277870 -PERF: core2: instrs=11548, cycles=41327, IPC=0.279430 -PERF: core3: instrs=11548, cycles=41707, IPC=0.276884 -PERF: instrs=46192, cycles=41707, IPC=1.107536 -make: Leaving directory '/home/jblab/ivan_khromov/release/vortex/build/tests/opencl/kernel4' diff --git a/tests/opencl/j_stat/perf.txt b/tests/opencl/j_stat/perf.txt deleted file mode 100644 index b842ece66..000000000 --- a/tests/opencl/j_stat/perf.txt +++ /dev/null @@ -1,3 +0,0 @@ -kernel1 ---warps=8 --cores=8 --threads=8 -cycles=57927 From 826da5c2f6a279c9cbff49ec2c20853064bb5af9 Mon Sep 17 00:00:00 2001 From: Ivan Khromov Date: Wed, 31 Jul 2024 20:44:24 +0300 Subject: [PATCH 8/8] Fix issues for pull request --- tests/opencl/j_stat/statistic.ipynb | 136 +++++++++++----------------- 1 file changed, 55 insertions(+), 81 deletions(-) diff --git a/tests/opencl/j_stat/statistic.ipynb b/tests/opencl/j_stat/statistic.ipynb index 81d952c55..af5afdc76 100644 --- a/tests/opencl/j_stat/statistic.ipynb +++ b/tests/opencl/j_stat/statistic.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 10, + "execution_count": 37, "metadata": {}, "outputs": [], "source": [ @@ -10,12 +10,13 @@ "import matplotlib.pyplot as plt\n", "from dataclasses import dataclass, field\n", "import pandas as pd\n", - "from tqdm import tqdm" + "from tqdm import tqdm\n", + "from pathlib import Path" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 38, "metadata": {}, "outputs": [], "source": [ @@ -36,11 +37,11 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 39, "metadata": {}, "outputs": [], "source": [ - "path_to_vortex = \"/home/jblab/ivan_khromov/release/vortex\"\n", + "path_to_vortex = Path.cwd().parent.parent.parent\n", "tile_size = 'TS'\n", "work_per_thread = 'WPT'\n", "width = 'WIDTH'" @@ -48,7 +49,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 40, "metadata": {}, "outputs": [], "source": [ @@ -59,7 +60,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 41, "metadata": {}, "outputs": [], "source": [ @@ -70,31 +71,29 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 42, "metadata": {}, "outputs": [], "source": [ "def create_common_h (params: dict, kernel_name: str):\n", " file_name = f\"{path_to_vortex}/tests/opencl/{kernel_name}/common.h\"\n", " with open(file_name, 'w') as file:\n", - " text = \"#ifndef COMMON_H\\n\" + \"#define COMMON_H\\n\" + \"\\n\" \n", + " file.write(\"#ifndef COMMON_H\\n\" + \"#define COMMON_H\\n\" + \"\\n\")\n", " if tile_size in params:\n", - " text += f\"#define TS {params[tile_size]}\\n\"\n", + " file.write(f\"#define TS {params[tile_size]}\\n\")\n", " if work_per_thread in params:\n", - " text += f\"#define WPT {params[work_per_thread]}\\n\"\n", - " text += \"#define RTS (TS/WPT)\\n\"\n", + " file.write(f\"#define WPT {params[work_per_thread]}\\n\")\n", + " file.write(\"#define RTS (TS/WPT)\\n\")\n", " if width in params:\n", - " text += f\"#define WIDTH {params[width]}\\n\"\n", - " text += '\\n' + \"#endif // COMMON_H\"\n", - " file.write(text)\n", + " file.write(f\"#define WIDTH {params[width]}\\n\")\n", + " file.write('\\n' + \"#endif // COMMON_H\")\n", " # open main.cc file to recompile before run with new common.h\n", - " with open(f\"{path_to_vortex}/tests/opencl/{kernel_name}/main.cc\", 'a') as main:\n", - " main.write('')" + " Path(f\"{path_to_vortex}/tests/opencl/{kernel_name}/main.cc\").touch(exist_ok=True)" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 43, "metadata": {}, "outputs": [], "source": [ @@ -104,7 +103,7 @@ " run_args = f\"-N{run_params.args['N']} -M{run_params.args['M']} -K{run_params.args['K']}\"\n", " command = f\"cd {path_to_vortex}/build && ./ci/blackbox.sh {vortex} --driver={run_params.driver} --app={run_params.kernel} --args=\\\"{run_args}\\\"\"\n", " print(command)\n", - " subprocess.call(f\"{command} > {path_to_output_file}\", shell=True)\n", + " result = subprocess.run(f\"{command} > {path_to_output_file}\", shell=True)\n", "\n", " # collect statistic \n", " with open(path_to_output_file, 'r') as file:\n", @@ -115,10 +114,11 @@ " if \"PERF:\" in line:\n", " general_perf_stat = line\n", " # check for errors\n", - " if \"FAILED\" in line: \n", - " error_message = error_verification(run_params, line[line.find(\"FAILED! - \"):])\n", - " if \"Error\" in line:\n", - " error_message = error_running(run_params, line[line.find(\"Error:\"):])\n", + " if result != 0:\n", + " if \"FAILED\" in line: \n", + " error_message = error_verification(run_params, line[line.find(\"FAILED! - \"):])\n", + " if \"Error\" in line:\n", + " error_message = error_running(run_params, line[line.find(\"Error:\"):])\n", " # pars string with general perf statistic of running kernel\n", " pairs = general_perf_stat.replace(\"PERF: \", \"\").split(\", \")\n", " perf_dict = {key_value.split(\"=\")[0]: float(key_value.split(\"=\")[1]) for key_value in pairs}\n", @@ -126,15 +126,15 @@ " error_message = error_running(run_params, \"Invalid number of cycles\")\n", " # write result to data frame\n", " run_result = pd.DataFrame([{\"kernel\": run_params.kernel[-1], \"driver\": run_params.driver, \"cores\": run_params.arch.cores, \n", - " \"warps\": run_params.arch.warps, \"threads\": run_params.arch.threads, \"M\": run_params.args[\"M\"], \n", - " \"N\": run_params.args[\"N\"], \"K\": run_params.args[\"K\"], \"instrs\": perf_dict[\"instrs\"], \"cycles\": perf_dict[\"cycles\"],\n", - " \"IPC\": perf_dict[\"IPC\"], \"error\": error_message}])\n", + " \"warps\": run_params.arch.warps, \"threads\": run_params.arch.threads, \"M\": run_params.args[\"M\"], \n", + " \"N\": run_params.args[\"N\"], \"K\": run_params.args[\"K\"], \"instrs\": perf_dict[\"instrs\"], \"cycles\": perf_dict[\"cycles\"],\n", + " \"IPC\": perf_dict[\"IPC\"], \"error\": error_message}])\n", " return run_result" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 44, "metadata": {}, "outputs": [], "source": [ @@ -148,7 +148,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 45, "metadata": {}, "outputs": [ { @@ -162,67 +162,41 @@ "name": "stdout", "output_type": "stream", "text": [ - "cd /home/jblab/ivan_khromov/release/vortex/build && ./ci/blackbox.sh --warps=4 --cores=4 --threads=4 --driver=simx --app=kernel1 --args=\"-N16 -M16 -K16\"\n" + "cd /home/jblab/ivan_khromov/release/vortex/build && ./ci/blackbox.sh --warps=2 --cores=1 --threads=8 --driver=simx --app=kernel1 --args=\"-N16 -M16 -K16\"\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - " 25%|██▌ | 1/4 [00:00<00:02, 1.12it/s]" + "In file included from /home/jblab/tools/pocl/include/CL/cl.h:20,\n", + " from /home/jblab/tools/pocl/include/CL/opencl.h:24,\n", + " from /home/jblab/ivan_khromov/release/vortex/tests/opencl/kernel1/main.cc:1:\n", + "/home/jblab/tools/pocl/include/CL/cl_version.h:22:104: note: #pragma message: cl_version.h: CL_TARGET_OPENCL_VERSION is not defined. Defaulting to 300 (OpenCL 3.0)\n", + " 22 | #pragma message(\"cl_version.h: CL_TARGET_OPENCL_VERSION is not defined. Defaulting to 300 (OpenCL 3.0)\")\n", + " | ^\n", + "/home/jblab/ivan_khromov/release/vortex/tests/opencl/kernel1/main.cc: In function ‘int main(int, char**)’:\n", + "/home/jblab/ivan_khromov/release/vortex/tests/opencl/kernel1/main.cc:161:25: warning: unused variable ‘context_properties’ [-Wunused-variable]\n", + " 161 | cl_context_properties context_properties[]{\n", + " | ^~~~~~~~~~~~~~~~~~\n", + "/home/jblab/ivan_khromov/release/vortex/tests/opencl/kernel1/main.cc:163:16: warning: unused variable ‘devices’ [-Wunused-variable]\n", + " 163 | cl_device_id devices[]{device_id};\n", + " | ^~~~~~~\n", + " 0%| | 0/4 [00:23 37\u001b[0m data_frames\u001b[38;5;241m.\u001b[39mappend(\u001b[43mperf\u001b[49m\u001b[43m(\u001b[49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moutput_file\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[1;32m 38\u001b[0m data_frame \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mconcat(data_frames, ignore_index\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[1;32m 40\u001b[0m \u001b[38;5;66;03m# draw graph based on the recived statistic\u001b[39;00m\n", + "Cell \u001b[0;32mIn[43], line 26\u001b[0m, in \u001b[0;36mperf\u001b[0;34m(run_params, path_to_output_file)\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# pars string with general perf statistic of running kernel\u001b[39;00m\n\u001b[1;32m 25\u001b[0m pairs \u001b[38;5;241m=\u001b[39m general_perf_stat\u001b[38;5;241m.\u001b[39mreplace(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPERF: \u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m)\u001b[38;5;241m.\u001b[39msplit(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m---> 26\u001b[0m perf_dict \u001b[38;5;241m=\u001b[39m \u001b[43m{\u001b[49m\u001b[43mkey_value\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msplit\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mfloat\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mkey_value\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msplit\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mkey_value\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mpairs\u001b[49m\u001b[43m}\u001b[49m\n\u001b[1;32m 27\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m perf_dict[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcycles\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m<\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 28\u001b[0m error_message \u001b[38;5;241m=\u001b[39m error_running(run_params, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid number of cycles\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "Cell \u001b[0;32mIn[43], line 26\u001b[0m, in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;66;03m# pars string with general perf statistic of running kernel\u001b[39;00m\n\u001b[1;32m 25\u001b[0m pairs \u001b[38;5;241m=\u001b[39m general_perf_stat\u001b[38;5;241m.\u001b[39mreplace(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPERF: \u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m)\u001b[38;5;241m.\u001b[39msplit(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m---> 26\u001b[0m perf_dict \u001b[38;5;241m=\u001b[39m {key_value\u001b[38;5;241m.\u001b[39msplit(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m=\u001b[39m\u001b[38;5;124m\"\u001b[39m)[\u001b[38;5;241m0\u001b[39m]: \u001b[38;5;28mfloat\u001b[39m(\u001b[43mkey_value\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msplit\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m) \u001b[38;5;28;01mfor\u001b[39;00m key_value \u001b[38;5;129;01min\u001b[39;00m pairs}\n\u001b[1;32m 27\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m perf_dict[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcycles\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m<\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 28\u001b[0m error_message \u001b[38;5;241m=\u001b[39m error_running(run_params, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid number of cycles\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[0;31mIndexError\u001b[0m: list index out of range" ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "cd /home/jblab/ivan_khromov/release/vortex/build && ./ci/blackbox.sh --warps=4 --cores=4 --threads=4 --driver=simx --app=kernel3 --args=\"-N16 -M16 -K16\"\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " 75%|███████▌ | 3/4 [00:02<00:00, 1.13it/s]" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "cd /home/jblab/ivan_khromov/release/vortex/build && ./ci/blackbox.sh --warps=4 --cores=4 --threads=4 --driver=simx --app=kernel4 --args=\"-N16 -M16 -K16\"\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "100%|██████████| 4/4 [00:03<00:00, 1.14it/s]\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" } ], "source": [ @@ -252,7 +226,7 @@ " \"N\": 16,\n", " \"K\": 16\n", "}\n", - "arch_p = arch(threads=4, cores=4, warps=4)\n", + "arch_p = arch(threads=8, cores=1, warps=2)\n", "run_p.append(run(arch_p, kernel=\"kernel1\", driver=\"simx\", args=arg))\n", "run_p.append(run(arch_p, kernel=\"kernel2\", driver=\"simx\", args=arg))\n", "run_p.append(run(arch_p, kernel=\"kernel3\", driver=\"simx\", args=arg))\n", @@ -266,7 +240,7 @@ "data_frame = pd.concat(data_frames, ignore_index=True)\n", "\n", "# draw graph based on the recived statistic\n", - "draw(data_frame, \"kernel\", \"cycles\", \"number of cycles per kernel\", \"graphics/graph.png\")" + "draw(data_frame, \"kernel\", \"cycles\", \"number of cycles per kernel\", f\"graphics/graph.png\")" ] } ],