Hello OpenCL
这一篇文章的目标是用一个最小的 Vector Add 示例,串联起 OpenCL 的核心流程,运行环境:
- platform:
QUALCOMM Snapdragon(TM) - device:
QUALCOMM Adreno(TM) 830 - version:
OpenCL 3.0 Adreno(TM) 830
1. 环境配置
宿主机需要编译环境,依赖c/cpp编译环境 + Opencl头文件 + 目标设备的动态库libOpenCL.so + Android交叉编译环境:
|
|
1.1 Android 交叉编译环境配置
如果还没有配置过 Android 交叉编译环境,需要先安装 Android NDK,配置环境变量。下面是一个示例流程:
-
步骤1:下载最新版软件包,获取地址(选择对应平台最新稳定版,点击后出现 “Android 软件开发套件许可协议”,勾选后鼠标右键下载按钮可以复制下载链接)
1 2 3 4 5 6 7 8 9 10 11# 服务器端运行 # 到指定目录下载并解压 `android_ndk` cd ~ && mkdir android_ndk && cd ~/android_ndk wget https://googledownloads.cn/android/repository/android-ndk-r29-linux.zip unzip android-ndk-r29-linux.zip # 这个文件名和下载的版本有关 # 删除压缩包 rm android-ndk-r29-linux.zip # 这个文件名和下载的版本有关 # 进入并记住解压后的目录 # 在目录里用 `pwd` 命令可以获取绝对路径 cd android-ndk-r29 # 这个目录和下载的版本有关,可以通过 `ls -lah` 显示目录 -
步骤2:配置环境变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23# 服务器端运行 # 通常会配置 `ANDROID_NDK_ROOT` 环境变量 # 但 `MNN` 中在 `project/android/build_64.sh` 使用的是 `$ANDROID_NDK` 环境变量,所以都设置一下 ➜ export ANDROID_NDK="$HOME/android_ndk/android-ndk-r29" # 环境变量 ➜ $ANDROID_NDK/ndk-build --version # 验证环境变量 GNU Make 4.3 Built for x86_64-pc-linux-gnu Copyright (C) 1988-2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. # 在命令行单次export只会在当前命令行有效 新开的终端不生效 # 需要把环境变量写到 `shell` 的配置文件中,`bash` 对应 `~/.bashrc`,`zsh` 对应 `~/.zshrc` # !!注意这里重定向是重定向文件末尾 '>>' 符号 echo 'export ANDROID_NDK="$HOME/android_ndk/android-ndk-r29"' >> ~/.zshrc # 环境变量 echo 'export ANDROID_NDK_ROOT="$HOME/android_ndk/android-ndk-r29"' >> ~/.zshrc # 环境变量 echo 'export PATH="$ANDROID_NDK:$PATH"' >> ~/.zshrc # 验证 ➜ ndk-build Android NDK: Could not find application project directory ! Android NDK: Please define the NDK_PROJECT_PATH variable to point to it. /root/android_ndk/android-ndk-r29/build/core/build-local.mk:151: *** Android NDK: Aborting . Stop.
2. 执行流程
这个最小示例的 Host 侧主线是:
|
|
2.1 初始化
首先做的是获取平台和设备,然后完成运行环境的构建。
核心流程是:
|
|
2.2. 编译Kernel
示例 kernel 保持最小,每个work item都只计算:c[i] = a[i] + b[i]。
|
|
接着在代码中编译这个kernel:
|
|
2.3 Buffer、参数绑定与执行
示例使用三块 buffer:
A:输入向量B:输入向量C:输出向量
Host 侧会先准备 CPU 数据和参考结果,然后走下面这条链:
|
|
2.4 编译运行
要在Android上运行需要拉取目标设备的动态库,宿主机编译命令如下:
|
|
支持额外参数:
--count <N>:设置向量长度--local <N>:设置本次运行的local size
|
|
这次实测输出为:
|
|
2.5 向量类型
opencl 还内置了向量类型,支持 $N=\{2,3,4,8,16\}$ 的大小。使用向量类型可以让每个 work item 处理更多数据,并且提供类似的广播机制,如下图所示。
图 1. 当标量 x 被显式转成 float4 时,会按 (x, x, x, x) 的形式广播,再与 float4 y 做逐元素计算。