hack のためのネタ帳, etc,,,

状況

Cygwin で OpenCL 叩いてみようと思い、まず、 辺りを参考に、profice と device 情報の一覧を得るため以下のようなコードを書いてみた。

clinfo.c

#include <stdio.h>
#include <stdlib.h>
#include <CL/cl.h>

#define MAXPLATFORMS 64
#define MAXDEVICES 1024
#define NUMELEM(X) (sizeof(X)/sizeof(X[0]))
#define SWAP(X,Y,Z) {Z=X;X=Y;Y=Z;}

#define PUT_PLATFORMINFO(PLATFORM,NAME,SIZE,VALUE,SIZE_RET) \
{ \
  cl_int ret; \
  ret = clGetPlatformInfo(PLATFORM, NAME, SIZE, VALUE, SIZE_RET); \
  if (ret != CL_SUCCESS) fprintf(stderr, "Warning: clGetPlatformInfo failes.: %s: %d\n", __FILE__, __LINE__); \
  else printf("%-34s : %s\n", #NAME, VALUE); \
}

#define PUT_DEVICEINFO(DEVICE,NAME,SIZE,VALUE,SIZE_RET,FMT,FILTER) \
{ \
  cl_int ret; \
  ret = clGetDeviceInfo(DEVICE, NAME, SIZE, VALUE, SIZE_RET); \
  if (ret != CL_SUCCESS) fprintf(stderr, "Warning: clGetDeviceInfo failes.: %s: %d\n", __FILE__, __LINE__); \
  else printf("%-34s : " FMT "\n", #NAME, FILTER(VALUE)); \
}

#define RAW(X) (X)
#define DEREF(X) (*(X))

/**
 * Get stringified device type of OpenCL
 * @param t [in] device type
 * @return Non-reentrant static char* with stringified device type of OpenCL.
 */
char *get_cl_device_type(cl_device_type *t)
{
  static char s1[1024]="", s2[1024]="";
  char *s = s1, *b = s2, *w;
  char *sep = "";
  sprintf(s, "%d : ", *t);
  if (*t & CL_DEVICE_TYPE_DEFAULT    ) {SWAP(s, b, w); sprintf(s, "%s%s%s(%d)", b, sep, "DEFAULT"    , CL_DEVICE_TYPE_DEFAULT    ); sep = " | ";}
  if (*t & CL_DEVICE_TYPE_CPU        ) {SWAP(s, b, w); sprintf(s, "%s%s%s(%d)", b, sep, "CPU"        , CL_DEVICE_TYPE_CPU        ); sep = " | ";}
  if (*t & CL_DEVICE_TYPE_GPU        ) {SWAP(s, b, w); sprintf(s, "%s%s%s(%d)", b, sep, "GPU"        , CL_DEVICE_TYPE_GPU        ); sep = " | ";}
  if (*t & CL_DEVICE_TYPE_ACCELERATOR) {SWAP(s, b, w); sprintf(s, "%s%s%s(%d)", b, sep, "ACCELERATOR", CL_DEVICE_TYPE_ACCELERATOR); sep = " | ";}
  if (*t & CL_DEVICE_TYPE_CUSTOM     ) {SWAP(s, b, w); sprintf(s, "%s%s%s(%d)", b, sep, "CUSTOM"     , CL_DEVICE_TYPE_CUSTOM     ); sep = " | ";}
  if (*t & ~(CL_DEVICE_TYPE_DEFAULT|CL_DEVICE_TYPE_CPU|CL_DEVICE_TYPE_GPU|CL_DEVICE_TYPE_ACCELERATOR|CL_DEVICE_TYPE_CUSTOM)) {
    SWAP(s, b, w);
    sprintf(s, "%s%s%s(%d)", b, sep, "unknown"     , *t & ~(CL_DEVICE_TYPE_DEFAULT|CL_DEVICE_TYPE_CPU|CL_DEVICE_TYPE_GPU|CL_DEVICE_TYPE_ACCELERATOR|CL_DEVICE_TYPE_CUSTOM));
  }
  return s;
}

int main(int argc, char *argv[])
{
  cl_int          ret;
  cl_platform_id  platforms[MAXPLATFORMS];
  cl_uint         num_platforms;
  cl_device_id    devices[MAXDEVICES];
  cl_uint         num_devices;
  cl_device_type  t;
  char            s[4096];
  size_t          size_ret;
  cl_bool         v_b;
  cl_uint         v_ui;
  cl_ulong        v_ul;
  size_t          size;
  ret = clGetPlatformIDs(NUMELEM(platforms), platforms, &num_platforms);
  if (ret != CL_SUCCESS) { fprintf(stderr, "Error: clGetPlatformIDS failed.\n"); exit(1); }
  printf("num_platforms : %d\n", num_platforms);
  for (int i = 0; i < num_platforms; i++) {
    printf("======================================================================\n");
    printf("Platform : %d/%d\n", 1+i, num_platforms);
    PUT_PLATFORMINFO(platforms[i], CL_PLATFORM_PROFILE   , sizeof(s), s, &size_ret);
    PUT_PLATFORMINFO(platforms[i], CL_PLATFORM_VERSION   , sizeof(s), s, &size_ret);
    PUT_PLATFORMINFO(platforms[i], CL_PLATFORM_NAME      , sizeof(s), s, &size_ret);
    PUT_PLATFORMINFO(platforms[i], CL_PLATFORM_VENDOR    , sizeof(s), s, &size_ret);
    PUT_PLATFORMINFO(platforms[i], CL_PLATFORM_EXTENSIONS, sizeof(s), s, &size_ret);
    printf("\n");

    ret = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, NUMELEM(devices), devices, &num_devices);
    printf("num_devices : %d\n", num_devices);

    for (int j = 0; j < num_devices; j++) {
      printf("----------------------------------------------------------------------\n");
      printf("Device : %d/%d\n", 1+j, num_devices);
      
      PUT_DEVICEINFO(devices[j], CL_DEVICE_NAME                    , sizeof(s   ),  s   , &size_ret, "%s"     , RAW);
      PUT_DEVICEINFO(devices[j], CL_DEVICE_VENDOR                  , sizeof(s   ),  s   , &size_ret, "%s"     , RAW);
      PUT_DEVICEINFO(devices[j], CL_DRIVER_VERSION                 , sizeof(s   ),  s   , &size_ret, "%s"     , RAW);
      PUT_DEVICEINFO(devices[j], CL_DEVICE_TYPE                    , sizeof(t   ), &t   , &size_ret, "%s"     , get_cl_device_type);
      PUT_DEVICEINFO(devices[j], CL_DEVICE_MAX_COMPUTE_UNITS       , sizeof(v_ui), &v_ui, &size_ret, "%u"     , DEREF);
      PUT_DEVICEINFO(devices[j], CL_DEVICE_MAX_CLOCK_FREQUENCY     , sizeof(v_ui), &v_ui, &size_ret, "%u MHz" , DEREF);
      PUT_DEVICEINFO(devices[j], CL_DEVICE_MAX_MEM_ALLOC_SIZE      , sizeof(v_ul), &v_ul, &size_ret, "%llu B" , DEREF);
      PUT_DEVICEINFO(devices[j], CL_DEVICE_LOCAL_MEM_SIZE          , sizeof(v_ul), &v_ul, &size_ret, "%llu B" , DEREF);
      PUT_DEVICEINFO(devices[j], CL_DEVICE_MAX_WORK_GROUP_SIZE     , sizeof(size), &size, &size_ret, "%zu"    , DEREF);
      PUT_DEVICEINFO(devices[j], CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(v_ui), &v_ui, &size_ret, "%u"     , DEREF);
      size_t max_work_item_dimensions = v_ui;
      size_t max_work_item_sizes[max_work_item_dimensions];
      size_t max_work_item_size_total = 1;
      ret = clGetDeviceInfo(devices[j], CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(max_work_item_sizes), max_work_item_sizes, &size_ret);
      printf("%-34s :", "CL_DEVICE_MAX_WORK_ITEM_SIZES");
      for (int k = 0; k < max_work_item_dimensions; k++) {
        printf(" %zu", max_work_item_sizes[k]);
        max_work_item_size_total *= max_work_item_sizes[k];
      }
      printf(" = %zu\n", max_work_item_size_total);
      
//      PUT_DEVICEINFO(devices[j], CL_DEVICE_IL_VERSION              , sizeof(s   ),  s   , &size_ret, "%s"     , RAW); // Missing before ver 2.1
//      PUT_DEVICEINFO(devices[j], CL_DEVICE_ILS_WITH_VERSION        , sizeof(s   ),  s   , &size_ret, "%s"     , RAW); // Missing before ver 3.0
      PUT_DEVICEINFO(devices[j], CL_DEVICE_BUILT_IN_KERNELS        , sizeof(s   ),  s   , &size_ret, "%s"     , RAW);
      PUT_DEVICEINFO(devices[j], CL_DEVICE_PROFILE                 , sizeof(s   ),  s   , &size_ret, "%s"     , RAW);
      PUT_DEVICEINFO(devices[j], CL_DEVICE_OPENCL_C_VERSION        , sizeof(s   ),  s   , &size_ret, "%s"     , RAW);
      PUT_DEVICEINFO(devices[j], CL_DEVICE_EXTENSIONS              , sizeof(s   ),  s   , &size_ret, "%s"     , RAW);
      
      printf("\n");
    }
  }
  return EXIT_SUCCESS;
}
結果
$ gcc clinfo.c -l OpenCL && ./a
num_platforms : 1
======================================================================
Platform : 1/1
CL_PLATFORM_PROFILE                : FULL_PROFILE
CL_PLATFORM_VERSION                : OpenCL 1.2 pocl 1.3 RelWithDebInfo+Asserts, LLVM 8.0.1, SPIR, SLEEF, POCL_DEBUG
CL_PLATFORM_NAME                   : Portable Computing Language
CL_PLATFORM_VENDOR                 : The pocl project
CL_PLATFORM_EXTENSIONS             : cl_khr_icd

num_devices : 1
----------------------------------------------------------------------
Device : 1/1
CL_DEVICE_NAME                     : pthread-Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
CL_DEVICE_VENDOR                   : GenuineIntel
CL_DRIVER_VERSION                  : 1.3
CL_DEVICE_TYPE                     : 2 : CPU(2)
CL_DEVICE_MAX_COMPUTE_UNITS        : 8
CL_DEVICE_MAX_CLOCK_FREQUENCY      : 4010 MHz
CL_DEVICE_MAX_MEM_ALLOC_SIZE       : 17179869184 B
CL_DEVICE_LOCAL_MEM_SIZE           : 4194304 B
CL_DEVICE_MAX_WORK_GROUP_SIZE      : 4096
CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS : 3
CL_DEVICE_MAX_WORK_ITEM_SIZES      : 4096 4096 4096 = 68719476736
CL_DEVICE_BUILT_IN_KERNELS         :
CL_DEVICE_PROFILE                  : FULL_PROFILE
CL_DEVICE_OPENCL_C_VERSION         : OpenCL C 1.2 pocl
CL_DEVICE_EXTENSIONS               : cl_khr_byte_addressable_store cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_3d_image_writes cl_khr_spir cl_khr_fp64 cl_khr_int64_base_atomics cl_khr_int64_extended_atomics cl_khr_fp64

見ての通り、CPU のみで GPU 拾えてない。

Cygwin OpenCL site:stackoverflow.com」辺りでググると以下のページを見つけた。
曰く、/etc/OpenCL/vendors に nvidia.ich 作って、/cygdrive/c/Windows/System32/nvopencl.dll って書いとけと。
ところが、Windows 10 で GeForce GTX の Studio とライバー 456.38 だと、こんなファイルは存在しておらず、
この通りに書いても結果は変わらず。
とりあえず、
  • /cygdrive/c/Windows/System32/OpenCL.dll
  • /cygdrive/c/Program Files/NVIDIA Corporation/OpenCL/OpenCL64.dll
等を見つけたので、それぞれ windows.icd、nvidia64.icd とかを作って書きこんでみたところ、
strace してみると確かにこれら .icd ファイルを読みに行って、dll を dlopen してるのだけど、結果は変わらずという状況。

解法

当分の間悩んだのだが、strace の結果を眺めてたら、ふと C:\Windows\System32\OpenCL.dll や C:\Program Files\NVIDIA Corporation\OpenCL\OpenCL64.dll が C:\Windows\System32\DriverStore\FileRepository\nv_dispsi.inf_amd64_98b8327e9bd736d9\nvopencl64.dll を loded してる事に気付く。
そこで、試しに

/etc/OpenCL/vendors/nvopencl64.icd

/cygdrive/c/Windows/System32/DriverStore/FileRepository/nv_dispsi.inf_amd64_98b8327e9bd736d9/nvopencl64.dll
のようなファイルを作ってみたところ、無事
$ gcc clinfo.c -l OpenCL && ./a
num_platforms : 2
======================================================================
Platform : 1/2
CL_PLATFORM_PROFILE                : FULL_PROFILE
CL_PLATFORM_VERSION                : OpenCL 1.2 CUDA 11.1.70
CL_PLATFORM_NAME                   : NVIDIA CUDA
CL_PLATFORM_VENDOR                 : NVIDIA Corporation
CL_PLATFORM_EXTENSIONS             : cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_fp64 cl_khr_byte_addressable_store cl_khr_icd cl_khr_gl_sharing cl_nv_compiler_options cl_nv_device_attribute_query cl_nv_pragma_unroll cl_nv_d3d10_sharing cl_khr_d3d10_sharing cl_nv_d3d11_sharing cl_nv_copy_opts cl_nv_create_buffer cl_khr_int64_base_atomics cl_khr_int64_extended_atomics cl_khr_device_uuid

num_devices : 1
----------------------------------------------------------------------
Device : 1/1
CL_DEVICE_NAME                     : GeForce GTX 1080
CL_DEVICE_VENDOR                   : NVIDIA Corporation
CL_DRIVER_VERSION                  : 456.38
CL_DEVICE_TYPE                     : 4 : GPU(4)
CL_DEVICE_MAX_COMPUTE_UNITS        : 20
CL_DEVICE_MAX_CLOCK_FREQUENCY      : 1797 MHz
CL_DEVICE_MAX_MEM_ALLOC_SIZE       : 2147483648 B
CL_DEVICE_LOCAL_MEM_SIZE           : 49152 B
CL_DEVICE_MAX_WORK_GROUP_SIZE      : 1024
CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS : 3
CL_DEVICE_MAX_WORK_ITEM_SIZES      : 1024 1024 64 = 67108864
CL_DEVICE_BUILT_IN_KERNELS         :
CL_DEVICE_PROFILE                  : FULL_PROFILE
CL_DEVICE_OPENCL_C_VERSION         : OpenCL C 1.2
CL_DEVICE_EXTENSIONS               : cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_fp64 cl_khr_byte_addressable_store cl_khr_icd cl_khr_gl_sharing cl_nv_compiler_options cl_nv_device_attribute_query cl_nv_pragma_unroll cl_nv_d3d10_sharing cl_khr_d3d10_sharing cl_nv_d3d11_sharing cl_nv_copy_opts cl_nv_create_buffer cl_khr_int64_base_atomics cl_khr_int64_extended_atomics cl_khr_device_uuid

======================================================================
Platform : 2/2
CL_PLATFORM_PROFILE                : FULL_PROFILE
CL_PLATFORM_VERSION                : OpenCL 1.2 pocl 1.3 RelWithDebInfo+Asserts, LLVM 8.0.1, SPIR, SLEEF, POCL_DEBUG
CL_PLATFORM_NAME                   : Portable Computing Language
CL_PLATFORM_VENDOR                 : The pocl project
CL_PLATFORM_EXTENSIONS             : cl_khr_icd

num_devices : 1
----------------------------------------------------------------------
Device : 1/1
CL_DEVICE_NAME                     : pthread-Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
CL_DEVICE_VENDOR                   : GenuineIntel
CL_DRIVER_VERSION                  : 1.3
CL_DEVICE_TYPE                     : 2 : CPU(2)
CL_DEVICE_MAX_COMPUTE_UNITS        : 8
CL_DEVICE_MAX_CLOCK_FREQUENCY      : 4010 MHz
CL_DEVICE_MAX_MEM_ALLOC_SIZE       : 17179869184 B
CL_DEVICE_LOCAL_MEM_SIZE           : 4194304 B
CL_DEVICE_MAX_WORK_GROUP_SIZE      : 4096
CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS : 3
CL_DEVICE_MAX_WORK_ITEM_SIZES      : 4096 4096 4096 = 68719476736
CL_DEVICE_BUILT_IN_KERNELS         :
CL_DEVICE_PROFILE                  : FULL_PROFILE
CL_DEVICE_OPENCL_C_VERSION         : OpenCL C 1.2 pocl
CL_DEVICE_EXTENSIONS               : cl_khr_byte_addressable_store cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_3d_image_writes cl_khr_spir cl_khr_fp64 cl_khr_int64_base_atomics cl_khr_int64_extended_atomics cl_khr_fp64

の結果を得るに至った。

素直に nvopencl に対して find かけて
$ find /cygdrive/c/Windows/ -iname '*nvopencl*.dll'
/cygdrive/c/Windows/System32/DriverStore/FileRepository/nv_dispsi.inf_amd64_98b8327e9bd736d9/nvopencl32.dll
/cygdrive/c/Windows/System32/DriverStore/FileRepository/nv_dispsi.inf_amd64_98b8327e9bd736d9/nvopencl64.dll
としとけば良かった案件 orz
地味に時間を無駄にした。

それにしても
  • /cygdrive/c/Windows/System32/OpenCL.dll
  • /cygdrive/c/Program Files/NVIDIA Corporation/OpenCL/OpenCL64.dll
は何なんだって話なんだが、
プロパティ見てみると、前者は
  • 製品名 : Khronos OpenCL ICD Loader
  • 著作権 : Copyright © The Khronos Group Inc 2016-2020
後者は
  • 製品名 : Khronos OpenCL ICD
  • 著作権 : Copyright © The Khronos Group Inc 2014
となっているのに対して、
  • /cygdrive/c/Windows/System32/DriverStore/FileRepository/nv_dispsi.inf_amd64_98b8327e9bd736d9/nvopencl64.dll
は、
  • 製品名 : NVIDIA CUDA 11.1.70 OpenCL 1.2 driver
  • 著作権 : (C) 2020 NVIDIA Corporation, Allrights reserv...
となっていてた。

つまり、OpenCL driver じゃなくて ICD Loader ということらしい。

あと、Cygwin の libOpenCL1 パッケージに付属の /usr/share/doc/ocl-icd/html/libOpenCL.html によると
環境変数 OCL_ICD_VENDORS で /etc/OpenCL/vendors 以下の .icd ファイルを指定できるらしくて
OCL_ICD_VENDORS=nvopencl64.icd ./a
とか
OCL_ICD_VENDORS=pocl.icd ./a
みたいにすることで、任意の vendor に絞ることが可能だった。

ただし、OCL_ICD_VENDORS と、複数形になっているにも関わらず、.icd ファイルを複数指定すると clGetPlatformIDS() に失敗する。
スペースや、:、;、がセパレートにならないかと試してみたが駄目だった。
.icd ファイルに複数の shared library を書く方法も試してみたが、その場合は先頭のみが有効だった。
OCL_ICD_VENDORS にはディレクトリも指定できるので、ディレクトリ内に目的の vendor の .icd ファイルを放り込んでおいて、そのディレクトリを指定するという方法は有効だった。

あと、同様にして Intel HD Graphics を叩く方法は不明。
候補になりそうなのは以下のファイルだが、少なくとも i7-6700K の HD Graphics 530 ドライバーバージョン 27.20.100.8682 では軒並み駄目だった。
$ find /cygdrive/c/Windows/ -iname '*opencl*.dll' -or -iname '*ocl*.dll'
/cygdrive/c/Windows/System32/DriverStore/FileRepository/igdlh64.inf_amd64_2cec8fd58a80e6ea/Intel_OpenCL_ICD32.dll
/cygdrive/c/Windows/System32/DriverStore/FileRepository/igdlh64.inf_amd64_2cec8fd58a80e6ea/Intel_OpenCL_ICD64.dll
/cygdrive/c/Windows/System32/DriverStore/FileRepository/igdlh64.inf_amd64_2cec8fd58a80e6ea/opencl-clang32.dll
/cygdrive/c/Windows/System32/DriverStore/FileRepository/igdlh64.inf_amd64_2cec8fd58a80e6ea/opencl-clang64.dll
/cygdrive/c/Windows/System32/DriverStore/FileRepository/nv_dispsi.inf_amd64_98b8327e9bd736d9/nvopencl32.dll
/cygdrive/c/Windows/System32/DriverStore/FileRepository/nv_dispsi.inf_amd64_98b8327e9bd736d9/nvopencl64.dll
/cygdrive/c/Windows/System32/DriverStore/FileRepository/nv_dispsi.inf_amd64_98b8327e9bd736d9/OpenCL32.dll
/cygdrive/c/Windows/System32/DriverStore/FileRepository/nv_dispsi.inf_amd64_98b8327e9bd736d9/OpenCL64.dll
/cygdrive/c/Windows/System32/DriverStore/FileRepository/rdvgwddmdx11.inf_amd64_4d3a1b424a257b28/opencl.dll
/cygdrive/c/Windows/System32/DriverStore/FileRepository/rdvgwddmdx11.inf_amd64_4d3a1b424a257b28/rdvgocl64.dll
/cygdrive/c/Windows/System32/InprocLogger.dll
/cygdrive/c/Windows/System32/OpenCL.dll
/cygdrive/c/Windows/SysWOW64/OpenCL.dll
/cygdrive/c/Windows/SysWOW64/rdvgocl32.dll
/cygdrive/c/Windows/WinSxS/wow64_microsoft-windows-r..xwddmdriver-wow64-c_31bf3856ad364e35_10.0.18362.1_none_8385dcee297257d1/opencl.dll
/cygdrive/c/Windows/WinSxS/wow64_microsoft-windows-r..xwddmdriver-wow64-c_31bf3856ad364e35_10.0.18362.1_none_8385dcee297257d1/rdvgocl32.dll
/cygdrive/c/Windows/WinSxS/amd64_dual_rdvgwddmdx11.inf_31bf3856ad364e35_10.0.18362.1_none_d782513d0562d02b/opencl.dll
/cygdrive/c/Windows/WinSxS/amd64_dual_rdvgwddmdx11.inf_31bf3856ad364e35_10.0.18362.1_none_d782513d0562d02b/rdvgocl64.dll
/cygdrive/c/Windows/WinSxS/amd64_microsoft-windows-mccs-inproclogger_31bf3856ad364e35_10.0.18362.1_none_34817760251a052e/InprocLogger.dll
Intel HD Graphics の OpenCL については以下のページ
OpenGL*、OpenCL*、Vulkan* ドライバーは個別にインストールする必要があります。これらのドライバーを必要とするゲームまたはアプリケーションと共にのみ配布されます。
とかいう注釈があった。
どうも、Intel HD Graphics 用のドライバーとは別配布となっているということらしい。
おそらく で配布されてる SDK か runtime がそれだと思われるので、後程確認。

あと、clinfo は自作しなくても、Ubuntu だと以下の物が利用可能だった。
  • Ubuntu packages / focal (20.04 LTS) / clinfo
  • GitHub / Oblomov / clinfo
ただし Cygwin だと isspace() が「error: array subscript has type ‘char’ [-Werror=char-subscripts]」になって make に失敗するので、pull request 投げておいた。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Wiki内検索

フリーエリア

管理人/副管理人のみ編集できます