yum-mirror/VkFFT
git clone https://git.yummers.dev/yum-mirror/VkFFT
3fa0c21
master
1//general parts 2#include <stdio.h> 3#include <vector> 4#include <memory> 5#include <string.h> 6#include <chrono> 7#include <thread> 8#include <iostream> 9#ifndef __STDC_FORMAT_MACROS 10#define __STDC_FORMAT_MACROS 11#endif 12#include <inttypes.h> 13 14#if (VKFFT_BACKEND == 0 ) 15#include "vulkan/vulkan.h" 16#include "glslang_c_interface.h" 17#elif (VKFFT_BACKEND == 1 ) 18#include <cuda.h> 19#include <cuda_runtime.h> 20#include <nvrtc.h> 21#include <cuda_runtime_api.h> 22#include <cuComplex.h> 23#elif (VKFFT_BACKEND == 2 ) 24#ifndef __HIP_PLATFORM_HCC__ 25#define __HIP_PLATFORM_HCC__ 26#endif 27#include <hip/hip_runtime.h> 28#include <hip/hiprtc.h> 29#include <hip/hip_runtime_api.h> 30#include <hip/hip_complex.h> 31#elif (VKFFT_BACKEND == 3 ) 32#ifndef CL_USE_DEPRECATED_OPENCL_1_2_APIS 33#define CL_USE_DEPRECATED_OPENCL_1_2_APIS 34#endif 35#ifdef __APPLE__ 36#include <OpenCL/opencl.h> 37#else 38#include <CL/cl.h> 39#endif 40#elif (VKFFT_BACKEND == 4 ) 41#include <ze_api.h> 42#elif (VKFFT_BACKEND == 5 ) 43#include "Foundation/Foundation.hpp" 44#include "QuartzCore/QuartzCore.hpp" 45#include "Metal/Metal.hpp" 46#endif 47#include "vkFFT.h" 48#include "utils_VkFFT.h" 49#include "half.hpp" 50 51VkFFTResult user_benchmark_VkFFT (VkGPU * vkGPU ,uint64_t file_output ,FILE * output ,uint64_t isCompilerInitialized ,VkFFTUserSystemParameters * userParams ) 52{ 53VkFFTResult resFFT = VKFFT_SUCCESS ; 54#if (VKFFT_BACKEND == 0 ) 55VkResult res = VK_SUCCESS ; 56#elif (VKFFT_BACKEND == 1 ) 57cudaError_t res = cudaSuccess ; 58#elif (VKFFT_BACKEND == 2 ) 59hipError_t res = hipSuccess ; 60#elif (VKFFT_BACKEND == 3 ) 61cl_int res = CL_SUCCESS ; 62#elif (VKFFT_BACKEND == 4 ) 63ze_result_t res = ZE_RESULT_SUCCESS ; 64#elif (VKFFT_BACKEND == 5 ) 65#endif 66const int num_runs = 3 ; 67double benchmark_result = 0 ;//averaged result = sum(system_size/iteration_time)/num_benchmark_samples 68//memory allocated on the CPU once, makes benchmark completion faster + avoids performance issues connected to frequent allocation/deallocation. 69uint64_t storageComplexSize = 8 ; 70switch (userParams -> P ) { 71case 0 : 72storageComplexSize = (2 * sizeof (float )); 73break ; 74case 1 : 75storageComplexSize = (2 * sizeof (double )); 76break ; 77case 2 : 78storageComplexSize = (2 * 2 ); 79break ; 80case 3 : 81storageComplexSize = (4 * sizeof (double )); 82break ; 83default : 84storageComplexSize = (2 * sizeof (float )); 85break ; 86 } 87uint64_t bufferSize = 0 ; 88if (userParams -> R2C ) { 89bufferSize = (uint64_t )(storageComplexSize /2 )* (userParams -> X + 2 )* userParams -> Y * userParams -> Z * userParams -> B ; 90 } 91else { 92if (userParams -> DCT ) { 93bufferSize = (uint64_t )(storageComplexSize /2 )* userParams -> X * userParams -> Y * userParams -> Z * userParams -> B ; 94 } 95else { 96bufferSize = (uint64_t )storageComplexSize * userParams -> X * userParams -> Y * userParams -> Z * userParams -> B ; 97 } 98 } 99 100float * buffer_input = (float * )malloc (bufferSize ); 101if (!buffer_input )return VKFFT_ERROR_MALLOC_FAILED ; 102for (uint64_t i = 0 ;i < bufferSize /sizeof (float );i ++ ) { 103buffer_input [i ]= (float )(2 * ((float )rand ()) /RAND_MAX - 1.0 ); 104 } 105for (uint64_t n = 0 ;n < 2 ;n ++ ) { 106double run_time [num_runs ]; 107for (uint64_t r = 0 ;r < num_runs ;r ++ ) { 108//Configuration + FFT application . 109VkFFTConfiguration configuration = {}; 110VkFFTApplication app = {}; 111//FFT + iFFT sample code. 112//Setting up FFT configuration for forward and inverse FFT. 113configuration .FFTdim = 1 ;//FFT dimension, 1D, 2D or 3D (default 1). 114//if (n == 1) configuration.keepShaderCode = 1; 115 116configuration .size [0 ]= userParams -> X ; 117configuration .size [1 ]= userParams -> Y ; 118configuration .size [2 ]= userParams -> Z ; 119if (userParams -> Y > 1 )configuration .FFTdim ++ ; 120if (userParams -> Z > 1 )configuration .FFTdim ++ ; 121configuration .numberBatches = userParams -> B ; 122configuration .performR2C = userParams -> R2C ; 123configuration .performDCT = userParams -> DCT ; 124if (userParams -> P == 1 )configuration .doublePrecision = 1 ; 125if (userParams -> P == 2 )configuration .halfPrecision = 1 ; 126if (userParams -> P == 3 )configuration .quadDoubleDoublePrecision = 1 ; 127#if (VKFFT_BACKEND != 5 ) 128if (userParams -> saveApplicationToString && (n == 0 )&& (r == 0 ))configuration .saveApplicationToString = 1 ; 129if (userParams -> loadApplicationFromString || (userParams -> saveApplicationToString && ((n != 0 )|| (r != 0 ))))configuration .loadApplicationFromString = 1 ; 130#endif 131//After this, configuration file contains pointers to Vulkan objects needed to work with the GPU: VkDevice* device - created device, [uint64_t *bufferSize, VkBuffer *buffer, VkDeviceMemory* bufferDeviceMemory] - allocated GPU memory FFT is performed on. [uint64_t *kernelSize, VkBuffer *kernel, VkDeviceMemory* kernelDeviceMemory] - allocated GPU memory, where kernel for convolution is stored. 132#if (VKFFT_BACKEND == 5 ) 133configuration .device = vkGPU -> device ; 134#else 135configuration .device = & vkGPU -> device ; 136#endif 137#if (VKFFT_BACKEND == 0 ) 138configuration .queue = & vkGPU -> queue ;//to allocate memory for LUT, we have to pass a queue, vkGPU->fence, commandPool and physicalDevice pointers 139configuration .fence = & vkGPU -> fence ; 140configuration .commandPool = & vkGPU -> commandPool ; 141configuration .physicalDevice = & vkGPU -> physicalDevice ; 142configuration .isCompilerInitialized = isCompilerInitialized ;//compiler can be initialized before VkFFT plan creation. if not, VkFFT will create and destroy one after initialization 143#elif (VKFFT_BACKEND == 3 ) 144configuration .context = & vkGPU -> context ; 145#elif (VKFFT_BACKEND == 4 ) 146configuration .context = & vkGPU -> context ; 147configuration .commandQueue = & vkGPU -> commandQueue ; 148configuration .commandQueueID = vkGPU -> commandQueueID ; 149#elif (VKFFT_BACKEND == 5 ) 150configuration .queue = vkGPU -> queue ; 151#endif 152//Allocate buffer for the input data. 153#if (VKFFT_BACKEND == 0 ) 154VkBuffer buffer = {}; 155VkDeviceMemory bufferDeviceMemory = {}; 156resFFT = allocateBuffer (vkGPU ,& buffer ,& bufferDeviceMemory ,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |VK_BUFFER_USAGE_TRANSFER_SRC_BIT |VK_BUFFER_USAGE_TRANSFER_DST_BIT ,VK_MEMORY_HEAP_DEVICE_LOCAL_BIT ,bufferSize ); 157if (resFFT != VKFFT_SUCCESS )return resFFT ; 158configuration .buffer = & buffer ; 159#elif (VKFFT_BACKEND == 1 ) 160cuFloatComplex * buffer = 0 ; 161res = cudaMalloc ((void ** )& buffer ,bufferSize ); 162if (res != cudaSuccess )return VKFFT_ERROR_FAILED_TO_ALLOCATE ; 163configuration .buffer = (void ** )& buffer ; 164#elif (VKFFT_BACKEND == 2 ) 165hipFloatComplex * buffer = 0 ; 166res = hipMalloc ((void ** )& buffer ,bufferSize ); 167if (res != hipSuccess )return VKFFT_ERROR_FAILED_TO_ALLOCATE ; 168configuration .buffer = (void ** )& buffer ; 169#elif (VKFFT_BACKEND == 3 ) 170cl_mem buffer = 0 ; 171buffer = clCreateBuffer (vkGPU -> context ,CL_MEM_READ_WRITE ,bufferSize ,0 ,& res ); 172if (res != CL_SUCCESS )return VKFFT_ERROR_FAILED_TO_ALLOCATE ; 173configuration .buffer = & buffer ; 174#elif (VKFFT_BACKEND == 4 ) 175void * buffer = 0 ; 176ze_device_mem_alloc_desc_t device_desc = {}; 177device_desc .stype = ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC ; 178res = zeMemAllocDevice (vkGPU -> context ,& device_desc ,bufferSize ,sizeof (float ),vkGPU -> device ,& buffer ); 179if (res != ZE_RESULT_SUCCESS )return VKFFT_ERROR_FAILED_TO_ALLOCATE ; 180configuration .buffer = & buffer ; 181#elif (VKFFT_BACKEND == 5 ) 182MTL ::Buffer * buffer = 0 ; 183buffer = vkGPU -> device -> newBuffer (bufferSize ,MTL ::ResourceStorageModePrivate ); 184configuration .buffer = & buffer ; 185#endif 186 187configuration .bufferSize = & bufferSize ; 188 189resFFT = transferDataFromCPU (vkGPU ,buffer_input ,& buffer ,bufferSize ); 190if (resFFT != VKFFT_SUCCESS )return resFFT ; 191 192if (configuration .loadApplicationFromString ) { 193FILE * kernelCache ; 194uint64_t str_len ; 195char fname [500 ]; 196int VkFFT_version = VkFFTGetVersion (); 197sprintf (fname ,"VkFFT_binary_X%" PRIu64 "_Y%" PRIu64 "_Z%" PRIu64 "_P%" PRIu64 "_B%" PRIu64 "_N%" PRIu64 "_R2C%" PRIu64 "_DCT%" PRIu64 "_ver%d" ,userParams -> X ,userParams -> Y ,userParams -> Z ,userParams -> P ,userParams -> B ,userParams -> N ,userParams -> R2C ,userParams -> DCT ,VkFFT_version ); 198kernelCache = fopen (fname ,"rb" ); 199if (!kernelCache )return VKFFT_ERROR_EMPTY_FILE ; 200fseek (kernelCache ,0 ,SEEK_END ); 201str_len = ftell (kernelCache ); 202fseek (kernelCache ,0 ,SEEK_SET ); 203configuration .loadApplicationString = malloc (str_len ); 204fread (configuration .loadApplicationString ,str_len ,1 ,kernelCache ); 205fclose (kernelCache ); 206 } 207//Initialize applications. This function loads shaders, creates pipeline and configures FFT based on configuration file. No buffer allocations inside VkFFT library. 208resFFT = initializeVkFFT (& app ,configuration ); 209if (resFFT != VKFFT_SUCCESS )return resFFT ; 210 211if (configuration .loadApplicationFromString ) 212free (configuration .loadApplicationString ); 213 214if (configuration .saveApplicationToString ) { 215FILE * kernelCache ; 216char fname [500 ]; 217int VkFFT_version = VkFFTGetVersion (); 218sprintf (fname ,"VkFFT_binary_X%" PRIu64 "_Y%" PRIu64 "_Z%" PRIu64 "_P%" PRIu64 "_B%" PRIu64 "_N%" PRIu64 "_R2C%" PRIu64 "_DCT%" PRIu64 "_ver%d" ,userParams -> X ,userParams -> Y ,userParams -> Z ,userParams -> P ,userParams -> B ,userParams -> N ,userParams -> R2C ,userParams -> DCT ,VkFFT_version ); 219kernelCache = fopen (fname ,"wb" ); 220fwrite (app .saveApplicationString ,app .applicationStringSize ,1 ,kernelCache ); 221fclose (kernelCache ); 222 } 223 224//Submit FFT+iFFT. 225 226double totTime = 0 ; 227 228VkFFTLaunchParams launchParams = {}; 229resFFT = performVulkanFFTiFFT (vkGPU ,& app ,& launchParams ,userParams -> N ,& totTime ); 230if (resFFT != VKFFT_SUCCESS )return resFFT ; 231run_time [r ]= totTime ; 232if (n > 0 ) { 233if (r == num_runs - 1 ) { 234double std_error = 0 ; 235double avg_time = 0 ; 236for (uint64_t t = 0 ;t < num_runs ;t ++ ) { 237avg_time += run_time [t ]; 238 } 239avg_time /=num_runs ; 240for (uint64_t t = 0 ;t < num_runs ;t ++ ) { 241std_error += (run_time [t ]- avg_time )* (run_time [t ]- avg_time ); 242 } 243std_error = sqrt (std_error /num_runs ); 244uint64_t num_tot_transfers = 0 ; 245for (uint64_t i = 0 ;i < configuration .FFTdim ;i ++ ) 246num_tot_transfers += app .localFFTPlan -> numAxisUploads [i ]; 247num_tot_transfers *=4 ; 248if (file_output ) 249fprintf (output ,"VkFFT System: %" PRIu64 "x%" PRIu64 "x%" PRIu64 " Batch: %" PRIu64 " Buffer: %" PRIu64 " MB avg_time_per_step: %0.3f ms std_error: %0.3f num_iter: %" PRIu64 " benchmark: %" PRIu64 " scaled bandwidth: %0.1f bandwidth: %0.1f\n" ,configuration .size [0 ],configuration .size [1 ],configuration .size [2 ],userParams -> B ,bufferSize /1024 /1024 ,avg_time ,std_error ,userParams -> N , (uint64_t )(((double )bufferSize /1024 ) /avg_time ),bufferSize /1024.0 /1024.0 /1.024 * 4 * configuration .FFTdim /avg_time ,bufferSize /1024.0 /1024.0 /1.024 * num_tot_transfers /avg_time ); 250 251printf ("VkFFT System: %" PRIu64 "x%" PRIu64 "x%" PRIu64 " Batch: %" PRIu64 " Buffer: %" PRIu64 " MB avg_time_per_step: %0.3f ms std_error: %0.3f num_iter: %" PRIu64 " benchmark: %" PRIu64 " scaled bandwidth: %0.1f real bandwidth: %0.1f\n" ,configuration .size [0 ],configuration .size [1 ],configuration .size [2 ],userParams -> B ,bufferSize /1024 /1024 ,avg_time ,std_error ,userParams -> N , (uint64_t )(((double )bufferSize /1024 ) /avg_time ),bufferSize /1024.0 /1024.0 /1.024 * 4 * configuration .FFTdim /avg_time ,bufferSize /1024.0 /1024.0 /1.024 * num_tot_transfers /avg_time ); 252benchmark_result += ((double )bufferSize /1024 ) /avg_time ; 253 } 254 255 256 } 257 258#if (VKFFT_BACKEND == 0 ) 259vkDestroyBuffer (vkGPU -> device ,buffer ,NULL ); 260vkFreeMemory (vkGPU -> device ,bufferDeviceMemory ,NULL ); 261#elif (VKFFT_BACKEND == 1 ) 262cudaFree (buffer ); 263#elif (VKFFT_BACKEND == 2 ) 264hipFree (buffer ); 265#elif (VKFFT_BACKEND == 3 ) 266clReleaseMemObject (buffer ); 267#elif (VKFFT_BACKEND == 4 ) 268zeMemFree (vkGPU -> context ,buffer ); 269#elif (VKFFT_BACKEND == 5 ) 270buffer -> release (); 271#endif 272 273deleteVkFFT (& app ); 274 275 } 276 } 277free (buffer_input ); 278return resFFT ; 279}