プラグイン集

無料ブログはココログ
2021年11月
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30        

サンプルJS

  • ユーロバカ一代の締切
    ・・・初期化中・・・

« Bellさんのブログを読んで | トップページ | 鉄道無線の接近警報を聞くには »

2014年5月20日 (火)

HPCとかでしょうがなく性能上げざる得なくなったら

この手はプロの方は使えません。学とか修とかまでで、やる事無くてソフトの動作速くすることになっちまった、トホホォって人向け。プログラマがやれることは、ハードウエアの動作効率を上げる事だけ。残念なことに、半導体には手出しできないし、新しく買ってもそこまで速くならなくなった。(いわゆる、フリーランチは終わったって奴。)

んじゃどうするかと言うと、1つ目にソフトの最適化。ループアンローリングしてキャッシュヒットさせるとか、分岐命令減らすとか、除算を乗算に変えるとか。それ位やって、あとは-Oオプションで最適化。2か3、Iccだと-O4があるんだっけ?浮動小数点計算周り崩壊するけど。後は、-marchで昔のCPU切り捨ててやれば、若干良くなる。出来てこれくらいか。ただループアンローリングとか分岐減らして上手く遅延スロットに当てるというのは、CPUにより成功・失敗が有るので安定性は乏しい。Core i7で潤沢にキャッシュがあるならいいがCeleronだとキャッシュミスでメモリまで行くから遅くなるとか。
とりあえずこの項目は、頭の片隅に置いておいて、キリキリまでチューニングするときに使う。

次、並列化。いろんなところで高速化するために言われている手法。
最近のCPUの周波数もIPC(1クロックあたりに通せる命令数)も伸びが良くない。空いた半導体にCPUもう一個封入するマルチコアのPCが普及してるからなせる業。

ちなみに、クロックが上がるというのはマジでうれしい、同じ構造(アーキテクチャ)で2倍速ならソフトが2倍速になる。CPU製造元でここの回路こうしたらよくなるな、でも製造入ってるから、次で良くしようと効率(IPC)も上がるとなおいい。CPUの性能は単純な式で評価すればクロック*IPCで評価される。

大体の普通のプログラマが作るソフトはCPU一個しか使わない。なぜならそう作るのが一番簡単で余計な心配しなくていいから。
まず、人間はアレコレ同時にしようとすると忘れる。お湯沸かしながら、編み物してやかん焦がしたというのがいい例。プログラマもスレッドの回収を忘れて資源のリークをやる。
次、逆転処理は出来ない。必ず依存がある。物には順序が有るというおはなし。たとえば、風呂入るときにお湯張らずに風呂に入れない。とか、箸と茶碗持って来ても飯たかなければ飯食えないとか。
風呂なら、洗う→すすぐ→お湯張る→脱衣→やっと風呂。飯なら米を出す→米をとぐ→米を休ませて浸す→釜に突っ込む→炊飯→若干蒸らす→茶碗に盛る。
などの飛び越して先にできない作業を依存関係と言う。
プログラムと一般に言えば、式次第なので、頭から順序良く運営される(いわば逐次処理)。コンピュータも同じだ。校歌・国歌斉唱を同時実行、校長・教頭・来賓あいさつを一気にできないのと同じ。
なんとか、同時にやっても問題ない所を探して同時にこなしてもらう。それが並列化。

だからすごく頭使う。風呂の例なら8割ぐらいお湯が溜まったら、脱衣を開始して入って、お湯が適量になったら止めるとか。飯の例なら、炊飯中におかず作るとか。ムラしている間に味噌汁作るとか。
関係性の低い別の作業を通す場合は、マルチコアはおいしいが、現実の1本のソフトに関して言えば、過酷な結果が待ち受けている。アムダールの法則 だ。

たとえば、20時間掛かる作業がある。手分け出来るのが半分の10時間。もう半分は前の作業が終わらなければ出来ない、依存であるとする。
結局、どんなに頑張って1万人くらい人手を集めても、10時間に限りなく近づくが10時間は切れない。と言うもの。

Amudaru_2ね?クロックが上がってくれれば、全体が速くなるからおいしいでしょ?効率面を見るIPCはこうも上がらない、上がって数%。
逆に、頑張って頭ひねって並列化したとしてもこの程度。理不尽でしょ?

他に並列化の問題としては、お膳立てが必要である。
先程の例で、1万人くらいの人手と言ったが、1万人かき集めてこなければならないし、みんなによろしくと配って、みんなから結果を回収して来るという作業が必要となる。こういう逐次でやっていた時には起こらない余計な手間をオーバーヘッドと言う。このオーバーヘッドが大きすぎて、並列化の恩恵が0どころかマイナスと言った事も発生する。

