Mercurial > hg > Papers > 2013 > yuhi-sigos
view paper/data_parallel.tex @ 3:bb436935f877
add images
author | Yuhi TOMARI <yuhi@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 01 Apr 2013 21:20:34 +0900 |
parents | 771aaa69c616 |
children |
line wrap: on
line source
\section{Ceriumにおけるデータ並列} OpenCLで充分な並列度を得るには、データ並列による実行をサポートした方が良い。 ceriumでopenclのデータ並列を使うために、iteratorというAPIを用意した。 ベンチマークをとるために、まずはCPU(many core)上でデータ並列の機構を実装した。 OpenCLでデータ並列を行う際は、NDRangeの引数でワークアイテムのサイズを設定し、以下のようにkernelを書けばよい。 \begin{verbatim} __kernel void multi(__global const float *i_data1, __global const float *i_data2, __global float *o_data) { int i = get_global_id(0); o_data[i] = i_data1[i]*i_data2[i]; } \end{verbatim} kernelを複数生成し、各kernelは自分が担当するindexをget\_global\_id APIで取得し、 その部分だけ計算を行う。CPUで実行する場合もGPU実行時のkernelとなるべく近い形式で記述できるようにする。 \subsection{データ並列実行の機構} データ並列で実行する場合はspawn APIではなく、iterate APIでtaskを生成すればよい。 Scheduler内で引数分taskを生成し、それぞれに自分が担当するindexをパラメタとして設定していく。 iterateにはlengthを引数として渡し、lengthの値と渡したlengthの個数でdimensionや ワークアイテムのサイズをSchedulerが計算する。 CPU実行時のkernelは以下のように記述する。 \begin{verbatim} static int // kernel run(SchedTask *s,void *rbuf, void *wbuf) { float *indata1,*indata2,*outdata; indata1 = (float*)s->get_input(rbuf, 0); indata2 = (float*)s->get_input(rbuf, 1); outdata = (float*)s->get_output(wbuf, 0); long i = (long)s->get_param(0); outdata[i]=indata1[i]*indata2[i]; return 0; } \end{verbatim} \subsection{Ceriumでのデータ並列におけるindex割り当ての実装} taskを生成するとき、dimensionとワークアイテムのサイズをもとに各taskが担当するindexを計算し、set\_paramする。 kernelはget\_paramでそのindexを取得してデータ並列で実行する。 get\_param APIがopenCLのget\_global\_id APIに相当する。 例として、cpu数4、一次元で10個のdataにたいしてデータ並列実行を行った場合、 各CPUが担当するindexは表:\ref{table:data_parallel_index}のようになる。 この例だと各CPUに対するindexの割り当ては、 CPU0はindex0、4、8、 CPU1はindex1、5、9、 CPU2はindex2、6、 CPU3はindex3、7となっている。 \begin{tiny} \begin{table}[h] \begin{center} \caption{data並列実行時のindexの割り当て} \label{table:data_parallel_index} \small \begin{tabular}[t]{c||c|c|c|c} \hline stage&CPU0& CPU1&CPU2&CPU3 \\ \hline 1&0&1&2&3 \\ \hline 2&4&5&6&7 \\ \hline 3&8&9& & \\ \hline \end{tabular} \end{center} \end{table} \end{tiny} この実装により、Ceriumでデータ並列の実行が可能になった。 並列プログラミングだと、並列化するtaskが全部同一であるという事は少なくない。 その際、task生成部分を何回もループで回すことなく、簡単なsyntaxで記述できる。 データ並列で実行する場合は、inputとoutputを各taskで共有するため、少ないコピーですむ。 CPUならメモリ領域がtaskとmanagerで同じなので、dataのコピーで大きいオーバーヘッドにはならない。 しかしCellとGPUはメモリ領域が異なるため、dataコピーのオーバーヘッドが大きく、 データ並列による高速化が見込める。