その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

CUDA 初学者は「効率的なプログラミング」を一旦忘れた方が良いと思った話

ある事情でCUDA 初学者が集まる勉強会で (恐れ多くも) TA をやってきて、その時に色々と思うところがあったので書きます。

「CUDA を始める動機」が与える影響

CUDA (GPGPU プログラミング)を始めるにあたっての動機の大半は「処理を高速化したいから」だと思います。
中には「GPGPU を使ったプログラミングに興味があったから」とか「CUDA が面白そうだったから」とか、
そういう知的好奇心からCUDA を始める強者もいるとは思いますが、
GPU 使えば処理にかかる時間を短縮できるんでしょ?」という即物的な動機からCUDA の学習や導入を検討する例が多いような印象を受けます。

で、その世相を反映してか、CUDA 初学者向けの書籍や記事には「高速に動作する処理の書き方」だとか「効率的なプログラムの書き方」という
発展的な内容にカジュアルに触れているものが多く、今回参加した初学者向け勉強会でもそういった内容がガンガン出ていたので、
「これって初学者にとってハードルが高いのでは?」と感じました。

とりあえず「動いたわーい」を経験した方が良いのでは

始めてプログラムを学んだ時、あるいは始めて触るプログラミング言語を学習した時のことを思い出して下さい。
果たして、その時に「効率的な書き方」に気を配ったりしたでしょうか?*1

例えば、
my $str = 'something';
my $length = length($str);
for (my $i = 0; $i < $length; $i++) {
    # Do Something
}
my $str = 'something';
for (my $i = 0; $i < length($str); $i++) {
    # Do Something
}
とでは、どちらが効率的か? という事を、最初の内は意識せずに書いていたのでは無いでしょうか。*2
で、「効率を意識」だとか「高速にチューン」だとかは、ある程度その言語でプログラムが書けるようになってからの次のステップというか、アドバンスな内容である訳です。

しかし、CUDA の入門書籍や記事はそのアドバンスな内容が先行している為に、来るものを拒んでいる感じが否めません。
しかもCUDA のチューニングといえば……
  • コアレッシング
  • バンクコンフリクトの解消
  • ワープダイバージェントの回避
  • Block の分割
  • etc...
と、初学者には難しい内容が多いので、最初からこれらを意識してプログラムを書こうとすると心がグシャッと折れる可能性が高まります。
「効率的なプログラミング? あーなんか難しいな……やめるか……」みたいな感じになりかねません。
なので、とりあえず最初は難しい内容 (チューニングとか) をガン無視して「とりあえず動くもの」を書いてみて
「わーい、動いた!」を経験した方がモチベーションを殺さずに学習を続けられて良いのでは無いかと思います。

(最近は) 普通に書いても早くなる場合が多い

つーか最近は、GPUアーキテクチャやCUDA 処理系が賢くなっていて色々と世話を焼いてくれるので、*3
(CUDA の作法に則っていれば) 効率化を特別意識してプログラムを書かなくても、CPU よりも高速に動作したりします。
限界までギンギンにチューンする必要がある場合はさておき、「現状 (CPU ベース) よりも高速に動けば嬉しいなー」という程度の要求であれば
ぐだぐだ難しい事を考えずにプログラムを書いても大丈夫だと思います。

GPGPUプログラミングは独自のプログラミングパラダイムである

CUDA の入門記事等を読むと「CUDA はC言語ベースの言語だから、C言語の知識さえあれば簡単にGPGPU プログラミングが出来る」
という記述をよく見かけますが、その認識は捨て去った方が良いと思います。
GPGPU プログラミング」は、「オブジェクト指向プログラミング」や「関数プログラミング」や「論理プログラミング」のように独立したプログラミングパラダイムだと感じています。

C言語のように、繰り返し処理 (for, while等) と分岐処理 (if, case等)を組み合わせて任意の結果を得る「手続き型プログラミング」と、
繰り返し処理と分岐処理を (なるべく) 排除して、莫大な数のThread を同時並列で実行させる「GPGPU プログラミング」とでは
全く異なるプログラミングパラダイムであると言えるでしょう。そんな具合にCUDA とC言語は異なるパラダイムなのにも関わらず、
「CUDA とC言語はほぼ同じ言語だ」という不要な前知識が存在する所為で理解や学習を妨げる可能性があります。
(例えば、C言語で効率の良い書き方が必ずしもCUDA で効率の良い書き方であるとは限らないのです)

WEB+DB PRESS Vol.67 の「入門 関数プログラミング」において、筆者の山本和彦さんは
関数プログラミングを習得するには、これまで命令プログラミングで培った技術は一旦忘れ、
真っ白な気持ちで臨む必要があります。関数型の山を登るためには、命令型の山を降りなければなりません」
と書かれています。GPGPU プログラミングも同様だと感じています。GPGPU プログラミングをマスターする為には、命令型の山を一度降りねばならないと思います。
なので、CUDA は「構文こそC言語と似ているものの、中身は全く別の言語」という認識の下で学習した方が身に付くのでは無いでしょうか。

まとめ

  • 最初のうちはCUDA で効率的なプログラムを意識しないで書いた方が良い
    • とりあえず動くものを作ってみよう
  • というか、最近は特別効率を意識してプログラムを書かなくてもある程度高速に処理される
  • GPGPU プログラミングは独自のプログラミングパラダイムである
    • C言語の知識がCUDA の高速化・効率化に適用できるとは限らない
という感じでしょうか。


ここから先は

特に効率化とかそこら辺は関係無い話です。
ただ書きたいから書いているだけです。

(補足1) 今出ている入門書はモダンではない

2012.10.30 現在、出版されているCUDA の入門書籍は古い内容のものが多く、
モダンなアーキテクチャや書式に対応していなかったりしているので注意が必要です。*4
例えば、「はじめてのCUDAプログラミング」はCUDA の入門には良い書籍だと思いますが*5
ご多分に漏れず内容が若干古いので適宜インターネット等で情報収集を行った方が良いと思います。
はじめてのCUDAプログラミング―驚異の開発環境[GPU+CUDA]を使いこなす! (I・O BOOKS)

はじめてのCUDAプログラミング―驚異の開発環境[GPU+CUDA]を使いこなす! (I・O BOOKS)


(補足2) "GPU = 高速" とは限らない

GPU が得意な処理かどうか」というのは見極めなければなりません。
GPU が得意な処理 (分岐させる必要が無い若しくは少ない、等)であれば、GPU で実装したときにCPU よりも高速に処理されると思いますが、
逆に不得意な処理をGPU に行わせようとするとCPU よりも低速になる可能性があります。
(ワープダイバージェントや、スレッド間の同期や、ホスト・デバイス間メモリ転送等でオーバヘッドが生じる為)
なので、GPU は必ずしも高速であるとは限らないという事を頭の隅に留めておいた方が良いと思います。
(「GPU にすれば何でも早くなるんでしょ?」みたいな事を良く訊かれたので)

*1:「おうともよ!」というツワモノはオッケイです。最初から高速化を意識したCUDA プログラミングをなさった方が幸せになれると思います

*2:とは言うものの、この例の$str の文字列長では有意な差は出ないと思いますが

*3:自動的にメモリキャッシュが効いてくれたり、メモリのアライメントをよしなにやってくれたり……

*4:特にFermi 以降のアーキテクチャは色々と劇的に変わっているので

*5:ただ、割と応用的な内容にも食い込んでいますが