マルチコア上で動作するプログラムは、コアを有効利用するために並行性を持つ様に構成(Thread化)する。それらのスレッドは別なコア上で動作する場合、物理的に並列動作する。
このようなシステムで、プログラムの並列性を理解して設計する事は次の様な観点から必須となる。
ソフトウェアを、マルチコアで動作させること、もしくはマルチコアで動作するように変換することを「並列化」と呼ぶ。最初に、ソフトウェアを並列化するための手法や開発プロセスの課題について説明する。ソフトウェアの並列動作可能な計算資源へのマッピングとして、計算資源の有効利用が課題とされている。また、並列プログラムは以下のような挙動理解が困難である。
並列プログラムの挙動には「非決定性」を含む場合がある。非決定性を持つプログラムでは、状態遷移の分岐が排他的でない。これはテストプログラムや不具合事象の再現性が悪く、デバッグしにくい。
並列に動作する別別のスレッドが別々の状態遷移を持つため、システムの状態はその組み合わせになり、複雑で、膨大な振る舞い空間をもつ。これはシステム挙動の網羅的な検証が困難である。
マルチコア上で動作する並列プログラムの挙動には非決定性が含まれる。
プロセスPAとPBが並行に動作する場合、「可能な挙動」は組み合わせが膨大になりうる。
PA = ea1 -> ea2 -> ea3 -> Stop;
PB = eb1 -> eb2 -> eb3 -> Stop;
複数スレッドが共有メモリ領域を読み書きする場合に起きる。並列に動作する複数のスレッドが共有の記憶領域に対して同時に書き込むような場合に、データが適切に更新されず、矛盾・破壊する事がある。これではプログラムの機能(入出力仕様)が保証されない。データ破壊は同時書き込み時に起こる。また、データ不整合は複数のメモリ内の情報の間に成り立っていなければならない関係(条件)が崩れる。
並列に動作する複数のスレッドが共有の記憶域にアクセスするために組み込んだ「排他制御」が想定通りに動作せず、システムが停止してしまう。これではプログラムの可用性が保証されない。また、共有リソースのロックが外れなくなる。
次の例では、連続するタイミング1,2においてThread A,BがそれぞれリソースR1,R2を異なる順番でロックすることでデッドロックするケースを示す。
タイミング1:
ThreadAがリソースR1を利用(R1をロック)
ThreadBがリソースR2を利用(R2をロック)
タイミング2:
ThreadAがリソースR2を使おうとしてR1のアンロックを待つ
ThreadBがリソースR1を使おうとしてR2のアンロックを待つ
<<<Deadlock>>>
形式検証では、対象システムの挙動をモデル化する。このモデルは、形式仕様記述言語(プログラムの構造を数学的な意味で厳密に記述するために設計された言語)で記述したモデルである。これにより、非決定的なモデルが表現でき、そのモデルに対して網羅的な検証が可能である。
挙動のモデルは「状態遷移」の考え方の数学的な表現。次の2種類が知られている。
有限オートマトンを用いる
並行プロセスを代数的な操作ができる「式」として表現する事で、並行動作するシステムの振る舞いを解析する。プロセス代数(CSP等)で、並行動作するシステム同士が協調動作する事を表現するのに「チャネル」の概念を使う。ここで、プリミティブ要素として「同期チャネル」を用意しているが、拡張要素として、「通信バッファ数」を指定できるモデルもある。
記述例
PA || PB
Spec <refine> Dsg
Name | Model | language | Distributed by | feature | |
---|---|---|---|---|---|
SPIN | automaton | Promela | Gerard J. Holzmann | Most measure | |
NuSMV | automaton | SMV | ITC-IRST (Italy) | many model | |
UPPAAL | Timed automaton | NTA | UP4ALL(Demmark) | Timed model Easy to use(GUI) |
|
PAT | CSP(base) | CSP# | Semantic Engineering | Many model | |
SCADE | Scade | Lustre | ANSYS/ESTEREL | Model Base | |
Simulink Design Verifier | Simulink/Matlab | Simulink model | Mathworks | Model Base |
より詳細はWikipediaを参照
並列処理に必要な要素を言語要素として持つ
プロセス代数(CSP)由来のもの。バッファサイズ指定が可能
make(chan int, 8) // バッファサイズ8のint型チャネル ch :=
定義した関数を「go」というキーワードを付けて呼び出す事でスレッド生成を意味する(「go routine」と呼ぶ)
go hello(); // hello 関数を別Threadで実行. helloは別途定義した関数
go world(); // world 関数を別Threadで実行. worldは別途定義した関数
「所有権(ownership)」概念の言語要素化
→ 安全でなければコンパイルが通らない
let(tx, rx): (Sender<i32>, Reciever<i32>) = mpsc::channel();
let child = thread::spawn(move || {<Thread手続き本体>})
EndPoint ep1, ep2;
Channel ch = new Channel<DataType>(ep1, ep2);
DataType data;
send(ch, data); // Code in Thread 1
receive(channel, &data); // Code in Thread 2
遷移イベントはアプリケーションによるOSのAPIコール
ソフトウェアのアーキテクチャ、デザイン、コーディングなどに対して、解決策としてのパターンを共有する。パターンはお互いに関連しあい、連携して利用されるパターン言語を形成する。
代表的な設計パタンのルーツは次の通り。現在は様々な領域でのパターン活動がある
※ Eric Gamma, Rechard Helm, Ralph Johnson, john Vissides
マルチ/メニーコアを利用したハードウェア上で動作する「並列処理ソフトウェア」に対しても、この「パターン」の蓄積・共有が有効だと思われる。
これらの設計パターンを用いる動機は、起こって欲しくない「設計由来の問題」をなくしたいことである。
活用可能なパターンカタログを作るために以下のような項目がそろっているのが望まれる
ソフトウエアアーキテクチャパターンの書籍(POSA:Pattern Oriented Software Architecture)中に並列処理パターンもいくつか紹介されている。
Intel発信の情報
https://software.intel.com/en-us/node/506112
以下のようなパターンが紹介され、それをどの様に実装するか解説されている
並列プログラムを構成するためのパターンを紹介し、後半にはそれらを使った並列アルゴリズムの解説を行っている
アンチパターン (英: anti-pattern) とは、ある問題に対する、不適切な解決策を分類したものである。 語源は、ソフトウェア工学におけるデザインパターンである。 主に失敗した開発プロセスに焦点を当てて失敗に陥るパターンを類型化する。 そうすることで、そのような事例の早期発見と対応策に関しての提案を目的とする。
マルチコア・システム開発に置いても、さまざまな不具合事象をパターンとして整理する活動を行う事で、同様の効果を期待できる。
マルチコアプロセッサと並列指向の言語やライブラリが与えられただけでは、それを有効活用するソフトウェアを構築するのは簡単ではない。
現状はある程度専門的なエンジニアがこれらを担っている。今後は、マルチコアを活用するソフトウェアをより多くのエンジニアが開発できるように、つかえる支援ツールの充実が望まれる。
並列化されていないプログラムのどこが並列化可能か、並列化する事による性能改善への寄与が大きいかといった情報を開発者へ提示。Threadプログラミング支援。
並列化されていないプログラムをスレッドライブラリなどを利用した並列化されたプログラムに変換する。
それにあたって、並列化されていないプログラムを解析(基本的にはデータフロー解析)して並行動作可能部分を抽出しスレッド化プログラムとして再構成する。さらに、限られたコア数に対してそれらのスレッドを割り当て配分する。
モデルベースの設計ツールが対象としている「モデル(ソフトウェア観点)」には、「データフロー」モデル、および、「状態遷移モデル」をがあり、これらをグラフィカルエディタなどの支援のもとに設計すると、そこから並列性を自動抽出することが可能となる。
SimulinkモデルとSimulinkモデルから生成されたCソースコードから並列化(Thread化)されたCソースコードを出力。
Threadのコア割り当てのためにSHIM(IEEE Std 2804)を利用した性能見積もりを行う。
マルチコア環境でのプログラム・デバッグでは、ステップ実行やブレークポイントを利用した操作でのデバッグが難しい。そこで、タイムスタンプのついたトレースをとり、実行後に可視化などをする事で現象分析する事が有効となる
しかし、可視化機能、解析機能などを持ったツールはトレースフォーマットに依存したものになるため、標準的なフォーマットが必要となる。