Coral Edge TPU Dev Board の OpenCL 環境を確認

# 1. 概要
　[前回記事](https://qiita.com/terryky/items/a639ea48f1cf240e8929) では、Coral EdgeTPU Dev Board 上で、TensorFlow Lite の GPU Delegate (**OpenGLES版**)を試しました。
　一方で、GPU Delegate には **OpenCL版** もあり、かねてからこちらも試してみたいと思っていました。

　EdgeTPU DevBoard の GPU は、[カタログスペック](https://coral.withgoogle.com/docs/dev-board/datasheet/) によれば、 OpenGLES3.1 に加えて OpenCL にも対応しているので、うまくやれば DevBoard 上で GPU Delegate (**OpenCL版**) を動かせるはずです。（前回同様、EdgeTPU DevBoard なのに EdgeTPU を使いません。）

　今回の記事では、その第一歩として、EdgeTPU DevBoard における OpenCL の動作環境構築までを書いてみます。

# 2. 必要ファイルの確認
　この作業に着手する前は、「そもそも DevBoard 上で OpenCL アプリをビルドするために必要なヘッダファイルやライブラリは、どこかに用意されてるのか？」という心配もあったのですが、あっけなく見つかりました。DevBoard 上に最初から存在しているようです。

#### ■OpenCL ヘッダファイル
```
mendel@green-rabbit:~$ ls -l /usr/include/CL
total 188
-rw-r--r-- 1 root root 74542 Jun 14  2016 cl.h
-rw-r--r-- 1 root root 18168 Sep  8  2016 cl_ext.h
-rw-r--r-- 1 root root 43558 Sep  8  2016 cl_platform.h
-rw-r--r-- 1 root root  1993 Jun 14  2016 opencl.h
(以下略)
```

#### ■OpenCL ライブラリ
```
mendel@green-rabbit:~$ ls -l /usr/lib/vivante/
total 17904
-rw-r--r-- 1 root root 2161664 Mar 20  2019 libCLC.so
-rw-r--r-- 1 root root 4322368 Mar 20  2019 libLLVM_viv.so
-rw-r--r-- 1 root root   26928 Mar 20  2019 libOpenCL.so
-rw-r--r-- 1 root root  372872 Mar 20  2019 libSPIRV_viv.so
-rw-r--r-- 1 root root  320440 Mar 20  2019 libVivanteOpenCL.so
(以下略)
```
　DevBoard 上で、上記ファイルを使ってネイティブビルドすれば、OpenCL アプリをビルドすることができそうです。


# 3. OpenCL デバイスクエリ
　とっかかりのOpenCLアプリとして、Dev Board の GPU がどのような OpenCL デバイスとして見えるのかを確認するQueryアプリを作りました。

## 3.1 Queryアプリの実装
　下記のように、OpenCL プラットフォーム および OpnCL デバイスに関する情報取得を行うAPIを一通り叩くようなコードを準備します。
　特に目新しいコードではありませんが、実際に私が使ったコードは、[ここ](https://github.com/terryky/tflite_cl_app/tree/master/query_cl_devices) で公開しています。

```C:main.c
#include <CL/cl.h>

#define PRINT_PLATFORM_INFO_STR(pf_id, param_name)              \
    do                                                          \
    {                                                           \
        char strbuf[1024];                                      \
        clGetPlatformInfo (pf_id, param_name, sizeof(strbuf), strbuf, NULL); \
        fprintf (stderr, " %-24s: %s\n", #param_name, strbuf);  \
    } while (0)

opencl_device_query () 
{
    cl_platform_id* pf_ids;
    cl_uint i, j, num_platforms;

    /* OpenCL プラットフォーム数を取得し、全てのプラットフォームID を取得 */
    clGetPlatformIDs (0, NULL, &num_platforms);

    pf_ids = (cl_platform_id*)malloc (num_platforms * sizeof (cl_platform_id));
    clGetPlatformIDs (num_platforms, pf_ids, NULL);

    /* i 番目のプラットフォームに関する Query */
    for (i = 0; i < num_platforms; i++)
    {
        cl_platform_id pf_id = pf_ids[i];
        cl_uint      num_devices;
        cl_device_id *devices;

        PRINT_PLATFORM_INFO_STR(pf_id, CL_PLATFORM_NAME);
        PRINT_PLATFORM_INFO_STR(pf_id, CL_PLATFORM_VENDOR);
        PRINT_PLATFORM_INFO_STR(pf_id, CL_PLATFORM_VERSION);
        PRINT_PLATFORM_INFO_STR(pf_id, CL_PLATFORM_PROFILE);
        PRINT_PLATFORM_INFO_STR(pf_id, CL_PLATFORM_EXTENSIONS);

        /* i 番目のプラットフォームに属する全てのデバイスIDを取得 */
        clGetDeviceIDs (pf_id, CL_DEVICE_TYPE_ALL, 0, NULL, &num_devices);

        devices = (cl_device_id *)malloc (sizeof(cl_device_id) * num_devices);
        clGetDeviceIDs (pf_id, CL_DEVICE_TYPE_ALL, num_devices, devices, &num_devices);

        for (j = 0; j < num_devices; j++)
        {
            query_cldev (devices[j]);
        }
    }
}
```
## 3.2 Queryアプリのビルド
　上記ソースコードは、DevBoard 上でネイティブビルドすれば、至ってシンプルにビルドすることができました。

```
mendel@green-rabbit:~$ gcc -L/usr/lib/vivante -lOpenCL main.c
mendel@green-rabbit:~$ ls -l a.out
-rwxr-xr-x 1 mendel mendel 18008 Nov  3 12:58 a.out*
```

## 3.3 Queryアプリ実行結果
　上記アプリを DevBoard 上で実行すると、下記のようなQuery結果が表示されます。
　OpenCL 1.2 Full Profile (DEVICE_TYPE=GPU) のデバイスとして、ちゃんと見えているようです。

```
--------------------------------------------------------
 OpenCL Platform [0/1]
--------------------------------------------------------
 CL_PLATFORM_NAME        : Vivante OpenCL Platform
 CL_PLATFORM_VENDOR      : Vivante Corporation
 CL_PLATFORM_VERSION     : OpenCL 1.2 V6.2.4.p2.163672
 CL_PLATFORM_PROFILE     : FULL_PROFILE
 CL_PLATFORM_EXTENSIONS  : cl_khr_icd

 ----------------------------------
  CL Device [0/1]
 ----------------------------------
  CL_DEVICE_NAME                          : Vivante OpenCL Device GC7000L.6214.0000
  CL_DEVICE_VENDOR                        : Vivante Corporation
  CL_DRIVER_VERSION                       : OpenCL 1.2 V6.2.4.p2.163672
  CL_DEVICE_OPENCL_C_VERSION              : OpenCL C 1.2
  CL_DEVICE_PROFILE                       : FULL_PROFILE
  CL_DEVICE_AVAILABLE                     : true
  CL_DEVICE_COMPILER_AVAILABLE            : true
  CL_DEVICE_TYPE                          : CL_DEVICE_TYPE_GPU
  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_gl_sharing
  CL_DEVICE_VENDOR_ID                     : 5654870
  CL_DEVICE_MAX_COMPUTE_UNITS             : 1
  CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS      : 3
  CL_DEVICE_MAX_WORK_ITEM_SIZES           : 1024 / 1024 / 1024
  CL_DEVICE_MAX_WORK_GROUP_SIZE           : 1024
  CL_DEVICE_MAX_CLOCK_FREQUENCY           : 800 MHz
  CL_DEVICE_ADDRESS_BITS                  : 32
  CL_DEVICE_MAX_MEM_ALLOC_SIZE            : 128 MByte
  CL_DEVICE_GLOBAL_MEM_SIZE               : 256 MByte
  CL_DEVICE_ENDIAN_LITTLE                 : true
  CL_DEVICE_HOST_UNIFIED_MEMORY           : true
  CL_DEVICE_ERROR_CORRECTION_SUPPORT      : true
  CL_DEVICE_LOCAL_MEM_TYPE                : global
  CL_DEVICE_LOCAL_MEM_SIZE                : 32 KByte
  CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE      : 64 KByte
  CL_DEVICE_QUEUE_PROPERTIES              : CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE
  CL_DEVICE_QUEUE_PROPERTIES              : CL_QUEUE_PROFILING_ENABLE
  CL_DEVICE_IMAGE_SUPPORT                 : true
  CL_DEVICE_MAX_READ_IMAGE_ARGS           : 128
  CL_DEVICE_MAX_WRITE_IMAGE_ARGS          : 8
  CL_DEVICE_IMAGE2D_MAX_WIDTH             : 8192
  CL_DEVICE_IMAGE2D_MAX_HEIGHT            : 8192
  CL_DEVICE_IMAGE3D_MAX_WIDTH             : 8192
  CL_DEVICE_IMAGE3D_MAX_HEIGHT            : 8192
  CL_DEVICE_IMAGE3D_MAX_DEPTH             : 8192
  CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR   : 4
  CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT  : 4
  CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT    : 4
  CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG   : 4
  CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT  : 4
  CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE : 0
  CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF   : 0
  CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR      : 4
  CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT     : 4
  CL_DEVICE_NATIVE_VECTOR_WIDTH_INT       : 4
  CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG      : 4
  CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT     : 4
  CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE    : 0
  CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF      : 0
```

# 4. 最後に
　EdgeTPU DevBoard 上で、OpenCL デバイスクエリに成功しました。
　(まだ CLカーネルは１つも動かしてませんが、）EdgeTPU DevBoard 上で OpenCL は動きそうな感じがしてきたので、引き続き、TensorFlow Lite (**OpenCL版**) に挑戦したいと思います。