CLBufferWrite

OpenCL バッファに書き込み、書かれた要素の数を返します。

uint  CLBufferWrite(
  int          buffer,                   // OpenCL バッファハンドル
  const void&  data[],                   // 値の配列
  uint         buffer_offset=0,           // OpenCL バッファ内のバイト単位のオフセット(デフォルトで 0)
  uint         data_offset=0,             // OpenCL バッファ内の要素数でのオフセット(デフォルトで 0)
  uint        data_count=WHOLE_ARRAY     // 書かれる配列の値の数(デフォルトでは配列全体)
  );

行列とベクトルを処理するためのバージョンもあります。

行列の値をバッファに書き込み、成功した場合は true を返します。

uint  CLBufferWrite(
  int          buffer,                   // OpenCL バッファハンドル
  uint         buffer_offset,             // OpenCL バッファ内のバイト単位のオフセット
  matrix<T>    &mat                       // バッファに書き込む値の行列
  );

ベクトルの値をバッファに書き込み、成功した場合は true を返します。

uint  CLBufferWrite(
  int          buffer,                   // OpenCL バッファハンドル
  uint         buffer_offset,             // OpenCL バッファ内のバイト単位のオフセット
  vector<T>    &vec                     // バッファに書き込む値のベクトル
  );

パラメータ

buffer

[in]  OpenCL バッファハンドル

data[]

[in]  OpenCL バッファに書かれる値の配列。参照で引き渡されます。

buffer_offset

[in]  OpenCL バッファ内のバイト単位での読み込みが始まるオフセット。デフォルトでは書き込みはバッファの一番初めから始まります。

data_offset

[in]  OpenCLのバッファに値を書き込むための最初の配列要素のインデックス。デフォルトでは配列の一番初めの値が使用されます。

data_count

[in]  書き込まれる値の数。デフォルトでは配列の値全部。

mat

[out] バッファにデータを書き込む行列は、matrix、matrixf、matrixc の 3 つのタイプのいずれかです。

vec

[out] バッファにデータを書き込むベクトルは、vector、vectorf、vectorc の 3 つのタイプのいずれかです。

戻り値

書かれた要素の数。エラーの場合 0 。エラー情報を取得するには、GetLastError() 関数が呼ばれます。

行列またはベクトルが正常に処理された場合は true、それ以外の場合は false

注意事項

1 次元配列では OpenCL バッファへの書き入れのための読み込みが始まる要素の番号は AS_SERIESフラグを考慮して計算されます。

2 次元以上の配列は1 次元として提示されます。この場合 data_offset は、1 次元目の要素の数ではなく、抜かされるべき要素の数です。

MatMul メソッドと OpenCL での並列計算を使用した行列乗算の

#define M       3000     // 1 番目の行列の行数
#define K       2000     // 1 番目の行列の列数は 2 番目の行列の行数と同じ
#define N       3000     // 2 番目の行列の列数
 
//+------------------------------------------------------------------+
const string clSrc=
"#define N     "+IntegerToString(N)+"                              \r\n"
"#define K     "+IntegerToString(K)+"                              \r\n"
"                                                                  \r\n"
"__kernel void matricesMul( __global float *in1,                   \r\n"
"                           __global float *in2,                   \r\n"
"                           __global float *out  )                 \r\n"
"{                                                                 \r\n"
"  int m = get_global_id( 0 );                                     \r\n"
"  int n = get_global_id( 1 );                                     \r\n"
"  float sum = 0.0;                                                \r\n"
"  for( int k = 0; k < K; k ++ )                                   \r\n"
"     sum += in1[ m * K + k ] * in2[ k * N + n ];                  \r\n"
"  out[ m * N + n ] = sum;                                         \r\n"
"}                                                                 \r\n";
//+------------------------------------------------------------------+
//| スクリプトプログラム開始関数                                             |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 擬似乱数生成器を初期化する
MathSrand((int)TimeCurrent());
//--- 指定されたサイズの行列にランダムな値を書き込む
matrixf mat1(M, K, MatrixRandom) ;   // 1 番目の行列
matrixf mat2(K, N, MatrixRandom);     // 2 番目の行列
 
//--- 単純な方法を使用して行列の積を計算する
uint start=GetTickCount();
matrixf matrix_naive=matrixf::Zeros(M, N);// 2 つの行列を乗算した結果がここに設定される
for(int m=0; m<M; m++)
  for(int k=0; k<K; k++)
    for(int n=0; n<N; n++)
      matrix_naive[m][n]+=mat1[m][k]*mat2[k][n];
uint time_naive=GetTickCount()-start;  
   
//--- MatMull を使用して行列の積を計算する
start=GetTickCount();
matrixf matrix_matmul=mat1.MatMul(mat2);
uint time_matmul=GetTickCount()-start;    
 
