例年、EMS 組込みマルチコアサミット)を開催してきましたが、今年は少し形をかえて実施します。
11月21日(木) 13:40-14:10(予定)パシフィコ横浜にて開催されるEdgeTech+2024において
「組込みマルチコアコンソーシアムが見る組込み産業の課題」と題して枝廣が講演します。
詳しくは以下の記事をご参照下さい。
コンパイラはプログラムを動作させることなく解析するため、実行時にならないとわからない情報の解析には限界があります。その代表例がC言語のポインタです。ポインタの値はOS等が割り当てるメモリ番地であるため、実行時にならないとわかりません。以下で詳しく説明しますが、ポインタを利用(特に演算)すると、処理の依存関係(データの読み書き順序などの理由で生じる処理の実行順序関係)の解析が難しくなり、2つの処理A、Bの依存関係が不明という状況が生じます。本来、処理AとBには依存(実行順序の制約)がなく、並列に処理できるにもかかわらず、コンパイラの解析で不明になってしまうと、コンパイラは処理AとBを並列実行せず逐次的に実行する選択をせざるを得ないため、並列性能が下がってしまいます。
ポインタの話をする前に依存関係(正確にはデータ依存関係)について具体的な例を用いて説明します。依存関係とは、例えば下図左のように複数の処理が同じ変数に対して読み書きしており、その実行順序が結果(この場合には変数zの値)に影響するような場合をいいます。依存関係は並列化に重要な影響があり、この例の場合には処理Bは処理Aよりも必ず後に実行される必要があり、処理AとBは並列処理できません。下図右のように読み書きする変数が異なれば結果に影響することがなくなり、処理AとBは並列処理が可能になります。そのため、最大の並列性能向上を得るためには処理の依存関係を減らすことが重要です。依存関係を減らすためには、当然ながら処理のアルゴリズムにおいてできるだけ依存をなくすことが肝要ですが、今回は、依存関係が存在しないにも関わらずコンパイラの解析によって依存があるかもしれないと判断されてしまうケースについて考えます。
シングルコア向けに書かれたソフトウェアを自動的にマルチコア向けにコンパイルするツールが自動並列化コンパイラです。
前回の動画で紹介したMBP (Model Based Parallelizer) (https://www.esol.co.jp/embedded/product/embp_overview.html )はMathworks社のSimulinkモデルを入力とする自動並列化ツールです。C/C++言語プログラムなどからの自動並列化ツールとしては、Intel社のコンパイラ (https://www.xlsoft.com/jp/products/intel/oneapi/index.html)や早稲田大学笠原研究室のOSCAR (https://www.kasahara.cs.waseda.ac.jp/index.html.ja)などが知られています。
自動並列化は以下の手順を全自動で実行します。手順については第12回「マルチコアで動作するソフトウェアとは」も参考にしてください。
①
ソフトウェアの分割
下図の①のようにソフトウェアを分割します。図において、カッコ内の数字は分割したソフトウェアの実行時間で、並列化の際に負荷分散を考慮するときに使います。
②
依存関係の抽出
下図の②のように分割したソフトウェアの依存関係(データの読み書き順序などの理由で生じる処理の実行順序関係)を抽出します。
③
並列化コードを生成
分割したソフトウェアを、実行環境で並列に動かすことができるソフトウェア部品(タスクやスレッド)としてコードを生成し、必要に応じて部品(タスク、スレッド)間通信等を挿入してプログラムを生成します。下図の③は実行例で、塗りつぶした長方形が部品間通信です。
今年も猛暑ですね。私の住む名古屋も体温を超える気温が当たり前となってきております。
本コンソーシアムで実施しているアンケートでも、マルチコア利用はほぼ当たり前になって来ています。一方、マルチコアの使いこなしが出来ているかというと、まだまだという状況の様です。「マルチコアを使ってしばらく経つが、正直あまりよく分かっていないけど、今更基本は聞けない。。」、「分かっているつもりだが、正直自信はない。。」という方も少なくないのではないでしょうか。そんな皆様に少しでもお役に立てれば、ということで本コンソーシアムではYouTubeにEMCチャンネルで基本のお話を紹介してきましたが、今回もう少し詳しく、図なども踏まえて「マルチコアの基本」を紹介するブログ記事シリーズを始めました。このシリーズでは、マルチコア・メニーコアとは、マルチコアの種類、マルチコアと電力や性能の関係、シングルコア上のソフトウェアからの移行など、基本的な用語や考え方を説明しています。
例えば、第1回ではマルチコア・メニーコアとは何かについて説明しています。第10回、第11回では、下の図のような例題をもとにマルチコア上でのソフトウェア性能見積の基本と難しさについて紹介しています。第12回では同じ例を使ってシングルコア上のソフトウェアからの移行の基本について説明し、第13回ではそのようなソフトウェアの資産性や再利用性の確保、第14回ではマルチコアに移行するときのルールについて動画コンテンツを用いて紹介しています。
マルチコアに対してよく聞かれる質問です。第12回で書いたように、マルチタスクで記載されたプログラムはマルチコアでそのまま動作する可能性はありますが、そうでないプログラムはそのままでは一つのコアでしか動かないため、自動もしくは手動での並列化が必要です。
いずれの手段を取るにしても、これまで一つのコアで順番に動いていた処理が同時に動くようになるため、いくつかのルールを守らないと動作結果やふるまいが「そのまま」ではなくなる場合があります。
次の動画では、これらの観点から質問に答えています。
なお、すべての動画はEMCのYouTube動画ページからご覧いただけます。
今回はマルチコアで動作するソフトウェアについて説明します。
マルチコアといっても、GPUなどを使うヘテロジニアス・マルチコアについては概念が異なってくるので別の機会に譲り、今回はCPUマルチコアについてのみ考えます。
CPUマルチコアで動作するソフトウェアを書くことは、第10回(リンク)で説明した図(下に再掲)をプログラムにすることになります。これを並列化プログラミングとよびます。下の図で、上段はソースコードでのイメージと依存関係のグラフ、中段はシングルプロセッサにおける実行、下段はマルチコア上での実行イメージで、黒く塗りつぶした四角はコア間通信です。並列化プログラミングは、上段のプログラムから下段の実行になるようにすることです。なおここで、マルチコア上での実行には、静的スケジューリングにより各処理の実行コアまで決める方法と、OSなどの動的スケジューリングに任せる方法とがあり、下では簡単に区別します。
前回、一つのアプリケーションの例を用いてマルチコア性能向上の概算手法について説明しました。今回はシステムになったとき難しくなる理由について説明します。
前回の概算手法は、下の図のような実行に対し、各処理の実行時間と、コア間通信やループ並列化のオーバーヘッドの値が既知であるとして計算する手法でした。最初にそれらの値の取得について考えてみます。なお、下の図において黒塗りの四角がコア間通信です。
前回までに、マルチコアによる性能向上に関連して依存関係やオーバーヘッドの話をしました。では結局の所、性能はどのくらい上がるのでしょうか。特にマネジメントとしては大変気になるところです。しかし、聞いても誰も答えられず、やってみないとわかりません、といったマネジャーの機嫌が悪くなる回答しか得られないことがほとんどです。この問題について2回に分けて考えてみたいと思います。
今回は、まず一つのアプリケーションでの並列性能向上を概算する方法について説明し、次回、システムになったときに性能見積が困難になる要因について考えてみます。
下の図のようなソースコード構成を持つアプリケーションを考えます。ソースコードは図のようにAからEまでの部分に分かれ、Aから開始し、それぞれ最大一回ずつ実行されるとします。括弧内は実行時間です。依存関係については以下のようになっているとします。
・ データ依存関係:Aで生成されたデータをBとCが使い、BとCでそれぞれ生成されたデータをEで使う
・ 制御依存関係:Cの結果によりD-1またはD-2のどちらかが実行される
これらの依存関係をグラフとして表現すると下図右のようになります。実線はデータ依存関係、破線は制御依存関係で、矢印の始点側の処理が終わらないと終点側の処理を開始できない、という関係を表現しています。
マルチコアでは、スーパーリニアといって、コア数を超える性能向上が得られる場合があります。
スーパーリニアはリソースが増えたことにより起こります。例えば、シングルコアの時と比べて2コアではキャッシュが2倍になりますが、それが良い影響を及ぼすことがあります。
例として、大きな配列を扱う処理があり、配列全体は一つのプロセッサのキャッシュに載らないが、分割すれば二つのプロセッサのキャッシュに載るようなケースを想定します。また、キャッシュがヒットする場合はミスする場合と比較して処理が2倍高速になるとします。このとき、下の図のように、シングルコアではデータサイズが大きいため常にキャッシュミスすると仮定し、全体で100の処理量があるとします。2コア実行で、そのままキャッシュミスする場合、理想的には2倍の高速化ですが、データが各プロセッサのキャッシュにすべて載ったことにより、さらに2倍高速化し、全体で4倍の高速化になります。このような場合、前回までに説明したオーバーヘッドの影響があっても、コア数よりも高速化することがあります。
前回、コア数を増やしてもコア数ほどには性能があがらないという話をして、その理由の一つとしてオーバーヘッドの話をしました。
例えば、一つのプロセッサで計算量が100の処理を2つのプロセッサで実行させようとしたとき、相手のプロセッサに処理依頼をする、結果を受け取るといった処理がオーバーヘッドになります。その処理の計算量がそれぞれ20とすると、全体で処理量が140になってしまい、処理を理想的に2分割できたとしても各プロセッサの計算量は70になり、性能が2倍になることはありません(下図左)。もとの処理量が10倍の1000であれば、オーバーヘッドの計算量は変わらないため、状況はよくなります(下図右)
●マルチコア適用ガイドのリニュアル版公開
●EMCブログ「はじめての並列化」も好評連載中
一般社団法人 組込みマルチコアコンソーシアム
〒104-0042 東京都中央区入船1丁目5-11 弘報ビル5階