今のCPUのクロックの伸びない他の要因は、まだあって書いてる時点で最新のCore i7 4790Kの噂の4GHzでどこまで情報を伝搬できるかを考えてみる。理論道理の30万km/秒で、1クロックあたり7.5cmの伝搬が限界。実際電気抵抗考えると、20万km/sの5cmぐらいが限界。Core i7 4771が3.7cm四方なので、端の部分にL字に配線されると、理論値でもぎりぎり端から端まで1クロックで伝搬できるかどうか。
次、微細化と熱。半導体の発熱は、発熱=電圧^2*周波数と言われて、微細化とともに電圧落として、周波数上げてこられた。だが、実際は、線細くすると電気抵抗が増える。電圧上げると2乗で効いてくるのでやむを得ず電流を増やす。電流が抵抗で消費されたり漏れ出て熱に変わる。細く小さく局所的に出る熱を早く広い面積に飛ばす事が出来ず、結局焼き切れてしまう。今の半導体物質だと、これ以上電圧下げると動作不良起こすらしい。ON・OFFしっかりするためには、ある程度の電圧はいるが、やっぱり細い線を通さざる得ない。
と言うように、かなりの悪循環に嵌っているようだ。線を大きくすれ解決しそうだがば、回路が大きくなって、線を取回す距離が増えるのでクロックを落とさざる得ない。やはり遠くなるから電流を消費する。結構にっちもさっちもいかない難しい問題となっているようだ。

背景と理論長くなったが、並列化やるには。

  1. コンピュータ増やす
  2. CPU増やす
  3. SIMD命令(SSEやAVX命令)を活用する
  4. GPU等のアクセラレータ使う

1・2はPCクラスタとかスーパーコンピュータでやられている方法。4つCPUが入るボードをたくさん詰めるとか。
3はSSEとかのCPUに入っている普段は寝ている機能を活性化してやる。今の時代Celeronでも入ってるから大丈夫。昔は無かったのに。
4はちょっと特殊。本来ゲーム用のGPUを計算に転用したり、行列専用のプロセッサーボードを追加したりという専用プロセッサをつなぐもの。
マルチコアはCPUメーカーが勝手にやった2のようなもの。

大体この4つの手段から選ぶことになる。
最近人気なのはGPUだ。研究と言いつつゲームに転用することが可能だからな。各手法を簡単に見ていくと。

1.コンピュータを増やす。
物理的にコンピュータ増やせば、並列して他の事が出来る。物量作戦。だが問題も多い。
まず、物理的に距離が出来るのでデータの送受信に時間がかかる。電気も食う。お手軽にLANケーブル繋いでグループ組む場合もあるし、ボード挿して、高速低遅延(レイテンシー)の専用ネットワークを組む(大体スーパーコンピュータ)場合もある。
コンピュータは同じものでなくてもいいが、負荷のバランス計算したりチューニングが面倒臭くなるのでほとんど同一のコンピュータで組まれる。
プログラミングとしては、PVM(並列仮想計算機)MPI を使って組むのが一般的。前者は仮想的に大量の計算機を1台に見せかける。後者は、データ通信を行いながら情報交換して計算させる。
PVMは1台に見せかけるために協調動作させる(オーバーヘッド)必要があるので、全部手動のMPIで組んだ方が(計算速度が)速いわとMPIの方が人気。※SCoreとかグリッドとかどこ行ったのかは不明。
MPIは、各コンピュータが計算結果持つから、ちゃんとどこに何があるのか把握しながら処理させないと頭が大変混乱する。データの持ち方だのディスクが共有されてるだののコンピュータシステムの組み方までしっかりと知っている必要がある。

