コンパイル例

oneAPI アプリケーションは、ダイレクト・プログラミング、oneAPI ライブラリーを使用する API ベース、およびそれらを組み合わせて記述することができます。API ベースのプログラミングでは、ライブラリーの機能を使用してデバイスへのオフロードを行います。これにより、開発者はアプリケーションの開発時間を節約できます。一般に、API ベースのプログラミングから始め、ニーズに対応できない場合に SYCL* または OpenMP* オフロード機能を導入するのが最も容易であると考えられます。

次のセクションでは、API ベースのコードと SYCL* を使用したダイレクト・プログラミングの例を紹介します。

API ベースのコード

次のコードは、oneAPI マス・カーネル・ライブラリーの oneapi::mkl::blas::axpy 関数を使用して、浮動小数点数のベクトル間で ax を乗算し、y を加算する API 呼び出し a * x + y) の使用法を示しています。このサンプルコードは、oneAPI プログラミング・モデルを利用して、アクセラレーターで加算を実行します。

#include <vector> // std::vector() 
#include <cstdlib> // std::rand() 
#include <CL/sycl.hpp> 
#include "oneapi/mkl/blas.hpp" 

int main(int argc, char* argv[]) { 

    double alpha = 2.0; 
    int n_elements = 1024; 

    int incx = 1; 
    std::vector<double> x; 
    x.resize(incx * n_elements); 
    for (int i=0; i<n_elements; i++) 
        x[i*incx] = 4.0 * double(std::rand()) / RAND_MAX - 2.0; 
        // -2.0 から 2.0 の間の rand 値 

    int incy = 3; 
    std::vector<double> y; 
    y.resize(incy * n_elements); 
    for (int i=0; i<n_elements; i++) 
        y[i*incy] = 4.0 * double(std::rand()) / RAND_MAX - 2.0; 
        // -2.0 から 2.0 の間の rand 値 

    cl::sycl::device my_dev; 
    try { 
        my_dev = cl::sycl::device(cl::sycl::gpu_selector()); 
    } catch(...){ 
        std::cout << "Warning, failed at selecting gpu device. Continuing on default(host) device.\n"; 
    } 

    // 非同期例外をキャッチ 
    auto exception_handler = [] (cl::sycl::exception_list exceptions) { 
    for (std::exception_ptr const& e : exceptions) { 
        try { 
            std::rethrow_exception(e); 
        } catch(cl::sycl::exception const& e) { 
            std::cout << "Caught asynchronous SYCL exception:\n"; 
            std::cout << e.what() << std::endl; 
        } 
    } 
}; 

cl::sycl::queue my_queue(my_dev, exception_handler); 

cl::sycl::buffer<double, 1> x_buffer(x.data(), x.size()); 
cl::sycl::buffer<double, 1> y_buffer(y.data(), y.size()); 

// y = alpha*x + y を実行 
try { 
    oneapi::mkl::blas::axpy(my_queue, n_elements, alpha, x_buffer, incx, y_buffer, incy); 
} 

catch(cl::sycl::exception const& e) { 
    std::cout << "\t\tCaught synchronous SYCL exception:\n" << e.what() << std::endl; 
} 

std::cout << "The axpy (y = alpha * x + y) computation is complete!" << std::endl; 

// y_buffer をプリント 
auto y_accessor = y_buffer.template 
    get_access<cl::sycl::access::mode::read>(); 
std::cout << std::endl; 
std::cout << "y" << " = [ " << y_accessor[0] << " ]\n"; 
std::cout << " [ " << y_accessor[1*incy] << " ]\n"; 
std::cout << " [ " << "... ]\n"; 
    std::cout << std::endl; 

    return 0; 
}

アプリケーション (axpy.cpp として保存) をコンパイルするには、次の操作を行います:

  1. MKLROOT 環境変数が適切に設定されていることを確認します (echo ${MKLROOT})。正しく設定されていない場合、setvars.sh | oneapi-vars.sh (Linux*)、または setvars.bat | oneapi-vars.bat (Windows*) スクリプトを実行するか、lib および include フォルダーを含むディレクトリー・パスを変数に設定します。

    setvarsoneapi-vars スクリプトの詳細については、oneAPI 開発環境の設定を参照してください。

  2. 次のコマンドでアプリケーションをビルドします:

    Linux*:

    icpx -fsycl -I${MKLROOT}/include -c axpy.cpp -o axpy.o

    Windows*:

    icpx -fsycl -I${MKLROOT}/include /EHsc -c axpy.cpp /Foaxpy.obj
  3. 次のコマンドでアプリケーションをリンクします:

    Linux*:

    icpx -fsycl axpy.o -fsycl-device-code-split=per_kernel \ 
    "${MKLROOT}/lib/intel64"/libmkl_sycl.a -Wl,-export-dynamic -Wl,--start-group \ 
    "${MKLROOT}/lib/intel64"/libmkl_intel_ilp64.a \ 
    "${MKLROOT}/lib/intel64"/libmkl_sequential.a \ 
    "${MKLROOT}/lib/intel64"/libmkl_core.a -Wl,--end-group -lsycl -lOpenCL \ 
    -lpthread -lm -ldl -o axpy.out

    Windows*:

    icpx -fsycl axpy.obj -fsycl-device-code-split=per_kernel ^ 
    "${MKLROOT}\lib\intel64"\mkl_sycl.lib ^ 
    "${MKLROOT}\lib\intel64"\mkl_intel_ilp64.lib ^ 
    "${MKLROOT}\lib\intel64"\mkl_sequential.lib ^ 
    "${MKLROOT}\lib\intel64"\mkl_core.lib ^ 
    sycl.lib OpenCL.lib -o axpy.exe
  4. 次のコマンドでアプリケーションを実行します:

    Linux*:

    ./axpy.out

    Windows*:

    axpy.exe

ダイレクト・プログラミング

ここでは、ベクトル加算のサンプルコードを使用します。このサンプルコードは、oneAPI プログラミング・モデルを利用して、アクセラレーターで加算を実行します。

次のコマンドは、実行形式をコンパイルしてリンクします:

icpx -fsycl vector_add.cpp

コマンドとオプションのコンポーネントと関数は、「API ベースのコード」セクションで説明したものと類似しています。

このコマンドを実行すると、実行時にベクトルの加算を実行する実行ファイルが作成されます。