admin
2022-08-18 67a5e3d825fde17b7b00906ce42b0bd8cafebc4e
ConsoleApplication/OpenclTest.cpp
@@ -1,431 +1,226 @@
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<CL/cl.h>
#include <chrono>
#include "OpenCLExcuter.h"
#include "ImgUtil.h"
using namespace std;
void printDevice();
uchar* createDemoData(int line);
uchar* createTemplateData(int line);
#include <stdio.h>
#include <stdlib.h>
#include <CL/cl.h>
int LINE_NUMBER = 10;
int RE = _NUMBER_L2_TOTAL_NUMBER;
const int ARRAY_SIZE = 1000;
/*
1. 创建平台
2. 创建设备
3. 根据设备创建上下文
*/
cl_context CreateContext(cl_device_id* device) {
   cl_int errNum;
   cl_uint numPlateforms;
   cl_platform_id firstPlatformId;
   cl_context context = NULL;
   errNum = clGetPlatformIDs(1, &firstPlatformId, &numPlateforms);
#define CHECK_ERRORS(ERR) \
   if(ERR != CL_SUCCESS){ \
      std::cerr << "OpenCL error code" << ERR << "file: " << __FILE__  << "line: " << __LINE__ << ".\nExiting..." << std::endl; \
      exit(1); \
   if (errNum != CL_SUCCESS || numPlateforms <= 0) {
      printf("Failed to find any OpenCL platforms.\n");
      return NULL;
   }
int main1() {
   //printDevice();
   //return 1;
   auto starttime = std::chrono::steady_clock::now();
   errNum = clGetDeviceIDs(firstPlatformId, CL_DEVICE_TYPE_GPU, 1, device, NULL);
   if (errNum != CL_SUCCESS) {
      printf("There is no GPU , trying CPU...\n");
      errNum = clGetDeviceIDs(firstPlatformId, CL_DEVICE_TYPE_CPU, 1, device, NULL);
   cl_int error;
   cl_uint num_of_platforms = 0;
   cl_platform_id platforms;
   }
   if (errNum != CL_SUCCESS) {
      printf("There is NO CPU or GPU\n");
      return NULL;
   }
   context = clCreateContext(NULL, 1, device, NULL, NULL, &errNum);
   if (errNum != CL_SUCCESS) {
      printf("Create context error\n");
      return NULL;
   }
   return context;
}
/*
@ 在上下文可用的第一个设备中创建命令队列
*/
   cl_device_id devices;
cl_command_queue CreateCommandQueue(cl_context context, cl_device_id device) {
   cl_int errNum;
   cl_command_queue commandQueue = NULL;
   //commandQueue = clCreateCommandQueue(context, device, 0, NULL);
   // OpenCL 2.0 的用法
   commandQueue = clCreateCommandQueueWithProperties(context, device, 0, NULL);
   if (commandQueue == NULL) {
      printf("Failed to create commandQueue for device 0\n");
      return NULL;
   }
   return commandQueue;
}
   cl_context context;
char* ReadKernelSourceFile(const char* filename, size_t* length) {
   FILE* file = NULL;
   size_t sourceLenth;
   char* sourceString;
   int ret;
   fopen_s(&file, filename, "rb");
   FILE* program_handle;
   size_t program_size;
   char* program_buffer;
   if (file == NULL) {
      printf("%s at %d : Can't open %s \n", __FILE__, __LINE__ - 2, filename);
      return NULL;
   }
   //重定位到文件末尾
   fseek(file, 0, SEEK_END);
   sourceLenth = ftell(file);
   //重定位到文件开头
   fseek(file, 0, SEEK_SET);
   sourceString = (char*)malloc(sourceLenth + 1);
   sourceString[0] = '\0';
   ret = fread(sourceString, sourceLenth, 1, file);
   if (ret == 0) {
      printf("%s at %d : Cant't read source %s\n", __FILE__, __LINE__ - 2, filename);
      return NULL;
   }
   fclose(file);
   if (length != 0) {
      *length = sourceLenth;
   }
   sourceString[sourceLenth] = '\0';
   return sourceString;
}
cl_program CreateProgram(cl_context context, cl_device_id device, const char* filename) {
   cl_int errNum;
   cl_program program;
   //记录大小的数据类型
   size_t program_length;
   char* const source = ReadKernelSourceFile(filename, &program_length);
   program = clCreateProgramWithSource(context, 1, (const char**)&source, NULL, NULL);
   size_t log_size;
   char* program_log;
   char kernel_name[] = "createBuffer";
   cl_kernel kernel;
   cl_command_queue queue;
   //获取平台
   error = clGetPlatformIDs(1, &platforms, &num_of_platforms);
   if (error != 0) {
      printf("Get platform failed!");
      return -1;
   if (program == NULL) {
      printf("Failed to creae CL program from source.\n");
      return NULL;
   }
   //获取设备
   error = clGetDeviceIDs(platforms, CL_DEVICE_TYPE_GPU, 1, &devices, NULL);
   if (error != 0) {
      printf("Get device failed!");
      return -1;
   errNum = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
   if (errNum != CL_SUCCESS) {
      char buildLog[16384];
      clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, sizeof(buildLog), buildLog, NULL);
      printf("Error in kernel : %s \n", buildLog);
      clReleaseProgram(program);
      return NULL;
   }
   return program;
}
/*
@ 创建内存对象
*/
bool  CreateMemObjects(cl_context context, cl_mem memObjects[3], float* a, float* b) {
   memObjects[0] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float) * ARRAY_SIZE, a, NULL);
   memObjects[1] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float) * ARRAY_SIZE, b, NULL);
   memObjects[2] = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(float) * ARRAY_SIZE, NULL, NULL);
   if (memObjects[0] == NULL || memObjects[1] == NULL || memObjects[2] == NULL) {
      printf("Error creating memeory objects.\n");
      return false;
   }
   return true;
}
/*
@ 清楚OpenCL资源
*/
void CleanUp(cl_context context, cl_command_queue commandQueue, cl_program program, cl_kernel kernel, cl_mem memObjects[3]) {
   for (int i = 0; i < 3; i++) {
      if (memObjects[i] != 0) {
         clReleaseMemObject(memObjects[i]);
      }
   }
   std::cout << " 获取设备:" << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - starttime).count() << std::endl;
   //创建上下文
   context = clCreateContext(NULL, 1, &devices, NULL, NULL, &error);
   if (error != 0) {
      printf("Creat context failed!");
      return -1;
   if (commandQueue != 0) {
      clReleaseCommandQueue(commandQueue);
   }
   std::cout << " 创建上下文:" << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - starttime).count() << std::endl;
   //创建程序;注意要用"rb"
    fopen_s(&program_handle,"kernel.cl", "rb");
   if (program_handle == NULL) {
      printf("The kernle can not be opened!");
      return -1;
   }
   fseek(program_handle, 0, SEEK_END);
   program_size = ftell(program_handle);
   rewind(program_handle);
   program_buffer = (char*)malloc(program_size + 1);
   program_buffer[program_size] = '\0';
   error = fread(program_buffer, sizeof(char), program_size, program_handle);
   if (error == 0) {
      printf("Read kernel failed!");
      return -1;
   }
   fclose(program_handle);
   program = clCreateProgramWithSource(context, 1, (const char**)&program_buffer,
      &program_size, &error);
   if (error < 0) {
      printf("Couldn't create the program!");
      return -1;
   }
   //编译程序
   error = clBuildProgram(program, 1, &devices, NULL, NULL, NULL);
   if (error < 0) {
      //确定日志文件的大小
      clGetProgramBuildInfo(program, devices, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
      program_log = (char*)malloc(log_size + 1);
      program_log[log_size] = '\0';
      //读取日志
      clGetProgramBuildInfo(program, devices, CL_PROGRAM_BUILD_LOG,
         log_size + 1, program_log, NULL);
      printf("%s\n", program_log);
      free(program_log);
      return -1;
   }
   free(program_buffer);
   //创建命令队列
   queue = clCreateCommandQueue(context, devices, CL_QUEUE_PROFILING_ENABLE, &error);
   if (error < 0) {
      printf("Coudn't create the command queue");
      return -1;
   }
   //----------程序正文开始---------
   for (int n = 0;n < 100;n++)
   {
      auto startexectime = std::chrono::steady_clock::now();
      //创建内核
      kernel = clCreateKernel(program, "createBuffer", &error);
      if (kernel == NULL) {
         printf("Couldn't create kernel!\n");
         return -1;
      }
      //初始化参数
      const int size = 70000;
      float result[size];
      float a_in[size];
      float b_in[size];
      for (int i = 0; i < size; i++) {
         a_in[i] = i+n;
         b_in[i] = i * 2.0;
      }
      //创建缓存对象
      cl_mem memObject1 = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float) * size, a_in, &error);
      if (error < 0) {
         printf("Creat memObject1 failed!\n");
         return -1;
      }
      cl_mem memObject2 = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
         sizeof(float) * size, b_in, &error);
      if (error < 0) {
         printf("Creat memObject2 failed!\n");
         return -1;
      }
      cl_mem memObject3 = clCreateBuffer(context, CL_MEM_WRITE_ONLY,
         sizeof(float) * size, NULL, &error);
      if (error < 0) {
         printf("Creat memObject3 failed!\n");
         return -1;
      }
      //设置内核参数
      error = clSetKernelArg(kernel, 0, sizeof(cl_mem), &memObject1);
      error |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &memObject2);
      error |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &memObject3);
      if (error != CL_SUCCESS) {
         printf("Error setting kernel arguments!\n");
         return -1;
      }
      //执行内核
      size_t globalWorkSize[1] = { size };
      size_t localWorkSize[1] = { 1 };
      const int work_dim = 2;
      error = clEnqueueNDRangeKernel(queue, kernel, work_dim, NULL, globalWorkSize,
         localWorkSize, 0, NULL, NULL);
      if (error != CL_SUCCESS) {
         printf("Error queuing kernel for execution!\n");
         return -1;
      }
      //读取执行结果
      error = clEnqueueReadBuffer(queue, memObject3, CL_TRUE, 0, size * sizeof(float),
         result, 0, NULL, NULL);
      if (error != CL_SUCCESS) {
         printf("Error reading result buffer!\n");
         return -1;
      }
      //显示结果
      for (int i = 0; i < 2; i++) {
         printf("%f ", result[i]);
      }
   if (kernel != 0) {
      clReleaseKernel(kernel);
      clReleaseMemObject(memObject1);
      clReleaseMemObject(memObject2);
      clReleaseMemObject(memObject3);
      std::cout << " 执行结束:" << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - startexectime).count() << std::endl;
   }
   if (program != 0) {
      clReleaseProgram(program);
   }
   if (context != 0) {
      clReleaseContext(context);
   }
}
   //-------------程序正文结束
