view paper/opencl.tex @ 6:41d37434e62c

fix
author Yuhi TOMARI <yuhi@cr.ie.u-ryukyu.ac.jp>
date Mon, 01 Apr 2013 21:51:11 +0900
parents 771aaa69c616
children
line wrap: on
line source

\section{OpenCL}
OpenCLとは、マルチコアCPUとGPUのようなヘテロジニアスな環境を利用した並列計算を支援するフレームワークである。
このフレームワークを用いてCeriumをGPGPUに対応させる。

OpenCLには主に2つの仕様がある。

\begin{itemize}
\item OpenCL C言語
\item OpenCL ランタイムAPI
\end{itemize}
OpenCL Cは演算用プロセッサ(本研究ではGPU)上で動作する、C言語を拡張したプログラミング言語である。
一方でOpenCLランタイムAPIはOpenCL Cで記述したプログラムをGPU上で実行させるため、
制御用のプロセッサ(本研究ではCPU)が利用するAPIである。

OpenCLではGPU側をkernel、制御デバイス側をhostとして定義する。

\subsection{Command Queue}
OpenCLでは、デバイスの操作にCommand Queueを使用する。
Command QueueはKernelに命令を送るための仕組みである。
Command QueueはclCreateCommandQueueというOpenCL APIで作成され、
Command Queueが所属するコンテキストや実行対象となるデバイスを指定する。

Kernelの実行、input dataへの書き込み、output data の読み込みといった
メモリ操作はこのCommand Queueを通して行われる。

\subsection{メモリアクセス}
host側は主にdataをinput/outputするメモリ資源の確保を行う。
GPUのメモリ空間(図\ref{fig:gpuarch})やCellのメモリ空間(図\ref{fig:cellarch})
はマルチコアCPU(図\ref{fig:cpuarch})と違い、共有メモリでないためhostとkernel(task)間でdataの共有ができない。
アクセスするにはメモリ空間間でコピーしなければならない。

GPGPUではhost側で memory bufferを作成してメモリのコピーを行う。
これらの処理やTaskはCommand Queueにenqueueすることで実行される。
\begin{figure}[htb]
  \begin{center}
    \includegraphics[scale=0.3]{./images/gpu_arch.pdf}
  \end{center}
  \caption{Gpu Archtecture}
  \label{fig:gpuarch}
\end{figure}

\begin{figure}[ht]
  \begin{center}
    \includegraphics[scale=0.5]{./images/cell_arch.pdf}
  \end{center}
  \caption{Cell Archtecture}
  \label{fig:cellarch}
\end{figure}

\begin{figure}[ht]
  \begin{center}
    \includegraphics[scale=0.5]{./images/cpu_arch.pdf}
  \end{center}
  \caption{Cpu Archtecture}
  \label{fig:cpuarch}
\end{figure}

\subsection{データ並列}
多次元のデータ構造がある場合に高い並列度を保つには、それを分割して並列に実行する機能が必要である。
これをOpen CLではデータ並列と読んでいる。
OpenCLは次元数に対応するindexがあり、openclは一つの記述から異なるindexを持つ複数のkernelを自動生成する。
その添字をglobal\_idとよぶ
この時入力されたデータはワークアイテムという処理単位に分割される。

OpenCLはワークアイテムに対してそれぞれを識別するID(global\_id)を割り当てる。
kernelはget\_global\_id APIによってIDを取得し、取得したIDに対応するデータに対して処理を行い、
データ並列を実現する。
このIDによって取得してきたワークアイテムをグローバルワークアイテムという。
また、ワークアイテムは3次元までのデータを渡すことができる。

データ並列によるkernel実行の場合はclEnqueueNDRangeKernel APIを使用するが、
この関数の引数としてワークアイテムのサイズと次元数を指定することでデータ並列で実行できる。

\subsection{ワークグループ}
前節でワークアイテムという処理単位について述べたが、
さらに複数個のグローバルワークアイテムをwork\_groupという単位にまとめることができる。
work\_group内では同期やローカルメモリの共有が可能となる。

グローバルワークアイテム(ワークアイテム全体)の個数と、
ローカルワークアイテム(グループ一つ辺りのアイテム)の個数を指定することでワークアイテムを分割する。
なお、このときグローバルワークアイテム数はローカルアイテム数の整数倍でなければ
clEnqueueNDRangeKernel API呼び出しは失敗する。

ローカルアイテム数は0を指定することで、コンパイル時に最適化させることができる。
したがってローカルアイテムのサイズは0を指定するのが一般的である。

\begin{figure}[htb]
  \begin{center}
    \includegraphics[scale=0.60]{./images/workitem.pdf}
  \end{center}
  \caption{WorkItem ID}
  \label{fig:workitem_id}
\end{figure}

なお、work\_groupを設定した場合はglobal\_idの他にwork\_group\_id、local\_idが
それぞれのkernelに割り当てられる(図:\ref{fig:workitem_id})。

kernel側からそれぞれIDに対応したAPIを使用して、各IDを取得する。
取得したIDから自分が担当するindexを計算して導く。
表:\ref{table:kernel_id_api}はkernel側で使用できる、IDを取得するためのAPIとなる。
\begin{tiny}
  \begin{table}[h]
    \begin{center}
      \caption{kernelで使用するID取得のAPI}
      \label{table:kernel_id_api}
      \small
      \begin{tabular}[t]{c|l}
        \hline
        get\_group\_id & work\_group\_idを取得  \\
        \hline
        get\_local\_id & local\_idを取得 \\
        \hline
        get\_global\_id &  global\_idを取得 \\
        \hline
      \end{tabular}
    \end{center}
  \end{table}
\end{tiny}
なお、local\_id、global\_idを取得するAPIは引数に0、1、2の値をsetすることができる。
idはx,y,z座標があり、それぞれが0,1,2に対応している。
例えばget\_global\_id(1)と呼び出した場合はy座標の、
get\_global\_id(1)と呼び出した場合はz座標のglobal\_idを取得する。