2.CPUを増やす。
物理的にCPU2個とか4個とか乗っているコンピュータもあるが、マルチコアもここの仲間。
Xeonで4CPUとかで運用すると、早いもの好きとかエンコードマニアとかすごい楽しい。
一つのコンピュータ内にCPUが複数あるので、1台で十分。
最近のCPUはメモリ直結しているのでケーブルを介して通信と言うことは無い。※例外的にOpteronとかXeonとかHT・QPIとかで繋がってるcc-NUMAは、HT・QPI使ってデータ通信するが。
この方式で並列処理する場合は、まず、別のソフトとして処理させる。そうすれば、自分が掴んでいるCPU以外のCPUにソフトを割り当ててくれて、並列処理できる。※一部ダメOSは同じCPUに処理割り当てて遅くなったりするが。一般用2kとか初期のXPとか。実は同一コンピュータ内でMPIを実行するとこの方式。別プロセスとして処理されて、同じようなデータでメモリを食ってくれる。なのでよくメモリ不足を起こす。
主流の方式としては、スレッド増やす。別ソフト(別プロセス)なんぞよりよっぽど起動が早く、終了も速い。同じソフトとして扱われるので、グローバル変数を共有できる。MPIだと同じPC上でも”通信”が必要。実際に行われてるのはメモリ介してのプロセス間通信だけど。
ソフトが確保したメモリを各スレッドが共有できるのでデータ交換はメモリアクセス速度となり、ケーブル通信よりよっぽど早い。
プログラミングとしては、OSが持ってるスレッドライブラリを使う。Windowsならwin-Threadや.NET Thread、background Workerなど。LinuxならpThread。
もしくは、OpenMPを使う。
どっちがメインって事は無いんだけど適材適所?OpenMPはループ展開系には強いが、他の別の作業となると弱い。Threadは逆に何でもできるが、習得が結構面倒くさい、OpenMPは#pragma omp parallel for とパラグマを打つだけ。(どっちもコンパイルオプションにヘッダーの追加が必要だ。)ThreadはOSの機能だけあってかなりチューニングされてて生成・消滅もかなり早いが、OpenMPはライブラリによるAPIなので、重い。スレッド保持のためにプールしたり余計な処理(オーバーヘッド)をしている。そこそこの性能で簡単なOpenMPを選ぶか、いろんなことするためにThreadを利用し、カリカリまでチューニングするかはプログラマの分かれるところだ。

3.SIMD命令(SSEやAVX命令)を活用する。
広い意味でベクトル計算を行う。NEC系列のガチスーパーコンピュータで用いられている、あのベクトルだ。たくさんのデータに対して、一つの命令を一気に適応する。ちなみにCeleronにもこの機能は乗っている。

Vector_calSIMD計算は、図のようにいくつかの要素をまとめて同じ命令を発行し一時に計算結果を得る。同じことを繰り返しまくるマルチメディア系の処理に効く。

余談ついでに、SIMDファミリーについて説明。SIMDは、Single Instruction Multiple Dataの頭文字をとったもので、単一命令複数データとなる。もちろん、複数命令複数データ(MIMD)、複数命令単一データ(MISD)、単一命令単一データ(SISD)の4つからなる。

命令
単一 複数
データ 単一 SISD MISD
複数 SIMD MIMD

SISDは従来の逐次処理だ。MISDは分類上の存在、1個のデータに同時に違う命令を適応するには無理がある。SIMDは今の通り、一つの命令を複数個のデータに適応する。MIMDは、1.のコンピュータを複数利用したり、2.のCPU複数使って別のことをする処理を指す。
SPMDと言う一つのプログラムで複数データを処理する事を挿す分類もあるが、1.のコンピュータを増やしてMPIでプログラムを組むとこうなる。全コンピュータが同一のプログラムを実行するが、参照しているデータが異なる(複数になる)為。
MPMDはプロセッサがそれぞれ別のデータかと思えばOSレベルまで別でなければならないらしく、もはや仮想マシーンが複数走るクラウド基盤を挿し、並列処理とはまた別の次元となる。※確かに、並列して全然違うデータ全然違うソフトが走っているという意味では並列処理だが。

最近のコンパイラは、最適化オプションでSSE2ぐらいまで勝手に使ってくれるが、Core i7生かし切るならSIMD命令(SSEやAVX命令)を使いこなさないと早くならない。
プログラミングとしては、最新命令を使うにはアセンブラ必須かと思いきやイントリンシック命令と言う便利な命令が有って、普通に関数使う感覚でSIMD命令を利用できる。ヘッダーとコンパイルオプション必須。ただし、メモリの境界(アライメント)を合わせる必要がある。同じ命令(計算)を複数(多量)のデータに行う時に効果が出るが、それぞれ違うとやっぱり、逐次処理せざる得ない。
命令はググるか、Intelコンパイラなら説明書に書いてある。