/*main函数*/
int main__(int argc, char** agrv) {
   cl_context context = 0;
   cl_command_queue commandQueue = 0;
   cl_program program = 0;
   cl_device_id device = 0;
   cl_kernel kernel = 0;
   cl_mem memObjects[3] = { 0,0,0 };
   cl_int errNum;
   //创建OpenCL上下文
   context = CreateContext(&device);
   if (context == NULL) {
      printf("Failed to create OpenCL context\n");
      return 1;
   }
   //获得OpenCL设备,并创建命令队列
   commandQueue = CreateCommandQueue(context, device);
   if (commandQueue == NULL) {
      CleanUp(context, commandQueue, program, kernel, memObjects);
      return 1;
   }
   //创建OpenCL程序
   program = CreateProgram(context, device, "kernel.cl");
   if (program == NULL) {
      CleanUp(context, commandQueue, program, kernel, memObjects);
      return 1;
   }
   kernel = clCreateKernel(program, "vector_add", NULL);
   if (kernel == NULL) {
      printf("Failed to create kernel\n");
      CleanUp(context, commandQueue, program, kernel, memObjects);
      return 1;
   }
   //创建OpenCL内存对象
   float result[ARRAY_SIZE];
   float a[ARRAY_SIZE];
   float b[ARRAY_SIZE];
   for (int i = 0; i < ARRAY_SIZE; i++) {
      a[i] = (float)i;
      b[i] = (float)(i * 2);
   }
   if (!CreateMemObjects(context, memObjects, a, b)) {
      CleanUp(context, commandQueue, program, kernel, memObjects);
      return 1;
   }
   //设置内核参数
   errNum = clSetKernelArg(kernel, 0, sizeof(cl_mem), &memObjects[0]);
   errNum |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &memObjects[1]);
   errNum |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &memObjects[2]);
   //释放资源
   clReleaseDevice(devices);
   clReleaseContext(context);
   clReleaseProgram(program);
   clReleaseCommandQueue(queue);
   std::cout << " 耗时:" << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - starttime).count() << std::endl;
   if (errNum != CL_SUCCESS) {
      printf("Error setting kernel arguments.\n");
      CleanUp(context, commandQueue, program, kernel, memObjects);
      return 1;
   }
   size_t globalWorkSize[1] = { ARRAY_SIZE };
   size_t localWorkSize[1] = { 1 };
   //执行内核
   errNum = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL, globalWorkSize, localWorkSize, 0, NULL, NULL);
   if (errNum != CL_SUCCESS) {
      printf("Error queueing kernel for execution\n");
      CleanUp(context, commandQueue, program, kernel, memObjects);
      return 1;
   }
   //将计算的结果拷贝到主机上
   errNum = clEnqueueReadBuffer(commandQueue, memObjects[2], CL_TRUE, 0, ARRAY_SIZE * sizeof(float), result, 0, NULL, NULL);
   if (errNum != CL_SUCCESS) {
      printf("Error reading result buffer.\n");
      CleanUp(context, commandQueue, program, kernel, memObjects);
      return 1;
   }
   for (int i = 0; i < ARRAY_SIZE; i++) {
      printf("i=%d:%f\n", i, result[i]);
   }
   printf("Executed program succesfully\n");
   CleanUp(context, commandQueue, program, kernel, memObjects);
   return 0;
}
int main3() {
   ImgUtil::init();
   OpenCLExcuter* op = new OpenCLExcuter();
   int dataCount = 100;
   int rows = 8* dataCount;
   int cols = 5 * LINE_NUMBER * RE;
   uchar* b_in = createTemplateData(dataCount);
   uchar* a_in = createDemoData(dataCount);
   //printf("输入1: \n");
   for (int r = 0;r < rows;r++) {
      for (int c = 0;c < cols;c++) {
      //   printf("%d ", a_in[r*cols+c]);
      }
   //   printf("\n");
   }
   //printf("输入2: \n");
   for (int r = 0;r < rows;r++) {
      for (int c = 0;c < cols;c++) {
      //   printf("%d ", b_in[r * cols + c]);
      }
      //printf("\n");
   }
   /*
   int rows = 10;
   int cols = 10;
   uchar* b_in = (uchar*)malloc(sizeof(uchar*)*400);
   uchar* a_in = (uchar*)malloc(sizeof(uchar*) * 400);
   for (int i = 0;i < 400;i++) {
      b_in[i] = i;
      a_in[i] = i + 1;
   }
   */
   op->init();
   for (int i = 0;i < 100;i++)
   {
      op->recognition_numbers(a_in, b_in, rows, cols ,_NUMBER_L2_WIDTH, _NUMBER_L2_HEIGHT, _NUMBER_L2_TOTAL_NUMBER);
   }
   op->destory();
   return 1;
}
uchar* createDemoData(int line) {
   unsigned char* data = (unsigned char*)malloc(sizeof(unsigned char) * (_NUMBER_L2_HEIGHT * line) * 5 * LINE_NUMBER * RE);
   int outLineDataCount = 8 * 5 * LINE_NUMBER * RE;
   int inLineDataCount = 5 * LINE_NUMBER * RE;
   for (int l = 0;l < line;l++)
   {
      int outLineCount = outLineDataCount * l;
      for (int re = 0;re < RE;re++) {
         for (int n = 0;n < LINE_NUMBER;n++)
         {
            for (int r = 0;r < 8;r++) {
               int intLineCount = inLineDataCount * r;
               for (int c = 0;c < 5;c++) {
                  uchar value = ImgUtil::NUMS_LEVEL2[re%10].data.ptr(r)[c];
                  int index = outLineCount;
                  index += intLineCount;
                  int x = re * LINE_NUMBER * 5 + n * 5 + c;
                  index += x;
                  data[index] = value > 40 ? 1 : 0;
               }
            }
         }
      }
   }
   return data;
}
uchar* createTemplateData(int line) {
   unsigned char* data = (unsigned char*)malloc(sizeof(unsigned char) * (_NUMBER_L2_HEIGHT * line) * _NUMBER_L2_WIDTH * LINE_NUMBER * RE);
   int outLineDataCount = _NUMBER_L2_HEIGHT * _NUMBER_L2_WIDTH * LINE_NUMBER * RE;
   int inLineDataCount = _NUMBER_L2_WIDTH * LINE_NUMBER * RE;
   for (int l = 0;l < line;l++)
   {
      int outLineCount = outLineDataCount * l;
      for (int re = 0;re < RE;re++) {
         for (int n = 0;n < LINE_NUMBER;n++)
         {
            for (int r = 0;r < _NUMBER_L2_HEIGHT;r++) {
               int intLineCount = inLineDataCount * r;
               for (int c = 0;c < _NUMBER_L2_WIDTH;c++) {
                  uchar value = ImgUtil::NUMS_LEVEL2[n].data.ptr(r)[c];
                  int index = outLineCount;
                  index += intLineCount;
                  int x = re * LINE_NUMBER * _NUMBER_L2_WIDTH + n * _NUMBER_L2_WIDTH + c;
                  index += x;
                  data[index] = value > 40 ? 1 : 0;
               }
            }
         }
      }
   }
   return data;
}
void printDevice() {
   cl_int err = CL_SUCCESS;
   // 1. 获取当前设备所有支持OpenCL的平台的数量
   cl_uint num_of_platforms = 0;
   err = clGetPlatformIDs(0, 0, &num_of_platforms);
   CHECK_ERRORS(err);
   // 2. 获取当前设备所有支持OpenCL的平台的信息
   cl_platform_id* platforms = new cl_platform_id[num_of_platforms];
   err = clGetPlatformIDs(num_of_platforms, platforms, 0);
   CHECK_ERRORS(err);
   cl_char platform_names[10][50];
   // 3. 打印平台信息
   cout << "平台信息:\n";
   for (cl_uint i = 0; i < num_of_platforms; i++)
   {
      // 获取平台字符串的长度
      size_t platform_name_length = 0;
      err = clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME, 0, 0, &platform_name_length);
      CHECK_ERRORS(err);
      // 获取平台字符串
      char* platform_name = new char[platform_name_length];
      err = clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME, platform_name_length, platform_name, 0);
      CHECK_ERRORS(err);
      cout << "    [" << i << "] " << platform_name << endl;
      // 备份platform name
      if (i < 10) {
         memset(platform_names[i], 0, 50);
         memcpy(platform_names[i], platform_name, platform_name_length);
      }
      delete[] platform_name;
   }
   // 4. 查询各平台设备数量
   struct {
      cl_device_type type;
      const  char* name;
      cl_uint count;
   }devices[] = {
      {CL_DEVICE_TYPE_GPU, "CL_DEVICE_TYPE_GPU", 0},               // GPU
      {CL_DEVICE_TYPE_CPU, "CL_DEVICE_TYPE_CPU", 0},               // CPU
      {CL_DEVICE_TYPE_ACCELERATOR, "CL_DEVICE_TYPE_ACCELERATOR", 0}   // 加速器
   };
   // 5. 遍历查询各个平台下拥有的设备数量
   for (cl_int j = 0; j < num_of_platforms; j++) {
      cl_platform_id platform = platforms[j];
      cout << "\nplatform:" << platform_names[j] << endl;
      // 6. 遍历查询GPU、CPU、ACCELERATOR设备的数量
      for (cl_int i = 0; i < (sizeof(devices) / sizeof(devices[0])); i++)
      {
         err = clGetDeviceIDs(platform, devices[i].type, 0, 0, &devices[i].count);
         if (err == CL_DEVICE_NOT_FOUND) {
            devices[i].count = 0;
            err = CL_SUCCESS;
         }
         CHECK_ERRORS(err);
         cout << "\tdevices:" << devices[i].name
            << "\tcount:" << devices[i].count;
         if (devices[i].count != 0) {
            // 7. 遍历查询GPU、CPU、ACCELERATOR 所有设备的信息
            cl_device_id* device = new cl_device_id[devices[i].count];
            err = clGetDeviceIDs(platform, devices[i].type, devices[i].count, device, 0);
            cout << "\t\tdevice name:";
            for (cl_int k = 0; k < devices[i].count; k++)
            {
               // 8. 获取和打印各个设备的name
               size_t length = 0;
               cl_device_id each_device = device[k];
               err = clGetDeviceInfo(each_device, CL_DEVICE_NAME, 0, 0, &length);
               CHECK_ERRORS(err);
               char* value = new char[length];
               err = clGetDeviceInfo(each_device, CL_DEVICE_NAME, length, value, 0);
               CHECK_ERRORS(err);
               cout << value << " ";
               // 9. 获取和打印各个设备的version
               err = clGetDeviceInfo(each_device, CL_DEVICE_VERSION, 0, 0, &length);
               CHECK_ERRORS(err);
               char* version = new char[length];
               err = clGetDeviceInfo(each_device, CL_DEVICE_VERSION, length, version, 0);
               CHECK_ERRORS(err);
               cout << version << " ";
               delete[] value;
               delete[] version;
            }
            delete[] device;
         }
         cout << endl;
      }
   }
   delete[] platforms;
}