LoginSignup
6
5

More than 3 years have passed since last update.

Android で OpenCL を試す

Last updated at Posted at 2019-12-30

OpenCL

OpenCL(Open Computing Language)は、マルチコアCPUやGPU などによる異種混在の計算資源において、
並列コンピューティングのためのクロスプラットフォームなAPIである。
標準化団体のクロノス・グループ(Khronos Group) によって仕様が策定され、
ロイヤリティフリーなオープン仕様として公開されている。

wikipedia : OpenCL

Android では、公式にはサポートされていないが。
CPU/GPUメーカーによりサポートされている。
機種依存性 高し。

Android上でのOpenCLの現状

Android で OpenCLの環境を作る

まず、CPU と GPUのメーカーと型番を調べる。

Nexus5 で実行した例

CPU

$ adb shell cat /proc/cpuinfo | grep Hardware
Hardware : Qualcomm MSM 8974 HAMMERHEAD (Flattened Device Tree)

GPU

$ adb shell dumpsys | grep GLES
GLES: Qualcomm, Adreno (TM) 330, OpenGL ES 3.0 V@127.0 AU@ (GIT@I96aee987eb)

これに対応したOpenCLドライバーを入手する。

Getting Started with OpenCL on Android

OpenCL on Mobile Devices

Qualcomm のサイトから OpenCLドライバーを入手すると、
ROM イメージを入れ替えるように記載されている。

Qualcomm Tools & Resources

もっと簡易な方法がないか調べてみると、
アプリに OpenCL ドライバーを同封する方法が見つかった。
githubリポジトリには、 Adreno 330 用のドライバーと、
ヘッダーファイルが同封されている。
今回は、これを試す。

github : OpenCL-android

下記にて OpenCL ドライバーが配布されているが、
動作せず。

github : Proprietary OpenCL drivers for Android

OpenCL ヘッダーファイルは
Khronos の github リポジトリで配布されている。
これに置き換えても動作する。

github : Khronos OpenCL-Headers

アプリを作成する

下記のプロジェクトファイルを自分の環境に合わせる。

github : OpenCL-android

下記を参考にした。

CMakeLists.txt

# OpenCL Header 
set(OPENCL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../opencl)
set(LIB "${OPENCL_DIR}/lib")
include_directories(${OPENCL_DIR}/include)

# OpenCL Driver 
add_library(libOpenCL SHARED IMPORTED )
set_target_properties(libOpenCL PROPERTIES
    IMPORTED_LOCATION "${LIB}/${ANDROID_ABI}/libOpenCL.so")

# C++ コード をコンパイルする
add_library( 
             ${target}
             SHARED
             native-lib.cpp )

# ターゲットをビルドする
target_link_libraries( # Specifies the target library.
                        ${target} 
                        libOpenCL
                       ${log-lib} )

# "libOpenCL.so" をアプリに同封する
  configure_file(
    "${LIB}/${ANDROID_ABI}/libOpenCL.so" 
    "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libOpenCL.so" 
    COPYONLY)

大きな修正が1つ必要です。

下記のようにカーネルファイルを読み込んでいる。

std::ifstream kernelFile(fileName, std::ios::in);

しかし、ネティブコードではアプリのファルダーにあるファイルは読み込めない。

Java にて、アプリのファルダーにあるファイルを読み込んで、
アプリごとのファイル領域にコピーして、
そのファイルパスをネティブコードに通知する方法にする。


    protected void onResume() {

        // カーネルファイルをコピ=してファイルパス名を取得する
        String path = AssetFile.getFilePath(this, CL_FILE_NAME);
        // ネティブコードを実行する
        String text = stringFromJNI(path);

そのほかの修正。
元のプログラムでは、OpenCLのカーネルが正しく動作しているかを確認していない。
ホスト側 (CPU)  と ターゲット側(GPU) で同じ計算を行い、照合するようにした。

native-lib.cpp

// result1 : CPU の計算結果
// result2 :  GPU の計算結果

    for(int k = 0;k <  ARRAY_SIZE;k++){
        float f1 = result1[k];
        float f2 = result2[k];
        int r1 = (int)f1;
        int r2 = (int)f2;
        // LOGD("result: %f", f2);

// 照合する
        if (r1 != r2) {
             LOGD("unmstch: %f , %f", f1, f2);
            return 1;
        }
    }

アプリを実行する

analyze apk により下記の2つが同封されていることが確認できる。
- libnative_lib.so
- libOpenCL.so
opencl1_analyze_apk.png

スクリーンショット
CPUとGPUの計算に要した時間を表示する
opencl1_main.png

GPU の方が遅くなっている。
メモリ転送などのオーバーヘッドによるものと思われる。

C++でOpenCL(高速化編)

サンプルコードをgithub に公開した。
https://github.com/ohwada/Android_Samples/tree/master/OpenCL1

関連記事

6
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5