//--- OpenCL で行列の積を計算する
matrixf matrix_opencl=matrixf::Zeros(M, N);
int cl_ctx;             // コンテキストハンドル
if((cl_ctx=CLContextCreate(CL_USE_GPU_ONLY))==INVALID_HANDLE)
  {
  Print("OpenCL not found, leaving");
  return;
  }
int cl_prg;             // プログラムハンドル
int cl_krn;             // カーネルハンドル
int cl_mem_in1;         // 1 番目の(入力)バッファハンドル
int cl_mem_in2;         // 2 番目の(入力)バッファハンドル
int cl_mem_out;         // 3 番目の(出力)バッファハンドル
//--- プログラムとカーネルを作成する
cl_prg = CLProgramCreate(cl_ctx, clSrc);
cl_krn = CLKernelCreate(cl_prg, "matricesMul");
//--- 3 つの行列に対して 3 つのバッファすべてを作成する
cl_mem_in1=CLBufferCreate(cl_ctx, M*K*sizeof(float), CL_MEM_READ_WRITE);
cl_mem_in2=CLBufferCreate(cl_ctx, K*N*sizeof(float), CL_MEM_READ_WRITE);
//--- 3 番目の行列 - 出力
cl_mem_out=CLBufferCreate(cl_ctx, M*N*sizeof(float), CL_MEM_READ_WRITE);
//--- カーネル引数を設定する
CLSetKernelArgMem(cl_krn, 0, cl_mem_in1);
CLSetKernelArgMem(cl_krn, 1, cl_mem_in2);
CLSetKernelArgMem(cl_krn, 2, cl_mem_out);
//--- 行列をデバイスバッファに書く
CLBufferWrite(cl_mem_in1, 0, mat1);
CLBufferWrite(cl_mem_in2, 0, mat2);
CLBufferWrite(cl_mem_out, 0, matrix_opencl);
//--- OpenCL コード実行時間の開始
start=GetTickCount();
//--- タスクの作業領域のパラメータを設定し、OpenCL プログラムを実行する
uint offs[2] = {0, 0};
uint works[2] = {M, N};
start=GetTickCount();  
bool ex=CLExecute(cl_krn, 2, offs, works);
//--- 結果を行列に計算する
if(CLBufferRead(cl_mem_out, 0, matrix_opencl))
  PrintFormat("[%d x %d] matrix read: ", matrix_opencl.Rows(), matrix_opencl.Cols());
  else
    Print("CLBufferRead(cl_mem_out, 0, matrix_opencl failed. Error ",GetLastError());
uint time_opencl=GetTickCount()-start;  
Print("Compare calculation time using each method");
PrintFormat("Naive product time = %d ms",time_naive);
PrintFormat("MatMul product time = %d ms",time_matmul);
PrintFormat("OpenCl product time = %d ms",time_opencl);  
//--- すべての OpenCL コンテキストを解放する
CLFreeAll(cl_ctx, cl_prg, cl_krn, cl_mem_in1, cl_mem_in2, cl_mem_out);
 
//--- 得られたすべての結果行列を相互に比較する
Print("How many discrepancy errors are there between result matrices?");
ulong errors=matrix_naive.Compare(matrix_matmul,(float)1e-12);
Print("matrix_direct.Compare(matrix_matmul,1e-12)=",errors);
errors=matrix_matmul.Compare(matrix_opencl,float(1e-12));
Print("matrix_matmul.Compare(matrix_opencl,1e-12)=",errors);
/*
  結果:
 
  [3000 x 3000] matrix read:
  各方法での計算時間の比較
  Naive product time = 54750 ms
  MatMul product time = 4578 ms
  OpenCl product time = 922 ms
  結果行列間にあった不一致エラーの数
  matrix_direct.Compare(matrix_matmul,1e-12)=0
  matrix_matmul.Compare(matrix_opencl,1e-12)=0
*/  
}
//+------------------------------------------------------------------+
//| 行列にランダムな値を書き込む                                             |
//+------------------------------------------------------------------+
void MatrixRandom(matrixf& m)
{
for(ulong r=0; r<m.Rows(); r++)
  {
  for(ulong c=0; c<m.Cols(); c++)
    {
    m[r][c]=(float)((MathRand()-16383.5)/32767.);
    }
  }
}
//+------------------------------------------------------------------+
//| すべての OpenCL コンテキストを解放する                                     |
//+------------------------------------------------------------------+
void CLFreeAll(int cl_ctx, int cl_prg, int cl_krn,
              int cl_mem_in1, int cl_mem_in2, int cl_mem_out)
{
//--- OpenCL によって作成されたすべてのコンテキストを逆の順序で削除する
CLBufferFree(cl_mem_in1);
CLBufferFree(cl_mem_in2);
CLBufferFree(cl_mem_out);
CLKernelFree(cl_krn);
CLProgramFree(cl_prg);
CLContextFree(cl_ctx);
}