Mercurial > hg > Papers > 2013 > yuhi-prosym
view presen/index.html @ 29:6b60c1277599 default tip
fix
author | Yuhi TOMARI <yuhi@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 12 Jan 2014 09:18:32 +0900 |
parents | d6d545336b5c |
children |
line wrap: on
line source
<!-- Google IO 2012 HTML5 Slide Template Authors: Eric Bidelman <ebidel@gmail.com> Luke Mahé <lukem@google.com> URL: https://code.google.com/p/io-2012-slides --> <!DOCTYPE html> <html> <head> <title>Google IO 2012</title> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="chrome=1"> <!--<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">--> <!--<meta name="viewport" content="width=device-width, initial-scale=1.0">--> <!--This one seems to work all the time, but really small on ipad--> <!--<meta name="viewport" content="initial-scale=0.4">--> <meta name="apple-mobile-web-app-capable" content="yes"> <link rel="stylesheet" media="all" href="theme/css/default.css"> <link rel="stylesheet" media="only screen and (max-device-width: 480px)" href="theme/css/phone.css"> <base target="_blank"> <!-- This amazingness opens all links in a new tab. --> <script data-main="js/slides" src="js/require-1.0.8.min.js"></script> </head> <body style="opacity: 0"> <slides class="layout-widescreen"> <slide class="title-slide segue nobackground"> <!-- The content of this hgroup is replaced programmatically through the slide_config.json. --> <hgroup> <h1 data-config-title><!-- populated from slide_config.json --></h1> <h2 data-config-subtitle><!-- populated from slide_config.json --></h2> <p data-config-presenter><!-- populated from slide_config.json --></p> </hgroup> </slide> <slide> <hgroup> <h3>研究目的(1/2)</h3> </hgroup> <article> <p> 当研究室ではPS3およびLinux、 Mac OSX上で動く並列プログラミングフレームワーク、 Ceriumの開発・改良を行っている </p> <p> CeriumはGPU上での並列実行に対応している <p> <font color="red">ヘテロジニアス(異種混合)環境下でのプログラミングをサポート</font> </p> <img src='images/cerium_resource.png' style="height:300px"> </article> </slide> <slide> <hgroup> <h3>研究目的(2/2)</h3> </hgroup> <article> <p> GPGPUでは通常のマルチコア<font color="red">CPUとは異なる並列プログラミング</font> と<font color="red">特別なチューニング</font>が必要となる。 そこでCeriumを用いてその差を吸収し、自動的なチューニングを可能にする。 </p> チューニングの一環として、以下を可能にした <ul> <li>Taskのデータ並列実行</li> <li>CPUとGPU両方でTaskを実行</li> </ul> <img src='images/exe_cpu_gpu.png' style="height:300px"> </article> </slide> <slide> <hgroup> <h3>OpenCLによるGPGPUへの対応</h3> </hgroup> <article> <p> OpenCLは ヘテロジニアス環境での並列計算を支援するフレームワーク </p> <table border="0" cellpadding="0" cellspacing="0"> <tbody> <tr> <td><img src='images/opencl.png' style="height:120px"></td> <td style="font-size:18pt;color:black"> <p> OpenCLのtaskはkernelと呼ばれ、OpenCL Cという Cに似た独自の言語で記述される </p> </td> </tr> </tbody> </table> <p> <h3 class='yellow'>Ceriumにおいて、CPU/Cell上で実行する場合とGPU上で実行する場合、 それぞれほぼ同じ形式でkernelを記述できる </h3> </p> </article> </slide> <slide> <hgroup> <h3>Kernelの記述</h3> </hgroup> 2つのinputDataの積を取り、outputDataに返す例題Multiply <table border="0" cellpadding="0" cellspacing="0"> <tbody> <tr> <td> <img src='images/kernel_description.png' style="height:570px"> </td> <td style="font-size:18pt;color:black"> <p> Taskの処理自体はC/C++の形式なので、同じ記述が可能。 </p> <p> 引数の受け取り方が違う。 <ul> <li>CPU <dd>rbuf/wbufとしてDataをまとめて受け取っている</dd></li> <li>GPU <dd>1つ1つ個別の変数として受け取っている</dd> <dd>それぞれの変数にOpenCL独自の修飾子が必要</dd></li> </ul> 変数で受けるなどしてこの差異を吸収すれば、同じ記述が可能。 </p> </td> </tr> </tbody> </table> </slide> <slide> <hgroup> <h3>Cerium Task ManagerによるTaskの実行</h3> </hgroup> <article> <table border="0" cellpadding="0" cellspacing="0"> <tbody> <tr> <td><img src='images/createtask.png' style="height:350px"></td> <td style="font-size:18pt;color:black"> <p> TaskManagerと各Threadsの間にはSyncronized Queueがある。</p> <p> TaskはTaskManagerからSyncronized Queueに送られる。 実行するデバイスに対応したThreadsがQueueからTaskを取得し、 並列実行していく。 </p> <p> </p> </td> </tr> </tbody> </table> <br> <p> ユーザが生成したTaskはTaskManagerに送られ、依存関係を解決したあと、 各Schedulerに送られ並列実行される </p> </article> </slide> <slide> <hgroup> <h3>GPUの特徴</h3> </hgroup> <article> <table border="0" cellpadding="0" cellspacing="0"> <tbody> <tr> <td><img src='images/gpu_arch.png' style="height:400px"></td> <td style="font-size:18pt;color:black"> <p> GPU上のローカルメモリはCPUとメモリ空間が異なるのでメモリの共有ができない。 よって、OpenCLのAPIを用いてデータを転送する必要がある。するとこの転送がネックになる。 </p> <p> GPGPUは<font color="red">データの転送が頻繁に起こる</font>ようなTaskは並列度が出づらい。 </p> </td> </tr> </tbody> </table> </article> </slide> <slide> <hgroup> <h3>データ転送</h3> </hgroup> <article> <table border="0" cellpadding="0" cellspacing="0"> <tbody> <tr> <td><img src='images/gpu_data_parallel.png' style="height:450px"></td> <td style="font-size:18pt;color:black"> <p> タスク並列だと、タスクごとにinput data と output data を転送しなければならない </p> <p> データ並列なら全dataをGPUに送ることになる。結果的に転送の回数は減る </p> <p> OpenCLでは、NDRange APIを用いてデータ並列実行を行う </p> </td> </tr> </tbody> </table> </article> </slide> <slide> <hgroup> <h3>OpenCLにおけるデータ並列</h3> </hgroup> <article> <table border="0" cellpadding="0" cellspacing="0"> <tbody> <tr> <td><img src='images/ndrange_arch.png' style="height:500px"></td> <td style="font-size:18pt;color:black"> <p> データを2、3次元に分割し、分割した部分に対して 同一のTaskを割り当て、並列に処理を行う並列化手法 </p> <p> CPUからinput/output data をGPUのglobal memoryにコピーし、データを分割 </p> <p>分割したデータをWork Itemと呼ぶ</p> <p><font color="red"> 複数生成されたkernelに対してそれぞれのWork ItemとIDを割り当てる。 </font> kernelは割り当てられたIDから自分が計算する範囲を求め、処理を行う。 </p> </td> </tr> </tbody> </table> </article> </slide> <slide> <hgroup> <h3>データ並列のための新しいAPI</h3> </hgroup> <article> <table border="0" cellpadding="0" cellspacing="0"> <tbody> <tr> <td> <img src="images/iterate.png" height="450"></img> </td> <td> <font style="font-size:18pt;color:black"> <p> データ並列による実行を行う場合、一つの記述から複数のTaskを生成する必要がある </p> <p> 生成した各TaskにIDとinput/output dataを割り当てる「iterate」というAPIを実装する </p> <p>iterate</p> <ul> <li>1つの記述から複数のTaskを生成する</li> <li>生成した複数のTaskにIDとInput/Output Dataを割り当てる</li> </ul> <p> この例だと、Taskの持つidとTaskに割り当てられるデータは 1対1で対応している。id=割り当てられたdataのindexとなっている。 </p> </font> </td> </tr></tbody></table> </article> </slide> <slide> <hgroup> <h3>iterate API</h3> </hgroup> <article> <p> input data を二倍してoutput data に返す例題 </p> <img src="images/iterateTaskGen.png" height="250"></img> <p> iterate(length)とすることで、TaskManagerがデータ並列用にTaskを生成 </p> <p> この例だとlength個のTaskが生成され、各Taskに0~length-1までのID(index)を割り振る </p> 各Taskはinput dataの自分が割り当てられた要素に対して処理を行う </p> </article> </slide> <slide> <hgroup> <h3>iterate(Kernel)</h3> </hgroup> <article> <img src="images/source/iterate_kernel.png" height="300"></img> <p> MultiCoreではschedulerの持つメンバ変数x、OpenCLはget_global_idというAPIを用いて、 自分に割り振られたid(index)を取得する。その後、そのindexに対して処理を行う。 </p> <p> iterateにおいても、CeriumとOpenCLはほぼ同じ形式でTaskの記述が可能である。 </p> </article> </slide> <slide> <hgroup> <h3>iterateの実装</h3> </hgroup> <article> <img src="images/source/iterate.png" height="280"></img> <p>渡されたlengthはwork item の要素数となる。</p> <p>taskにデータ分割のためのdata(dimension, や workitem size)をsetする。</p> <p> Schedulerはtaskが持ってるdataを元にtaskを複数生成し、idを割り当てる。 </p> </article> </slide> <slide> <hgroup> <h3>iterateの実装(多次元)</h3> </hgroup> <article> <img src="images/source/iterate_multidim.png" height="300"></img> <p> 引数を複数渡せば多次元のデータ分割ができる。3次元までサポートする。 </p> </article> </slide> <slide> <hgroup> <h3>CeriumにおけるGPU上でのデータ並列</h3> </hgroup> <br> <p> GpuSchedulerがOpenCLのAPIを呼び出し、GPUの制御を行う</p> <p> TaskManagerから受け取ったTaskは必要なパラメータを各種持っている </p> <article> <img src="images/source/GpuScheduler.png" height="120"></img> <table border="2" style="font-size:18pt;"> <tbody> <h3 class="yellow">Taskの持つメンバ変数</h3> <tr> <td>dim</td> <td>データを分割する次元数</td> </tr> <tr> <td>x</td> <td>x座標の要素数</td> </tr> <tr> <td>y</td> <td>y座標の要素数</td> </tr> <tr> <td>z</td> <td>z座標の要素数</td> </tr> </tbody> </table> </article> </slide> <slide> <hgroup> <h3>ベンチマーク</h3> </hgroup> <h3 class="yellow">実験環境</h3> <table> <tbody> <tr> <td>OS</td><td>MacOS 10.9.1</td> </tr> <tr> <td>CPU</td><td>2*2.66GHz 6-CoreIntel Xeon</td> </tr> <tr> <td>Memory</td><td>16GB</td> </tr> <tr> <td>Compiler</td><td>Apple LLVM version 5.0<br>(clang-500.2.79)</td> </tr> <tr> <td>GPU</td><td>AMD ATI Radeon HD 5870 1024MB</td> </tr> </tbody> </table> <p> </p> <h3 class="yellow">時間測定の方法</h3> <ul> <li>CPU</li> RDTSC命令を用いて、CPUからタイムスタンプカウンタを取得し、 時間の測定を行っている <li>GPU</li> OpenCLのAPI(clGetEventProfilingInfo)を用いて測定 </ul> <p> Taskがtask_start_time, task_end_timeを持っていて、 SchedulerがTaskを開始・終了した時に値を書き込む。 </p> </slide> <slide> <hgroup> <h3>ベンチマーク</h3> </hgroup> <table > <tbody> <tr> <td> <!-- benchmark --> <img src="images/bench_mark_busy_time.png" height="300"></img> </td> <!-- /benchmark --> <td> <!-- system env --> <h3 class="yellow">FFT</h3> <font size="5"> <p> フーリエ変換と周波数フィルタによる、 512*512の画像への処理をデータ並列で行う例題 </p> <h3 class="yellow">結果</h3> <font size="5"> <p> GPU 実行が1 coreのCPUよりも4.8倍、2 Coreよりも2.7倍の実行速度。 CPUはどのコアもBusy TimeとRun Timeに大きな差は無いが、 GPUは大きく差が開いた。 </p> </font> </td> <!--system env --> </tr> </tbody> </table> <dl> <ul> <li><font color="red">iterateを使用すると、GPU側が劇的に速い</font></li> <li>GPUはBusy Time以外の時間に大きく処理を割いている</li> <dd>おそらくデータの転送(IO)部分</dd> </ul> </dl> </slide> <slide> <hgroup> <h3>CPUとGPUの同時実行</h3> </hgroup> <article> <table > <tbody> <tr> <td> <!-- image --> <img src="images/exe_on_cpu_and_gpu.png" height="300"></img> </td> <!-- /imafe --> <td> <!-- describe --> <font size="5"> <p> さらなる改良として、CPU上とGPU上での同時実行を可能にした。 </p> <p> GPUに比べてCPUの演算能力は小さかったが、 同時実行できれば演算資源の1つとして活用できる </p> </font> </td> <!-- describev --> </tr> </tbody> </table> <br> <p> CPUとGPUの同時実行は、実行するTaskに対してset_cpu(ANY_ANY)とすれば良い </p> <p> TaskはCPUとGPU、交互に割り振られる </p> </article> </slide> <slide> <hgroup> <h3>ベンチマーク</h3> </hgroup> <article> <img src="images/bench_mark_hetero.png" height="350"></img> <h3 class="yellow">結果</h3> <p> 現段階ではSchedulingを行ってないため、GPUやCPUを単体で動かした時よりも遅くなる。 </p> <p> CPUとGPUは実行速度に差が出る場合がある。 Taskの計算内容によってはどちらかのアーキテクチャに任せた方が良い。 それを確認するベンチマークを動かす。 </p> </font> </article> </slide> <slide> <hgroup> <h3>ベンチマーク</h3> </hgroup> <article> <img src="images/bench_mark_each_task.png" height="350"></img> <p> FFTはSpinFactやButterfly演算等、様々なTaskで構成されている。 それぞれのTaskについて、実行時間を計測した。 </p> <p> 大体のTaskはGPUの方が速いが、SpinFactのTaskに関してはCPUの方が実行速度が速い。 </p> </article> </slide> <slide> <hgroup> <h3>新たに実装するScheduling手法の提案</h3> </hgroup> <article> <table > <tbody> <tr> <td> <img src="images/decide_weight.png" height="150"></img> </td> <td style="font-size:18pt;color:black"> 並列実行するTaskをCPUとGPUで事前に一度実行し、実行時間を測定する。 それぞれの実行時間の割合で重みをつける。 </td> </tr> <tr> <td> <img src="images/select_arch.png" height="200"></img> </td> <td style="font-size:18pt;color:black"> <p> それぞれの重みからCPU実行とGPU実行のどちらに適しているか判断する </p> </td> </tr> </tbody> </table> </article> </slide> <slide> <hgroup> <h3>新たに実装するScheduling手法の提案</h3> </hgroup> <article> <p> 更に、CPUとGPUでTaskが同時に終了するようにSchedulingを行いたい。 </p> <table > <tbody> <tr> <td> <img src="images/decide_weight2.png" height="150"></img> </td> <td style="font-size:18pt;color:black"> 全てのTaskがCPUの二倍、GPUの方が実行速度が早い場合 </td> </tr> <tr> <td> <img src="images/select_arch2.png" height="180"></img> </td> <td style="font-size:18pt;color:black"> <p> それぞれのTaskを得意とするアーキテクチャに全て割り振るのではなく、 RunTimeが最小になるように割り振る </p> </td> </tr> </tbody> </table> </article> </slide> <slide> <hgroup> <h3>まとめ</h3> </hgroup> <article> <ul> <li>Cerium Task Managerをデータ並列に対応</li> <li>FFTによるデータ並列実行のベンチマーク</li> <li>CPUとGPUでのTaskの同時実行に対応</li> <li>同時実行時のTaskのScheduling手法の提案</li> </ul> <h3 class="yellow">今後の課題</h3> <ul> <li>提案したSchedulingの手法を実装/ベンチマーク</li> <li>ベンチマークに使用する例題の追加</li> <li>GPUのSchedulerにパイプライン機構の導入</li> </ul> </article> </slide> <!-- <slide> <hgroup> <h3>ベンチマーク結果の考察</h3> </hgroup> <article> <p> 性能向上は見られたが、CPUと比べると未だ差が開いている<br> GPU向けに適切なチューニングが今後の課題となる </p> <ul> <li>CPUとGPUの性能差</li> <li>data送受信のオーバーヘッド</li> </ul> <br> <h3 class="yellow">改善案</h3> <p> データ並列によるkernelの実行 </p> </article> </slide> <slide> <hgroup> <h3>OpenCLにおけるデータ並列</h3> </hgroup> <article> <table border="0" cellpadding="0" cellspacing="0"> <tbody> <tr> <td><img src='images/ndrange_arch.png' style="height:450px"></td> <td> <font style="font-size:18pt;color:black"> <p>データを2、3次元に分割し、分割した部分に対して並列処理する並列化手法</p> <p> CPUからinput/output data をGPUのglobal memoryにコピーし、データを分割</p> <p>分割したデータをWork Itemと呼ぶ</p> <p><font color="red"> 複数生成されたkernelに対してそれぞれのWork ItemとIDを割り当てる。 </font> kernelは割り当てられたIDから自分が計算する範囲を求め、処理を行う。 </p> </td> </tr> </tbody> </table> </article> </slide> <slide> <hgroup> <h3>Cerium におけるデータ並列(Task生成)</h3> </hgroup> <article> <p>Twiceというinput data を2倍にしてoutput data に返す例題</p> <pre class="prettyprint" data-lang="main.cc"> for (int c=0; c < length;c++) { twice[c] = manager->create_task(Twice); twice[c]->set_param(0,c,sizeof(int)); twice[c]->set_inData(0, indata, sizeof (int)*length); twice[c]->set_outData(0, outdata, sizeof (int)*length); Twice[c]->set_cpu(CPU); twice[c]->spawn(); } </pre> <table border="2" style="font-size:18pt;"> <tbody> <tr> <td>create_task()</td> <td>Taskを作成する。input data等を設定した後、spawnする。</td> </tr> <tr> <td>set_param()</td> <td>任意にパラメタをsetする。ここでは各Taskにidを送っている。</td> </tr> <tr> <td> set_inData(), set_outData()</td> <td >input data, output dataをsetする</td> </tr> <tr> <td> set_cpu()</td> <td >taskを実行するデバイスの指定</td> </tr> </tbody> </table> </article> </slide> <slide> <hgroup> <h3>Cerium におけるデータ並列(Taskの記述)</h3> </hgroup> <article> <pre class="prettyprint" data-lang="twice.cc"> int id = s->get_param(0); output_data[id] = input_data[id] * 2; </pre> <ul> <li>get_param() :set_paramした値を取得する。ここではidを取得している </li> <li>取得したidから自分が処理する範囲を計算し、処理する</li> </ul> </article> </slide> --> <slide class="backdrop"></slide> </slides> <script> var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-XXXXXXXX-1']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); </script> <!--[if IE]> <script src="http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js"></script> <script>CFInstall.check({mode: 'overlay'});</script> <![endif]--> </body> </html>