4.6 基本功能函数

因为OpenCL意味着对于系统来说是不可知的,有些任务不能像传统的C/C++那样自动完成。不过好消息是当相关工具代码完成后,就可以是用到所有OpenCL应用代码中。

4.6.1 打印编译错误信息

当我们尝试编译和链接我们的OpenCL程序对象时(使用clBuildProgram()clCompileProgram()clLinkProgram()),OpenCL C代码可能会出现错误。出现错误时,主机端不会直接显示这些编译错误,而是直接退出。通过OpenCL API的返回值,让编程者知道是编译时候的错误,并需要手动去将编译输出打印出来。

当OpenCL程序对象编译失败,一个构建日志将会产生,并保存在程序对象中。该日志可以通过API clGetProgramBuildInfo()检索出,传入CL_PROGRAM_BUILD_LOG到param_name,得到相应日志内容。还有与其类似的API存在,clProgramBuildInfo()需要调用两次:第一次是获取日志的大小,分配对应大小的数组,用来放置日志内容;第二次是将日志中的具体内容取出。

本章中我们自己封装了一个名为printCompilerError()的函数,用于打印OpenCL C的编译错误信息。printCompilerError()的具体实现在程序清单4.12中。

  1. void printCompilerError(cl_program program, cl_device_id device)
  2. {
  3. cl_int status;
  4. size_t logSize;
  5. char *log;
  6. /* Get the log size */
  7. status = clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
  8. check(status);
  9. /* Allocate space for the log */
  10. log = (char *)malloc(logSize);
  11. if (!log){
  12. exit(-1);
  13. }
  14. /* Read the log */
  15. status = clGetPeogramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, logSize, log, NULL);
  16. check(status);
  17. /* Print the log */
  18. printf("%s\n", log);
  19. }

程序清单4.12 查询程序对象编译日志的函数封装

4.6.2 创建一个程序字符串

第3章中,我们使用了字符数组(const char **strings),调用clCreateProgramWithSource()创建程序对象。不过,将OpenCL C源直接携程字符数组是十分不便的。因此,通常的做法都是将OpenCL C源码放置在一个单独文件中,当主机端使用到的时候对改文件进行读取。

使用C++时(如代码清单4.8所示),从文件中读取字符串就简单很多。不过,当我们使用C语言时,从文件中读取字符串就需要多做一些事情。代码清单4.13就展示了,如何使用一个C函数将文件读取到一个C的字符串(字符数组)中。

  1. char *readFile(const char *filename)
  2. {
  3. FILE *fp;
  4. char *fileData;
  5. long fileSize;
  6. /* Open the file */
  7. fp = fopen(filename, "r");
  8. if (!fp){
  9. printf("Could not open file: %s\n", filename);
  10. exit(-1);
  11. }
  12. /* Determine the file size */
  13. if (fseek(fp, 0, SEEK_END)){
  14. printf("Error read the file\n");
  15. exit(-1);
  16. }
  17. fileSize = ftell(fp);
  18. if (fileSize < 0){
  19. printf("Error read the file\n");
  20. exit(-1);
  21. }
  22. if (fseek(fp, 0, SEEK_SET)){
  23. printf("Error read the file\n");
  24. exit(-1);
  25. }
  26. /* Read the contents */
  27. fileData = (char *)malloc(fileSize + 1);
  28. if (!fileData){
  29. exit(-1);
  30. }
  31. if (fread(fileData, fileSize, 1, fp) != 1){
  32. printf("Error reading the file\n");
  33. exit(-1);
  34. }
  35. /* Terminate the string */
  36. fileData[fileSize] = '\0';
  37. /* Close the file */
  38. if (fclose(fp)){
  39. printf("Error closing the file\n");
  40. exit(-1);
  41. }
  42. return fileData;
  43. }

程序清单4.13 将OpenCL C源码从文件中读取出