技術

XcodeでOpenCL APIのC++ Wrapperを使ってみる

前回ホストコードをC++で書いたが、CのAPIを使っていたためC++らしさはあまり表現出来ていなかった。
あれから、OpenCL APIのC++ Wrapper(OpenCL C++ Bindings)というものの存在を知ったので、それを使って前回のホストコードをさらにC++っぽく書き換えてみた。
ソース(ホストコードのみ)はこの記事の最後に載せてある。

C++で開発する際は、このWrapperがあるとかなり楽になる。
例外が使えるので、エラーチェックのためのコードを逐一挿入する必要がないし、デストラクタで各種リソースが解放されるようになってるため、基本的にその辺りを気にしなくて良い。

カーネルもC++で書けるといいのに。(環境の限定なしで。)

以下ソース。

#include <iostream>
#include <vector>
#include <string>

#define __CL_ENABLE_EXCEPTIONS
#include "cl.hpp"


int main(int argc, const char * argv[])
{
    // プラットフォーム一覧を取得
    std::vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);
    if (platforms.size() == 0) {
        std::cerr << "No platform.\n";
        return EXIT_FAILURE;
    }
    
    // 見つかったプラットフォームの情報を印字
    std::cout << platforms.size() << " platform(s) found.\n";
    for (auto p : platforms) {
        std::cout << "Platform: " << p.getInfo<CL_PLATFORM_NAME>() << "\n";
        std::cout << "Vendor: " << p.getInfo<CL_PLATFORM_VENDOR>() << "\n";
        std::cout << "Version: " << p.getInfo<CL_PLATFORM_VERSION>() << "\n";
        std::cout << "Profile: " << p.getInfo<CL_PLATFORM_PROFILE>() << "\n";
        std::cout << "\n";
    }
    
    // デバイス一覧を取得
    std::vector<cl::Device> devices;
    platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
    if (devices.size() == 0) {
        std::cerr << "No device.\n";
        return EXIT_FAILURE;
    }
    
    // 見つかったデバイスの情報を印字
    std::cout << devices.size() << " device(s) found.\n";
    for (auto d : devices) {
        std::cout << "Device: " << d.getInfo<CL_DEVICE_NAME>() << "\n";
        std::cout << "Vendor: " << d.getInfo<CL_DEVICE_VENDOR>() << "\n";
        std::cout << "Version: " << d.getInfo<CL_DEVICE_VERSION>() << "\n";
        std::cout << "Profile: " << d.getInfo<CL_DEVICE_PROFILE>() << "\n";
        std::cout << "\n";
    }
    
    // コンテキストの作成
    cl::Context ctx(devices);
    
    // コンパイル済みclプログラムの読み込み
    std::string bitcode_path = "OpenCL/kernel.cl.gpu_32.bc";
    cl::Program program = cl::Program(ctx, devices, {
        {bitcode_path.c_str(), bitcode_path.length()}
    });
    
    // プログラムのビルド
    program.build(devices);
    
    // カーネルの作成
    cl::Kernel kernel(program, "addone");
    
    // データを用意
    int n = 1000;
    std::vector<float> h_data(n);
    for (int i = 0; i < n; i++) {
        h_data[i] = float(i);
    }
    
    // デバイスメモリを確保しつつデータをコピー
    cl::Buffer d_data(ctx, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, sizeof(float) * n, h_data.data());
    
    // カーネルの引数をセット
    kernel.setArg(0, d_data);
    kernel.setArg(1, n);
    
    // コマンドキューの作成
    cl::CommandQueue q(ctx, devices[0]);
    
    // カーネルの実行
    cl::NDRange global(n, 1, 1);
    q.enqueueNDRangeKernel(kernel, cl::NullRange, global);
    
    // 結果を読み込み
    q.enqueueReadBuffer(d_data, CL_TRUE, 0, sizeof(float) * n, h_data.data());
    
    // 結果の印字
    for (int i = 0; i < n; i++) {
        std::cout << h_data[i] << ", ";
    }
    std::cout << "\n";
    
    std::cout << "Done.\n";
    return EXIT_SUCCESS;
}

コメントを残す

メールアドレスが公開されることはありません。



※画像をクリックして別の画像を表示

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください