GPUでIFを使うな！？

# 初めに
　この記事を書こうと思ったのは、専門学校で同じような事をパワポで発表したからです。どうせなら、もっと分かり易くした上で、記事にしてしまおうと思い書きました。題名でGPUに詳しそうな感じをかもしだしていますが、別に特段詳しいわけでもなく、ただ単に気になったという理由です。ですので、間違っている可能性も十二分にあるので、**参考程度**で見て下さい。
　この記事では、多少GPUについて知っておいた方が分かり易いと思います。ですが、余り知らない人向けにも、出来る限り分かり易く説明します。なので、若干に違う表現になっている場合もありますのでご了承ください。

　さて、本題に入ります。HLSL・GLSL・CUDAなど、GPUに処理を書く上で、よくこの言葉を聞くのではないのでしょうか？結論としては「<font color="red">**遅くなるから**</font>」です。でも、「なぜ？」とは思った事はありませんか？
　HLSL・CUDAなど、GPUでのコードについてよく知らない人は、「GPUでは遅くなるからIFを使うなよ～」ぐらいの解釈でOKです。というより、それだけで十分です。よほど~~変態~~みたいなことをしない限り、理由を気にする事態になる事はほぼ確実にありませんから（笑）

# 説明（LV.1）
## GPUとは？
　CPUとは異なり、名前の通りグラフィカルな仕事をする部品です。詳しく言うと、出来る限り**同時**に画像処理・頂点変換・ピクセル計算などなど、これらの**物量**をこなすために使われる部品です[^0]。
　では、物量をこなすにはどうすればいいのでしょうか？・・・そうです。「目には目を物量には物量を」という事です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/705645bc-a97b-2f57-d14e-e8b59b781db9.png)
　ここでいう「職人」を本来は「**スレッド**」と呼びます。プログラマーならお馴染みですね。

[^0]: 近年では、GPGPUのように描画機能以外の事にも使われるようになっています。


## 職人（スレッド）の働き
　会社にも働くルールがあるように、GPUの職人（スレッド）にも働くためのルールがあります。ここでは分かり易いように、<font color="red">「職人」を「**会社員**」と置き換えて説明します。</font>
　やはり、IF文がどのようにGPUで再現されているのかを知る必要があります。

---
### ルールその１
　１つの会社で、社員は全て同じ仕事をするわけではありません。いくつか部署に分かれて違う仕事をします。単純作業でも実際に行う作業は一つではありませんよね？
![Warp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/429077b5-b072-3a7c-2323-273ab6831b96.png)

:::note
プログラマー向け
　GPUには沢山のスレッドがある訳ですが、一つ一つ管理されている訳ではなく、３２スレッドごとにまとめて管理されています。このまとまりを「<font color="red">**Warp**</font>」と呼びます。（NVIDIA GPUの場合）
:::

---
### ルールその２
　この会社では社長が部署ごとに「１つ」の仕事を割り振り「命令」を下します。ワンマン社長ですね。その命令を受けて、各部署全員が出された仕事を同時にこなします。<font color="red">**決して**、部署内で別々の仕事をする事は無く、全員が**同時に**仕事を開始します</font>。
![pose_meirei2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/1510f1e5-35fd-6c63-eaed-f2eb1c77235f.png)

:::note
プログラマー向け
　GPUは基本「１つの命令」に対し「スレッド」は同じ処理しか出来ません。同じ処理を命令させるので当たり前ですが。
　というのも、GPUでは頂点計算・ピクセル計算のように、同じような処理をするにもかかわらず、１Threadずつ命令して実行するのは余りにも非効率なうえに、命令ユニットも演算器の数も全く足りなくなってしまうからです[^1]。
![無駄が多い.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/f5e8052a-cac9-f05b-18fa-8d03af720a83.png)
:::

[^1]: ~~ただでさえ3080/3090は大きのに...~~
---
### ルールその３
　この会社では効率化の為に、社長が判断して不要な仕事は社員にやらせず、別の仕事を割り振ります。社長自ら働く素晴らしい会社ですね。
![Warp2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/1192750e-0494-a461-913d-e0b7f1fee847.png)

:::note
プログラマー向け
　これは``Warp``全体での「IF（条件式）」の判断し処理を省略します。
　後述しますが、``Warp``全てのスレッドで``False``になる条件の場合、各スレッド実行前に命令ユニットが判断する事によって、「各スレッドで``False``の判断を下して「処理をしない」とする判断」こと自体が省けます（演算器側での判断）。その場合、条件終了後の処理（``True``になった場合の処理終了後）の命令を実行します。
:::

---
### ルールその４
　何とこの会社では、一部の社員が「この仕事は不可能な状況だ」と判断すると、その社員はサボることが認められます。羨ましい？ですね。

+ 社長「え？不可能な仕事を持ってくるな？いやいや、他の社員は出来ているではないか。」
+ 社員「そんなぁ～。」
![Warp3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/74f868ee-f5ac-a615-113c-3ad2a1f9a540.png)

:::note
プログラマー向け
　ルール３では、``Warp``内全てのスレッドが``False``の場合は、``True``になった場合の処理が省かれて処理後の命令を下しました。では、全て``False``にならず、一部スレッドだけ``True``の条件がある場合はどうなるのでしょうか？
　答えは「``True``になったスレッドのみを処理させ、``False``のスレッドは待機させる」です。そして、``True``側のスレッドの処理が終わり次第、``False``のスレッドの待機を解除し、全てのスレッドを処理します。
:::

## まとめ
　以上の４ルールを守って、GPUの職人は働いています。勿論、同時に働く職人が多ければ多いほど、効率は良くなります。その為、サボっている職人が多ければ多いほど、効率が悪くなってしまいます。つまり、速度が落ちるという事です。
　例えば、単純作業において、全力で働いて仕事を完遂させるのと、半分の力で働いて仕事を完遂させるのでは、どちらが速く終わるでしょうか？そういう事です。

:::note
プログラマー向け
　GPUのシステム上、「<font color="red">**１つの命令で複数のスレッドを動かして**</font>」います。その為にルール４での弊害が発生してしまいます。勿論、「１つの命令」＝「１つの処理方法」なので、「１Warp」内の全てのスレッドは「別々の処理」をさせる事は**基本不可能**だからです。
　ルール４に補足を付け加えるなら、たった「１スレッド」``True``の条件になってしまった場合であっても、必ず``True``のスレッド以外は待機します。そして、そのスレッドの処理が終了しだい、元のスレッドの待機を解除して**全て同時**に実行します。１人の為に他の31人は待機するという事です[^4]。理由は分かりますよね？
:::

[^4]: 遠足に思えてきた（笑）

# 詳しく知りたい人向け（LV.2）
　これ以降は、「GPUの紹介＋IF文」といった感じで紹介します。因みに、本記事ではCUDAの処理方法をメインに説明します。というのも、資料が沢山ある上に分かり易いからです。
　通常、「スレッドの管理」などはGPU側で行いますが、スレッドの呼び出す数などいくつかの部分は、ユーザー側の管理になっている事が多いです。例えば、```CUDA```は「グリッド数」と「ブロック数」をユーザー側で指定します。他にも、```OpenCL```は「スレッド総数」と「スレッド全体を何分割するか」を指定したりします。

## GPUは多次元で分割されている
　CUDAでは「複数のスレッド」をまとめているモノを「<font color="red">**ブロック**</font>」と呼びます。更に「複数ブロック」をまとめているモノを「**グリッド**」と呼びます。CUDAを勉強している方ならご存じですよね？正確に言いますと、スレッドは``Warp``で固められているので「グリッド ＞ ブロック ＞ Warp ＞ スレッド」という関係性になります。下記の画像はあくまでも**イメージ**です。「図形の数＝実際の数」ではありません。
![グリッド ブロック Warp スレッド.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/50c9da20-a997-e3e6-96a5-2005763fca45.png)

　ここで少しややこしいお話なのですが、実はブロック・スレッドは「３次元」として管理されています（ソフトウェア的な概念に近い？）。上記の画像が3Dで描かれているのは伏線でした。
　LV.1で説明されていた例を当てはめると...

+ 会社（社長）＝ ブロック
+ 部署 ＝ Warp
+ 会社員 ＝ スレッド

に当たります。つまり、「会社」の上には「社会」という名の「グリッド」がある訳ですね。

## GPUのハードウェア的なあれこれ
　これだけ見ると、結構シンプルに見えるのですが、実際にはハードウェア（GPU）が関係してきます。実は先ほど「会社（社長）」としたのですが、正確には別です。
　というのも、「複数のブロック」を管理しているのは「グリッド」なのですが、ハードウェア的には「<font color="red">**SM（ストリーミング並列プロセッサ（Streaming Multiprocessor））**</font>」によって、１つブロックを処理します。勿論、``SM``も複数個あるので、それらを管理しているのはどこかというと、「**Giga Thread Engine**」によって「複数の``SM``」の動作を管理しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/31dab561-dd78-c86c-df3b-864f98ba516a.png)
※[画像の参照元（P.34）](https://www.slideshare.net/NVIDIAJapan/cuda-57590006 "菱洋エレクトロ株式会社 IS推進部 CUDA エンジニア　石井　琢人様が講義されたスライドです。NVIDIA Japanなので間違いない情報のはずです。")

## ソフトウェア・ハードウェアの管理
　はい、訳が分からなくなってきましたね。分かります。ここで一旦整理しましょう。
![グリッド ブロック Warp スレッド.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/af4484c4-d9cc-c8d2-2610-3f28a4ab6c9d.png)
　スレッドはWarpによって管理され、Warpはブロックによって管理され、ブロックはグリッドによって管理されています。「グリッド ＞ ブロック ＞ Warp ＞ スレッド」です。簡単ですね。
　ですが、これはあくまでソフトウェア的な考え方であって、ハードウェアとなると話が変わってきます。つまり、「仕事」と「人」で管理方法が異なるという事です。LV.1の例で説明しましょう。

### 仕事
　今までは会社員として説明してきましたが、ハードウェア的な概念が混じると説明出来ないので、分解します。会社員はいわゆる「労働（仕事）」をする「人」です。ここでは「労働（仕事）」についてです。
　「１つの仕事」は「１つスレッド」として扱われます。ここに「仕事＝スレッド」条約が締結されました。
　前述している通り、仕事は１種類だけではなく、いくつも種類があります。種類ごとに仕事をまとめる場所として「部署（``Warp``）」があり管理をします。更に、部署は「会社」で管理されています。これがソフトウェア的な考え方になります。
　ですが、これでは会社として機能（活動）出来ません。「会社」と「会議室などの部屋」があるのに「仕事をする人」が存在しないからです。まるで、ペーパーカンパニーです。
![business_paper_company.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/ac60076f-1d4a-2a2e-6aa1-10c8c2a8da33.png)

### 人
　ここでは「仕事をする人」についてです。「１人」はGPUの場合「演算器」と言えます。``CUDA``で言うと「``CUDA``コア」になります。勿論、「一人」だけでは働けないので仕事を与える必要があります。
　それが「部署長」つまり``SM``になります。そして、「部署長」には複数人をまとめて管理出来る能力がありますが、「部署長」は「１つの命令」を「全員へ発行する」という管理を行っています。実は社長と会社員の間に部署長が隠れていたわけですね。
　なので、複数で別々の命令を出したい場合、複数の``SM``が必要になってきます。複数存在する場合やはり、それらを管理する必要があるので、``Giga Thread Engine``つまり「社長」によって管理します。各``SM``で勝手に命令を出されては大変な事になってしまうからです。これが、ハードウェア的な考え方になります。
　ですが、これも同じくこのままでは会社として機能（活動）出来ません。当たり前ですが、命令を下すための「仕事」が無いからです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/64e8c893-028e-c26a-c916-d019952192ec.png)
※[画像の参照元（P.31）](https://www.slideshare.net/NVIDIAJapan/cuda-57590006)

　上記の通り、「人」と「仕事」の両方あってこそ存在出来る「会社（GPU）」です。違いが分かってもらえたでしょうか？

## ``SM``はブロックをどう処理するか
　少しおまけなのですが、``SM``とブロック間で必ず守らなければならないルールが存在します。

+ １つの``SM``で実行されるブロックは１つ
+ １つの``SM``に複数のブロックが同時に存在出来る

以上です。これらのルールを守って処理していきます。
![SM Block.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/5026b4af-6c53-002f-ad42-58cec3bf711c.gif)
　イメージ的には上記のようになります。ただし、<font color="red">ブロックの実行順序は保証されず、特定の``SM``へのブロック割り当ては出来ません</font>。あくまでイメージ図です。更に、ルールで書かれていた通り、``SM``で実行されるブロックは必ず「１つ」なので、実行中に新しいブロックが来た場合は待機する事になります。
　つまり、社長は部署長が今すぐ仕事出来るかを気にせずに仕事を投げていたわけです。勿論、今すぐ処理が出来ない場合はどんどん処理（タスク）が積み重なっていきます。
![Block SM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/7fef5579-6c8b-f0c5-2770-5f892ba6d64b.png)

## GPUの目的
　ここで改めて目的について触れますが、GPUで処理するのは頂点計算・ピクセル計算などの「同じ処理ばかりなのでまとめて処理してしまおう」＝「１つの命令で複数のスレッドを処理しよう」という考えからきています。この考えを、「<font color="red">**Single Instruction Multiple Thread (SIMT)**</font>」と言います。
　つまり、SIMTの言いたい事は「１頂点＝１スレッド、１ピクセル＝１スレッドで処理しよう」という事です。しかし、全てのピクセル・頂点で行う処理は出力結果が異なるだけで実行処理は全く同じですよね？なので、「**１つの命令**で**複数のスレッド**を使い処理しよう」という事です。
　このように、「１つの命令で複数のスレッド」を扱う単位をNVIDIAは「**Warp**」と決めました。やったー、これで命令処理の手間が圧倒的に省けるぞー（棒）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/41344458-9dce-16d6-e657-e2470fea45b2.png)
※[画像の参照元（P.58）](https://www.slideshare.net/NVIDIAJapan/cuda-57590006)
あ、UFOのワープとは関係無いですよ。

## IF問題
　ですが、現実問題として全く同じ実行処理では済まない場合が多いと思います。プログラミングには欠かせない「IF文」です。このままでは１つの``Warp``の中に、条件が成立するスレッドと不成立のスレッドが混在してしまい、同じ処理が出来ないではありませんか。
　そこで考え出されたのが「スレッド自体に処理実行の可否判断をさせればいいじゃないか」という方法です。そうする事で、疑似的に同じ処理をさせる事が可能になるからです。つまり、条件が不成立の時だけ実行処理を無視するという事です。ですが、「無視するだけで速度が速くなる訳ではない」ので注意して下さい。
　言い換えると、１ピクセル毎に実行処理の可不可を判断し、実行出来ない場合は「１ターンお休み」をします。（節電の為に読み出し処理や計算を止めるからです）
![Thread Play Stop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/6edaf82b-93f8-dc1c-0c62-e8740688109f.png)

## まとめ
　このように、GPUにとってのIFがどれだけ厄介かをご理解いただけたのではないのでしょうか？これだけ書いてあれですが、分からなくても問題ありません。タイトル通り「GPUでIFを使うな」を覚えてもらえれば大丈夫です。プラスαで覚えてもらうならば、「IFを使うとしても、出来る限り短く書け」といった感じです。

# もっと詳しく知りたい人向け（LV.3）
　これ以上知りたい人はかなり少ないと思いますが、GPUのマルチスレッド方法・実行ユニットにも踏み込んでいきます。

:::note warn
改めて注意
　ここで本音を吐くと、私なりに理解して考えまとめた上での記述なので、勘違い・間違いの可能性は普通にあり得ます。何度も言いますがその点をご理解した上でご覧ください。最終的にはご自身で判断いただくようお願いします。参考サイトは一番下に書いてありますので、それも参考にして下さい。
:::

## スレッドのフリーズ対策
　実は、LV.1の会社員について少し修正する事があります。普通、会社員が仕事をする時は何か道具を使いますよね？会社員の例ではパソコンでしたが、GPUでは実行ユニット（以降は「**PE**」とします）に当たります。この``PE``がやっていることは演算処理やレジスタでのロード/ストアなどの処理です。
　それだけならいいのですが、ご存じの通り、演算処理にしろロード/ストア処理にしろ絶対に処理時間がかかります。するとどうでしょうか？次の命令実行まで待機する羽目になってしまいます。パソコンで例えるならフリーズ状態です。
　こんなことは許されません、作業が止まってしまいます。ですので、それらを回避する為に、``PE``ごとに複数のスレッドを持ち、処理待ちしている間、別のスレッドを実行するという手段をとっています。そして、別のスレッドへ・・・別のスレッドへ・・・を繰り返し、最初のスレッドに戻ってきている時には、既にそのスレッドでの処理を終えているという算段です。
　会社員の例で例えると、１台目のパソコンに仕事内容を入力して結果が返ってくるまでフリーズ、直ぐに２台目を使って仕事内容を入力→結果待ち、３台目入力→結果待ち・・・。手持ちのパソコンを全て入力し終えたので、１台目に戻ってくると既に結果が表示されている。といった感じになるでしょうか。
![スレッド オーダー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/a04f8ce4-b8f9-5a62-6b99-2ad865dacf22.png)
　つまり、この会社の会社員全員に約10台のパソコンが配られるようです。現実ならそんなに要りませんが（笑）
　LV.1での説明では一人当たり、約1スレッドを持っている表現をしました。ですが実際には一人当たり約10スレッドを持っています。簡略化の為に省略したので、ここで報告します。
![PC沢山.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/db3a6b11-b20a-592f-9a8f-432343c46f22.png)

## 実行ユニットの動き
　今度は実行ユニット（PE）視点からの「IF」問題を見てみましょう。

　さて、``PE``が大量に集まったものがGPUとも言えるわけですが、何度も言っている通り、GPUには同じ処理を行うことが多いです。なので、「どうせ同じ処理しかしないから、命令機構は１つでいいだろ」と思うかもしれません。ですが、GPU君にとって難敵「IF問題」などがあるので、ある程度自由に出来た方が良いわけです。ここでは、スレッド＝``PE``として扱います。

![笑えない.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/8b896cc9-4e23-caba-49d0-34448cd7f0ae.png)
　上図で分かると思いますが、何度も言っている通り、IFが存在する場合は「条件が成立する``PE``」と「不成立の``PE``」が混在してしまう可能性が非常に高くなってしまいます。そして、「１つの命令」に対しては「同じ処理」しか出来ません。例え１つでも「条件が成立する``PE``」が存在してしまうと、他の「不成立の``PE``」の処理が<font color="red">**全て**</font>ストップしてしまいます。
　つまり、何万・何十万ものスレッドに対して命令機構が１つだけだと、他の「不成立の``PE``」が全てストップしてしまいかねません。これでは大量に同時並行で処理出来るGPUの強みが無くなってしまいます。全く笑えません。

![まだまし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/e3620d34-b7a3-dbbe-8ece-f033ddcb15f9.png)
　上図のように、命令機構を複数個用意して、「全て」ではなく「一定数」の``PE``に対し１つ命令機構を付けます。こうする事で、命令を分割する事が可能になり、ストップする影響範囲が「１命令単位」で済みます。すると、全体的に動く``PE``を増え実行率が増加する訳です。ただし、命令機構へ「命令」を出す「命令機構」が必要になります[^2]。組織である以上は統率する者は必要ですので。
　兎にも角にも、比較的まだ「まし」になります。決して「GOOD！」とは言えませんが。

![だいぶマシ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/3abee0e4-5351-7239-7669-3ff258c27e7b.png)
　ならば、「命令機構を増やせばいいじゃないか」となるかもしれませんが、上図のように命令機構を増やしすぎると、逆に全ての命令機構に命令する手間・時間が増え、実行率は上がるものの、実行するまでに時間がかかるという事になります。これではあまりにも手間がかかってしまい非効率になってしまいます。更に、命令機構を増やすという事は「物理的」に機構が増えるのでGPU自体が大きくなってしまいます。となると、``PE``か命令機構もしくは両方を減らさざる負えなくなってしまい、これでは本末転倒です。[^6]
　つまり、命令機構と``PE``の**バランス**が大事になってきます。実際に、NVIDIAは``32PE``ごとに命令機構を搭載し、AMDは``64PE``ごとに搭載しています。

[^2]: 上からの命令（物理）
[^6]: 今思ったんですが、画像がごちゃごちゃしすぎですね。もう少し少なくするべきだったかな？

## 「Streaming」で「Multi」な「processor」
:::note warn
ここの欄について
私がいくつかの記事から考察して記述しているので、間違えの可能性が十二分にありえます。
:::

　先ほどから``SM``と何度も記述していますが、略さずに言うと「Streaming Multiprocessor」です。でも、よく考えてみて下さい。

+ Multi ＝ 複数の
+ Processor ＝ 処理装置
+ multiprocessing ＝ 複数の並行プロセスを同一システム内で使用すること[^3]

　では残りの「Streaming」は何でしょうか？この言葉、近年では「ストリーミング再生」のように、よく聞く言葉ですよね？単語自体は簡単に調べた限り「流れ」が近いでしょうか。プログラムが処理されることを「流れ」と言っているのでしょうか？私は違うと考えています。むしろ、「流れ」より「逐次」の方が意味的には近いと思っています。といっても、英語では「Sequential」になってしまいますが...[^5]。
　前述した[スレッドのフリーズ対策](#スレッドのフリーズ対策)の時に記述しましたが、１つの``SM``は複数個のスレッドを管理しています。ですがその時に「チョッ マテヨ」と感じた方はいましたか？

+ **32**実行ユニットごとに命令機構を搭載している
+ 実行ユニットは複数のスレッドを管理している（大体10スレッド）
+ ``Warp``は**32**スレッドで、それが実行の最小単位になっている
+ ``Warp``は「１命令を**32**並列」で実行されている

　あれれぇ～おかしぃ～ぞぉ～？命令を実行しているのは「複数のスレッド(約10スレッド)を持つ複数の実行ユニット（32PE）」なのに、実行の最小単位は``Warp``（32スレッド）ではありませんか。
　つまり、実行の**最小単位**は``Warp``であるにもかかわらず、**複数の実行ユニット**が**複数のスレッド**を持っている上で実行している事になっています。訳が分からなくなってきました。

　こういう時こそ落ち着きましょう。素数を数えましょう。0,0,0,0,0,0,0,0...。失礼しました。
　私の考えは、あくまでも``Warp``（32スレッド）＝ 複数の実行ユニット（32PE）です。``Warp``は複数あり、**１実行ユニット**も約10スレッド持っている。つまり、**１度**に複数個の``Warp``（約10Warp）を実行しているのではないかと考えました。
　更に、「１SMは１ブロック（複数個の``Warp``の塊）のみ処理」されますよね。そうです、複数個``Warp``があるので、それが実行ユニットの複数のスレッド分だけ複数の``Warp``が実行されるという考えに落ち着きました。
![Streaming Multiprocessor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/1dff0e4a-cd04-9844-bd69-5bbcfe91e5d2.png)
　上図を見て頂ければ大体私の言いたい事が分かると思います。これらの事を「IF」とからめると、命令機構は``Warp``ごとに命令しますが、あくまでも、別の``Warp``には影響せず、その``１Warp``のみ影響します。そして、影響する時間は他の``Warp``の処理が終わり１周回ってくるまでです。これは、ボードゲームの「１ターンお休み」がイメージとしては一番近いと思います。

![Streaming Multiprocessor 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/2c13437e-3bc5-fdcf-1368-2cb6c7391e58.png)

　上図のような感じで``PE``が管理しているスレッドを「**逐次**」実行していき、``SM``が管理している``PE``を「**複数同時**」に「**処理する装置**」だと私は考えました。これぞまさしく「Streaming」で「Multi」な「processor」です。
　これらの事は、他の記事では完全に省略して記載していると思います。どう考えてもややこしくなり過ぎますからね...。以上、私の考察でした。

[^3]: Wiki先輩より
[^5]: 偶然かこちらも先頭が「S」ですね。

## まとめると・・・？
+ １つの実行ユニットは「複数のスレッド（約10スレッド）」を管理
+ 命令機構は「**32**」実行ユニットごと
+ ``Warp``も「**32**」スレッドごと
+ ``Warp``は「１命令を**32**並列」で実行

何となく分かってきましたよね？更に言葉を付け加えると...

+ ``Warp``を複数個まとめたものが「ブロック」
+ ブロックは``Streaming Multiprocessor(SM)``で管理。つまり下請けです。
+ 複数の``SM``は「Giga Thread Engine」で管理。つまり元請けです。

以上の事を踏まえて、画像処理でGPUの働きをまとめると、以下のようになります。
### パート１
![画像処理１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/0fec081e-2f44-12e7-08bc-dc7fcd535102.png)
　かなり適当ですが、エンジニア（発注主）が画像処理をGPUに投げる場合、CUDAはメンドクサイ処理などを内部でやってくれます。その為のライブラリなんですが（笑）
　さて、今回はCUDAを使って処理するとしましょう。プログラム上で「実行関数」が呼び出されると、「Giga Thread Engine」君が「任された！」と処理を開始します。

### パート２
![画像処理２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/44578218-1cca-caaf-964b-733dd14246d4.png)
　「Giga Thread Engine」は画像を分割して処理しようとします。画像を分割した物を「ブロック」として処理します。その分割したブロックは``SM``達へ仕事として渡されます。ですが、１つの``SM``では「１ブロック」しか処理出来ないので、他のブロックはタスクとして待機します。上図では点線に囲まれた画像の事です。
※ 各ブロックの数字はランダムです。

### パート３
![画像処理４.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/b645e57a-d877-9fe0-2a52-f5296e2cc179.png)
　各``SM``は作業予定のブロック（画像の一部）を細分化し、「１ピクセル＝１スレッド」として扱います。ですが、命令の最小単位はあくまでも``Warp``（32スレッド）なので、``32PE``のスレッドごとに``１Warp``仕事を与えます。
　そして、命令機構は各``PE``に「実行処理を開始しろ！」と命令します[^7]。

[^7]: あくまでもこういう感じかな？という私の考えなので、実際にどのようにGPUで処理されるかは分かりません...。

### パート４
![画像処理５.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/66a59ebb-d47e-b95c-ba68-31911d2090f8.gif)
　命令機構は``Warp``ごとに命令を出して``PE``が動きます。上図の場合は「IF」が存在する場合の``Warp``の大体の動き方になります。（勿論、絶対正しいと言えないのでイメージですが...。参考程度でお願いします。）

# 最後に
　やってしまった、また記事が長くなってしまった...。内容的に分割してしまうと訳が分からないと思うので、分割しなかったのですが、いかんせん量が多くなってしまった...。ここまで、全て読んでくれた方には感謝しかありません。知らなくても問題ない内容に貴重な時間を割いていただき、本当にありがとうございます。書いておきながら申し訳なさが出てきてしまいました。

　ここまで読んだ方なら大体の事は分かってもらえたかと思います。これ以上の事は長くなりすぎるので説明は除きますので、気になる方は下記のリンクから覗いてみて下さい。

# 素材
+ [イラストや](https://www.irasutoya.com/)がほとんど[^8]
+ [CMAN](https://sozai.cman.jp/)はアイコンなど
    + [再生ボタンダウンロード先](https://sozai.cman.jp/icon/player/play/)
    + [一時停止ボタン](https://sozai.cman.jp/icon/player/pause/)
+ [NVIDIA JapanのSlideshare](https://www.slideshare.net/NVIDIAJapan/cuda-57590006)のスライドからいくつか参照しました。
それ以外はパワポを使った自作です。

[^8]: 非商用なので種類制限は問題ないはず...というより、そもそも20種類も使用していないと思われ...。

# 参考サイト

https://news.mynavi.jp/article/architecture-341/

https://zukaaax.com/archives/357

https://yusuke-ujitoko.hatenablog.com/entry/2016/01/27/210415

https://www.slideshare.net/NVIDIAJapan/cuda-57590006

https://www.slideshare.net/KMC_JP/gpgpu-91122680

https://news.mynavi.jp/article/architecture-340/

https://news.mynavi.jp/article/architecture-314/

https://news.mynavi.jp/article/architecture-349/

https://news.mynavi.jp/article/architecture-318/

https://news.mynavi.jp/article/architecture-204/

https://news.mynavi.jp/article/architecture-342/