GTC2011 Japan

653 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
653
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • みなさん、CUDAチュートリアル第二弾、CUDA30分クッキングへようこそ。\nぼくはフィックスターズという会社でプログラマをしています、飯塚と申します。どうぞよろしくお願いします。\n\nさて、いまここにいるみなさんは、CUDAをこれから学ぶ、あるいは既に学んでいる方だと思われます。このチュートリアルの目的は、CUDAプログラミングという敷居がどれくらいの高さなのか、実感として知っていただくことです。ここで紹介するツールやテクニックは現場で使われているものであり、CUDAの使用を検討している方、今まさに学習中の方には、必ず役に立つものと信じています。\n\n\n\n\n\n
  • それでは、本日のメニューをご紹介します。\n\n前菜は、CUDA環境構築です。CUDAプログラミングを行うに当たって、何が必要なのかを簡単にご説明します。メイン1皿目には、配列をxxするプログラム、というものをゼロから実装します。メイン2皿目には、C++で実装されたリアルタイムレイトレーシングプログラムをCUDAに移植します。そしてデザートには、簡単にパフォーマンス測定を行います。\n
  • 早速、CUDAプログラミングの環境構築を行っていきましょう。\n
  • 今回はWindowsにおけるお手軽CUDAプログラミング環境を構築します。\n材料はこちらの通り。ドライバ、ツールキット、SDK、Visual Studioなどホストコードのコンパイラ、またクロスプラットフォームなビルドシステムCMakeを導入します。\n\n= Live =\nといっても難しいことはなく、このようにWebページからインストーラをダウンロードし、ワンクリックでインストールを行うだけです。\n\n
  • WindowsやMacなら、このとおりインストーラを4, 5発実行して、おまけに再起動するくらいですみます。Linux環境だとドライバのインストール周りでもう少し複雑なのですが、これについては弊社のCUDA Information siteにてインストール手順を公開していますので、ご参考にしていただければと思います。\n
  • さて、これでCUDAプログラミング環境は整いました。次はいよいよプログラミングの時間です。\n
  • お題は、ゼロからGPUプログラムを作りましょう・・・です。\n今回は、配列に対して任意の操作を関数オブジェクトとして実装し、これを実行するGPUプログラムを作成してみます。\n\n材料として、いくつかのCUDA APIとCUDAの文法を覚えておきましょう。\nまた、C++ templateとよくできたエディタ、よくできたキーボードも必要です。\n\nちなみに僕にとっての「よくできた」はvimとHappy Hacking Keyboardなのですが・・・\n時間もないのでこれについてのの議論はまたいつか。\n\n= Live =\n1.CMakeLists.txtをつくる\n2. mainかく\n
  • さて、CUDA APIとCUDAの拡張構文についてですが、必要なのは全部でたった4つです。\nGPUは専用のメモリ空間を持っており、このメモリ空間のアロケーションに使用するのがcudaMallocとcudaFreeです。\nまた、CPU側のメモリとの間のデータのコピーはcudaMemcpyというAPIを使用します。\n\nそして、カーネルと呼ばれるGPUプログラムの呼び出しには、CUDAの拡張文法を使用します。\nこのようにアングルブラケットをカーネル関数の前に付け、nvccでコンパイルすると、\nカーネルの呼び出しとして解釈されます。\n\n= Live =\nCUDA APIを使用したホストコードを作成する\n
  • さて、CUDAスレッドとカーネルという言葉が出てきましたね。これについて説明します。\n\nGPUは、数万というCUDAスレッドを数百のCUDAコアで並列処理するという実行モデルを持っています。CUDAカーネルは、CUDAスレッドの処理内容を記述するためのもので、__global__という識別子を関数の先頭に付けると、それがCUDAカーネルになります。\n\n= Live =\nCUDAカーネルのスタブを書く\n
  • CUDAカーネル内部では、いくつかの特殊な組み込み関数や変数が使用できます。今回は、threadIdxという組み込み変数のみを使用します。この変数は、そのカーネルを実行するCUDAスレッドのIDを格納しており、CUDAスレッドごとに違う変数を取得できます。\n\n= Live =\nカーネルを実装\n関数オブジェクトを実装し、関数に__device__識別子を付ける\n
  • さて、CUDAを使用した簡単なコードを作成しました。たった50行のコードです。また、ホスト側はメモリ領域が連続していればSTLでも問題ありません。またカーネル呼び出しではC++ templateを使用できるため、柔軟なプログラミングが可能なことがわかりました。\n\nまた、このコードですが、実行されるロジックのほとんどを、CPUとGPUで共有することが可能です。これによって、デバッグしやすい、保守しやすい、またこれは特にチューニングいない場合に限りますが、パフォーマンス比較がしやすい、などのメリットがあります。\n\n= Live =\ncpu_gpu_vecxx.cuを見せる\n\n
  • それでは、メイン2皿目、リアルタイムレイトレーシングについて。\n\n
  • ここに、C++で書かれたプログラムがあります。これをGPUに移植しようというのが、今回のテーマです。\n\n= Live =\n1. buildはしておく\n2. ./cpu_rendererするだけ\n
  • レイトレーシングは、その名のとおり、視点から仮想スクリーンに対する光線を追跡して3Dモデルを2Dにマッピングするものです。この絵にはレイは一本しか書かれていませんが、最低でもスクリーンのピクセル数のレイを追跡する必要があります。\n
  • このプログラムのおおまかな作りはこちら。DrawImageのcomputeメソッドがピクセルごとにSceneクラスのrender()メソッドを呼び出します。Sceneには複数のレンダリング対象オブジェクトが含まれており、Primitiveインタフェースを通じて必要なメソッドを呼び出します。\n
  • 今回は、Sceneクラス以下すべてをCUDA化します。これを行うために、どのくらいの作業が必要になるのでしょうか?では早速やっていきましょう。\n\n= Live =\n1. CMakeLists.txtひらき、CUDA_NVCC_FLAGSに-D USE_CUDA -arch=sm_20をセットし、cuda_add_executableする\n2. porting.h をひらき、FUNC_DECLに__host__ __device__つける\n3. main.cpp を main.cuにコピーする\n4. DrawImageにd_image_を追加する\n5. DrawImage::initにcudaMalloc(&d_image...)とcudaMemset(d_image...)かく\n6. DrawImage::finishにcudaFree(d_image)をかく\n\n
  • さて、ここでわかるとおり、Scene以下をCUDA化するのですから、CUDAカーネル内部でC++のオブジェクトを生成できなくてはなりません。ここで、CUDA4.0からサポートされたnew/deleteが活躍します。\n\n= Live =\n1. DrawImageにd_scene_p_を追加\n2. グローバル空間にnew_kernelとdelete_kernelを追加\n3. DrawImage::initにcudaMalloc(&d_scene_p_, ...)とnew_kernelの呼び出しをかく\n4. DrawImage::finishにcudaFree(d_scene_p_)とdelete_kernelの呼び出しをかく\n5. グローバル空間にrender_kernelとdisplace_light_kernelをかく\n5. DrawImage::computeにrender_kernelの呼び出しをかく\n6. DrawImage::displace_lightにdisplace_light_kernelの呼び出しをかく\n\nビルドして動かす\n\n
  • さて、ポイントですが、今回行った作業はわずか50行程度のコードの追加です。Scene以下のコードは1行も触っていないことにお気づきですか?肝心のレンダリングロジックは、CPUとGPUで完全にコードを共有しています。\n\nこれができたのも、CUDA4.0でC++サポートがだいぶ拡充されたことが理由の一つです。SDKにnewdeleteというサンプルコードがあるので、興味のある方はそちらもみてみてください。\n
  • さて、最後にパフォーマンスの測定を行います。\n
  • パフォーマンス測定に使うのは先程移植したのレンダラです。せっかくCUDAにしたのだから、そのスピードを数字としてみたいですよね。今回はFPSとして、つまり一秒間に何枚レンダリングできたのか、画面上に表示してみることにします。\n\n= Live = \n1. display_callbackにPerformance perf(“all”)を宣言、compute()とdisplay()のあとでperf.stop()して、1e3fをperf_mean_ms()でわり、fpsとする\n2. stringstream ssに適当に文字列として突っ込み、glutSetWindowtitle(ss.str().c_str())する\n3. ビルドしてcpu版とgpu版を比べる。10倍くらい違うハズ\n
  • 今回はfps、つまり単純な計算時間という形でパフォーマンスを表示しましたが、本当に大事なのは計算時間のうち、どのような処理がどのくらいの割合を占めるのかということです。これについては、第3、4チュートリアルで紹介されるプロファイリングツールが役立ちます。興味のある方は是非御覧ください。\n
  • フリーランチ、つまり努力せずプログラムが早くなる夢の時間は終わり、少しの手間で、美味しいディナーを食べる時が来ました。次はみなさんの番です。\n
  • C/C++を知っていれば、CUDAプログラミングは難しくありません。簡単に動かすだけであれば、最低限の努力で達成可能な場合もあります。\n\n最後になりますが、今回使用したソースコードは以下で公開しています。\n
  • それではみなさん、よいプログラミングを!\n
  • GTC2011 Japan

    1. 1. CUDA入門 CUDA30分クッキング株式会社フィックスターズプログラマ 飯塚拓郎
    2. 2. 本日のメニュー単色 Antipasto CUDA環境構築 Primo Piatto 配列をxxする Second Piatto リアルタイムレイトレーシング Dolce パフォーマンス測定
    3. 3. Antipasto CUDA環境構築単色
    4. 4. Antipasto CUDA環境構築✓ お題単色 - Windowsでお手軽CUDAプログラミング環境を整えましょう✓ 材料 - NVIDIA Driver : NVIDIA GPUのドライバ - NVIDIA CUDA Toolkit : CUDAコンパイラ、ランタイムライブラリ等 - NVIDIA GPU Computing SDK : サンプルコード、ユーティリティ等 - Visual Studio 20xx : ホストコードのコンパイラ - CMake(お好みで) : クロスプラットフォームなビルドシステム
    5. 5. Antipasto CUDA環境構築単色✓ Cooking Point - Windowsならインストーラ4, 5個 - Macでもほとんど同じ One More Thing ... - Linuxディストリビューションのインストールチュートリアルはこちら - http://gpu.fixstars.com/index.php/CUDAのインストール
    6. 6. Primo Piatto 配列をxxする単色
    7. 7. Primo Piatto 配列をxxする単色✓ お題 - ゼロからGPUプログラム作りましょう✓ 材料 - cudaMalloc - cudaFree - cudaMemcpy - <<<>>> - C++ template、よくできたエディタ、よくできたキーボード
    8. 8. CUDA APIとCUDA構文✓ メモリアロケーション単色 - cudaMalloc(void** devPtr, size_t size) - cudaFree(void* devPtr)✓ メモリコピー - cudaMemcpy(void* dst, void* src, size_t size, enum cudaMemcpyKind kind) カーネル呼び出し - <<<1, threadNum>>>kernel_name(...) - kernel_nameというカーネルをtheadNum個のCUDAスレッドで実行す
    9. 9. CUDAスレッドとカーネル単色 CUDAカーネルには 各スレッドの処理を記述 CUDAスレッドは CUDAカーネルを実行 CUDAコアは CUDAスレッドを順次実行
    10. 10. CUDAカーネル✓ 今回のカーネルを書く上で覚えなきゃいけないこと単色 - dim3 threadIdx - CUDAカーネルの組み込み変数で、スレッドIDが格納されます - スレッド空間が一次元なら、threadIdx.xがスレッドIDになる これだけ!
    11. 11. Primo Piatto 配列をxxする単色✓ Cooking Point - ホスト側はメモリ領域が連続していることが保証できていればSTLでもOK - c++ templateで汎用性もバッチリ - たった50行 One More Thing ... - これってGPUのコードがほとんどそのままホストコードとして動きます
    12. 12. Second Piatto リアルタイムレイトレーシング単色
    13. 13. Second Piatto リアルタイムレイトレーシング単色✓ お題 - C++なCPUコードをCUDA化しましょう✓ 材料 - 並列化できそうなCPUコード
    14. 14. レイトレーシングについて単色 光源 レンダリング対象物 視点 レイ 仮想スクリーン
    15. 15. 設計図単色 Sceneは複数の Scene Primitive Primitiveをもつ -------------- ---------- --- -- Pixel render(int x, intersect() = 0 ピクセルごとに Primitiveインタフェースを rende()を呼び出す 実装 DrawImage Sphere Triangle ---------- -------- -------- -- compute() - -
    16. 16. 設計図 ここ全部CUDA化単色 Scene Primitive -------------- ---------- --- -- Pixel render(int x, intersect() = 0 DrawImage Sphere Triangle ---------- -------- -------- -- compute() - -
    17. 17. CUDA カーネル C++ compatibility単色✓ CUDA3.xまでは・・・ - リソースアロケーションとかできない - そもそも本当の意味でのfunction callはできなかった - (関数は全部inline)✓ CUDA4.0では・・・ - カーネル内部でnew/delete可能! - function callが実装され、virtualが使えるようになった!
    18. 18. Second Piatto リアルタイムレイトレーシング単色✓ Cooking Point - 全体が約1700行、うち50行程度を追加しただけ - ループを見よ!CUDAで並列化できるところは大体ループ✓ One More Thing - CUDAのC++サポートが大分いい感じ - SDKのnewdeleteというサンプルにスレッドセーフなコンテナの実装アリ
    19. 19. Dolce パフォーマンス測定単色
    20. 20. Dolce パフォーマンス測定単色✓ お題 - パフォーマンスを測ってみましょう✓ 材料 - 十分な精度のタイマ関数(とそのユーティリティ) - さっきのレイトレーシングプログラム
    21. 21. Dolce パフォーマンス測定✓ Cooking Point単色 - パフォーマンス測定値は見やすい形で!✓ One More Thing - パフォーマンスメトリクス - ベースとなるのは計算時間 - 重要なのは、計算時間のうち何がどのくらい占めているのかということ - 計算がネック:compute bound - 転送がネック:memory bound
    22. 22. Free Lunch is Over, Let s Have a Dinner !単色
    23. 23. Free Lunch is Over, Let s Have a Dinner !単色✓ Cooking Point - C/C++を知っていれば、CUDAプログラミングはむずかしくない - 既存のソースコードも、動かすだけなら最低限の努力でOK✓ One More Thing - 今回使用したソースコードを公開します - http://github.com/iitaku/gtc2011
    24. 24. Happy Programming, Everyone !

    ×