4.GPU等のアクセラレータを使う。
昔からこのブログを読んでる人なら何度もになるが、一方通行ではありません。加速器です。GPUなら3Dグラフィクス描画速度向上用の加速器です。
特定用途の計算なら多体計算専用のGRAPEや、行列積の計算専用のClearSpeedなどが前から存在していて、特定の計算用に、専用のハードウエアを使うというのは、目新しい手法ではない。ただ、そういう計算を行う人はごく限られた人しか使わず、その人が勝手に演算ボードを作って終わりと言う場合がほとんどだった。
ただ、パソコンの発達とともに、ゲームが飛躍的に進歩し派手なグラフィクスの需要が急増した。今やノートパソコンやタブレット・スマートフォンに至るまでGPUは無くてはならない存在となっている。
従来、GPUは3Dグラフィクス特化しているため、3Dグラフィクスで用いられる表現範囲で計算を行わなければならなかったが、NvidiaのCUDAやATIのATIStreamと言った汎用目的でのGPU操作言語が登場してからは、店で買ってくるだけで、単純計算に限ればCPUの何倍もの速度を手に入れることができるようになった。
GPUの構造は、簡単な作りのCPUが大量にある構造をしておりSIMD命令を通しやすい構造となっている。しかもローカルに超高速広帯域のメモリまでついている。
CPUは少数精鋭タイプだが、GPUは凡人大量に集めた数は力タイプとなっている。
プログラミングとしては、まず、ATIStreamはATIがAMDに買収された時点で終了した技術となっている。Nvidia専用のCudaで組むか、Windows7以降しか対応しない・Direct X11以降の技術でしか動かないDirectComputeで組むか、GPUの製造会社を問わないOpenCLを使うかとなる。
現在の所、Nvidiaの自称Cの拡張のCudaか、どのGPUでも動くOpenCLがメジャー。DirectComputeは出遅れている模様。
こちらも、NvidiaのGPU限定でカリカリまでCudaでチューニングしてNvidiaが用意した高速ライブラリを使うか、デスクトップでもノートでも環境自由自在のOpenCLを使うかでプログラマの判断が分かれそうなところだ。

番外、少数精鋭ではなく精鋭を多数そろえたら、Xeon Phi。
なんと、CPUを大量に用意したような環境がある。Xeon Phi。従来のコードを改良して大量並列に動かそうと言うものだ。ただLinuxでないとフルパワーを発揮できない。プログラミング環境が特殊。法人にしか売らないなど非常に特殊。とりあえずコンピュータショップでいちばんいいGPUを頼むで買って来れるGPUとは大違いだ。
Xeon Phiは謎が多い。

言っておくが、頑張って並列化ガリガリしても、アムダールの法則で、結局並列化できない部分に引っ張られてプログラム全体としての速度向上率は悪くなるし、お膳立てというオーバーヘッドで下手すれば効果はマイナスと言うことがある。だから、並列化不能の部分ももうとうに示したとおり、アーキテクチャに沿って最適化を施してあげないと簡単に速度向上が頭打ちとなる。並列化無理な部分もちゃんと処理を見直して効率化してあげようね。(並列化終わってから。)
コンパイラの最適化オプションの説明もちゃんと読もう。浮動小数点演算が簡単化されたりして、期待した結果が出てこない事が多々ある。特にCG。AMDとIntelだとIntelの方が絵がいいというのは、AMDがIEEEに沿って正確に64Bit計算するがIntelはIEEEに従っておらず中間80bitに精度補正して計算する結果が表れたものだ。コンパイルオプションによりこの動作を無力化すること出来るのでIntelの良さを潰してしまうことになる。CGも動画も料理もじっくりコトコト、早けりゃ良いと言う物じゃ無いという部分もある。


まとめると、学生の終わりに、お上に言われて並列処理しなければならなくなったどうすればいい→手段は4つかな。

  1. コンピュータを増やしてMPI通信しながらデータを仕上げるでプログラミングを行う。
  2. CPUを増やす。ループの時間短縮を狙うならOpenMP、いろいろ詰めるならThreadで頑張る。
  3. SIMD命令を活用する。SSE命令をきちんとつかえているのか。何個かまとめて計算できないかを考える。
  4. GPU等のアクセラレータを使う。GPU使うならNvidia縛りでCudaで速さを求めるか、OpenCLを使ってどの環境でも動くようにするかの選択を行う。

以上。大体この4個だ。並列化が終わって疲れたーしないで、きちんと並列不可能な部分も見直して、従来の最適化を施してあげようね。アムダールの法則で今一早くならないから。

« Bellさんのブログを読んで | トップページ | 鉄道無線の接近警報を聞くには »

プログラミング」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: HPCとかでしょうがなく性能上げざる得なくなったら:

« Bellさんのブログを読んで | トップページ | 鉄道無線の接近警報を聞くには »