図1は、実施の形態によるプログラム並列化装置を含むプログラム並列化システムの機能を説明するための一例の機能ブロック図である。このプログラム並列化システムは、プログラム解析部101と、プログラム並列化装置に対応するプログラム並列化部102と、プログラム変換部103とを備える。プログラム解析部101は、入力された逐次プログラム110を解析し、解析結果として終了制御情報120、変更情報121およびデータ依存情報122を出力する。なお、逐次プログラム110は、各指示が一列の時系列上で逐次的に実行可能に記述されたプログラムをいうものとする。
なお、ここでは、プログラム並列化装置がプログラム並列化部102に対応しているように説明しているが、これはこの例に限定されない。例えば、プログラム並列化装置は、プログラム並列化部102に加えてプログラム変換部103を備えていてもよい。さらに、プログラム並列化装置は、プログラム解析部101、プログラム並列化部102およびプログラム変換部103を備えていてもよい。
図2は、図1のプログラム並列化システムによるプログラム並列化処理の例を概略的に示すフローチャートである。図2のフローチャートの実行に先立って、例えばプログラム並列化システムの外部から、並列化プログラムへの変換対象である逐次プログラム110と、当該逐次プログラム110に含まれるループをどのような処理単位に分割するのかを示すループ分割情報130とが入力される。
最初のステップS100で、プログラム解析部101は、それぞれ入力された逐次プログラム110およびループ分割情報130に基づき、当該逐次プログラム110を解析し、終了制御情報120、変更情報121およびデータ依存情報122を出力する。終了制御情報120は、プログラム中のどの処理がどのような形でループを終了させるのかを示す。変更情報121は、ループ終了後に利用されるデータを変更するのは、プログラム中のどの処理なのかを示す。また、データ依存情報122は、処理を分割した際に複数の処理で利用するデータの依存関係を示す。
次のステップS101で、プログラム並列化部102は、ステップS100でプログラム解析部101から出力された終了制御情報120および変更情報121と、それぞれ入力された逐次プログラム110およびループ分割情報130とに基づき、当該逐次プログラム110に対して並列化処理を行い、中間並列化プログラム131を出力する。
次のステップS102で、プログラム変換部103は、ステップS101で出力された中間並列化プログラム131と、ステップS100でプログラム解析部101から出力されたデータ依存情報122とに基づき、データの依存関係を保証した最終的な並列化プログラム140を作成し、出力する。
図3は、プログラム並列化部102の機能を示す一例の機能ブロック図である。プログラム並列化部102は、入力部201、ループ変換部202、ループ並列化部203および出力部204を備える。
図4は、プログラム並列化部102によるプログラム並列化処理を示す一例のフローチャートである。先ず、ステップS110で、入力部201は、逐次プログラム110、ループ分割情報130、終了制御情報120および変更情報121を入力する。次のステップS111で、ループ変換部202は、終了制御情報120に基づきループの終了制御がループの内部処理以外で実現されているか否かを判定する。その結果、ループ変換部202は、ループの内部処理以外で終了制御が実現されているループに限って、ステップS112で、ループの内部処理による終了制御が行われるように変換し、処理をステップS113に移行させる。終了制御がループの内部処理で行われていると判定した場合には、そのまま処理をステップS113に移行させる。
ステップS113で、ループ並列化部203は、ループ分割情報130に従い逐次プログラム110のループを各処理に分割し、分割された各処理を並列に実行できる形に変換する。例えば、マルチコアの各コアで実行することが可能となるスレッドやプロセスといった形に変換する。変換する形式はこれに限らず、並列化プログラム140を動作させる環境によって独自に用意されている並列化形式でもよい。さらに、ループ並列化部203は、ステップS110で入力部201に対して入力された各情報に基づき、ループが分割された各処理にループ終了時の処理を追加し、中間並列化プログラム131を生成する。そして、次のステップS114で、出力部204は、中間並列化プログラム131を出力する。
次に、本実施形態によるプログラム並列化処理について、典型的なソースコードを用いてより具体的に説明する。以下では、プログラム並列化システムが上述した図1の構成であり、プログラム並列化システム内のプログラム並列化部102が上述した図3の構成である場合を例にとって説明を行う。
なお、実施形態はこの例に限られず、例えば、図1および図3に例示する複数の機能ブロックが協調しながら動作を行う構成であってもよいし、一部の機能ブロックの順番を入れ替えた構成であってもよい。また、図1および図3に例示する構成のうち、ある機能ブロックを他の機能ブロックに分割することもできる。さらには、これら3つの形態を組み合わせた構成によりプログラム並列化システムを構成することも可能である。さらにまた、図1および図3に例示する複数の機能ブロックのうち1または複数を、複数のモジュールに分割してプログラム並列化システムを構成することもできる。
先ず、プログラム解析部101の機能について説明する。図1を参照し、プログラム解析部101は、既に述べたように、逐次プログラム110およびループ分割情報130に基づき逐次プログラム110を解析し、終了制御情報120、変更情報121およびデータ依存情報122を出力する。逐次プログラム110は、例えば、C言語やJava(登録商標)言語のようなプログラミング言語を用いて記述される。これに限らず、逐次プログラム110は、特定の処理装置に独自のプログラミング言語を用いて記述されていてもよい。逐次プログラム110は、1つのファイルに全てのソースコードが格納されて提供されてもよいし、ソースコードが分割されて複数のファイルに格納されて提供されてもよい。
図5は、逐次プログラム110の例を示す。この例では、プログラム並列化システムによってコードの一部が変更される部分のソースコードのみが図5に示されているが、プログラム解析部101には、アプリケーションを動作させるために必要なソースコード全てを入力してもよい。多くのソースコードを入力した場合、解析時間は長くなるが、その分データ依存関係などの解析精度は向上する。
なお、この図5および以下の同様のプログラム例を示す図において、特に記載のない限り、各行の先頭の2桁の数字は説明のための行番号を示し、続くコロン(:)でソースコード本体と区別されている。また、本実施形態の中で例示される各プログラムおよびコードは、プログラミング言語として一般的に用いられるC言語の記法を模した疑似コードである。
図5の例では、逐次プログラム110を記述するコード501において、6行目から12行目までが、for文によるループを構成している。また、ループ中、7行目でループ変数iによる関数処理がなされ、8行目で7行目の結果に基づく関数処理がなされる。さらに、9行目では、8行目の結果に基づく判定処理がなされ、判定結果に応じて10行目でループに対する終了制御処理がなされる。また、ループ外の13行目は、他の関数に返すための戻り値が示される。
図6は、プログラム解析部101に係る、逐次プログラム110以外の情報の例を示す。図6(a)は、ループ分割情報130の例を示す。図6(b)および図6(c)は、それぞれ終了制御情報120および変更情報121の例を示す。また、図6(d)は、データ依存情報122の例を示す。
図1では、ループ分割情報130は、ユーザがテキストエディタなどを用いて直接的に記述してプログラム並列化部102に対して入力するように示されているが、これはこの例に限定されない。例えば、プログラム解析部101により逐次プログラム110を解析して並列化に適したループを探索し、並列化が容易な分割方法を決定することでループ分割情報130を出力してもよい。また、プログラム変換部101においてループ分割情報130をユーザにGUI(Graphical User Interface)などを通じて提示し、確認および修正を行った情報を出力してもよい。なお、逐次プログラム110のソースコードから、ループ分割情報130を出力する方法は、既存の、コンパイラなどでプログラムの構文解析を行う技術を応用することで実現できる。
また、図1では、終了制御情報120、変更情報121およびデータ依存情報122は、プログラム解析部101が逐次プログラム110を解析して出力するようにしている。なお、逐次プログラム110のソースコードから、終了制御情報120、変更情報121およびデータ依存情報122を出力する方法は、既存の、コンパイラなどでプログラムの構文解析を行う技術を応用することで実現できる。
終了制御情報120、変更情報121およびデータ依存情報122を生成するには、例えばこれらの情報のうち1つまたは複数を、ユーザがテキストエディタなどを用いて直接的に記述してプログラム並列化部102に対して入力するようにしてもよい。また、プログラム変換部101において終了制御情報120、変更情報121およびデータ依存情報122をユーザにGUIなどを通じて提示し、確認および修正を行った情報を出力してもよい。
また、ループ分割情報130、終了制御情報120、変更情報121およびデータ依存情報122は、プログラム並列化部102およびプログラム変換部103が必要とする情報を含んでいれば、作成方法は問わない。例えば、並列化コンパイラなど、他の装置向けに作成されたプログラム解析部110で作成したものであっても、他の装置を本実施形態によるプログラム並列化部102向けに改造したものであってもよい。また、プログラム解析部101によって生成された終了制御情報120、変更情報121およびデータ依存情報122を、さらにユーザがテキストエディタなどを用いて修正してプログラム並列化部102に入力することも考えられる。また、ループ分割情報130、終了制御情報120、変更情報121およびデータ依存情報122はテキストデータではなく、バイナリデータや、プログラム並列化システムや他の装置向けに独自に定義された中間データ形式であってもよい。
さらに、ループ分割情報130、終了制御情報120、変更情報121およびデータ依存情報122は、それぞれ別個のファイルに格納されて提供されてもよいし、纏めて1つあるいは複数のファイルに格納されて提供されてもよい。ループ分割情報130、終了制御情報120、変更情報121およびデータ依存情報122を混在させてファイルに格納して提供することも考えられる。
ループ分割情報130について説明する。ループ分割情報130は、逐次プログラム110中の並列化の対象となるループの内部処理を、並列化に適した処理単位に分割するための情報を含む。図6(a)の例では、情報601の第1行目の記述「7:thread_1」が、逐次プログラム110のコード501における7行目を「thread_1」と呼ばれる処理に分割し、第2行目の記述「8:thread_2」が、当該コード501における8行目を「thread_2」と呼ばれる処理に分割し、第3行目の記述「9-11:thread_3」が、当該コード501の9行目から11行目を「thread_3」と呼ばれる処理に分割することを示す。
この例では単一のファイル内のプログラムを行数で指定しているが、指定方法はこれに限らない。複数ファイル内のプログラムを指定するために、プログラムのファイル名などを行数の前に記述してもよい。また、逐次プログラム110中に分割する部分を直接指定してもよいし、その指定した部分にラベルを付け、これをループ分割情報130にそのラベルで指定してもよい。このように、並列化するループの内部処理をどのように分割するかを指定できれば、ループ分割情報130における構文の文法は問わない。
なお、以下では、適宜、「thread_1」と呼ばれる処理を実行するスレッドをスレッドthread_1、「thread_2」と呼ばれる処理を実行するスレッドをスレッドthread_2、「thread_3」と呼ばれる処理を実行するスレッドをスレッドthread_3と称する。
終了制御情報120について説明する。終了制御情報120は、ループ分割情報130によって分割された各処理の中で、ループの終了制御を行う処理を指定する。図6(b)の例では、情報602の記述「End:thread_3」が、図6(a)に例示されるループ分割情報130において処理「thread_3」の中でループの終了制御が行われていることを示す。
また、ループの終了制御を行う構文がある1つの処理の中に複数存在する場合、例えば、処理「thread_3」の中に2つの終了制御が存在する際には「End:thread_3:2」のように記述することができる。この例では、ループ分割情報130によって設定された処理名を用いて終了制御処理を指定しているが、指定方法はこれに限らない。ループ分割情報130のように、プログラム中の行数で終了制御コードを指定し、プログラム並列化部102にてループ分割情報130の情報と組み合わせることでループの終了制御を行う処理を指定してもよい。また、逐次プログラム110中に終了制御コードを直接指定してもよいし、その指定した部分にラベルを付け、これを終了制御情報120にそのラベルと終了制御の数で指定してもよい。また、この例では終了制御情報120によって指定されたスレッドは1つであったが、複数あっても構わない。このように、終了制御を行う部分が幾つ存在し、それをどの処理が行うのかを指定できれば、終了制御情報120における構文の文法は問わない。
変更情報121について説明する。変更情報121は、ループ分割情報130によって分割された各処理の中で、ループ終了後に利用されるデータを変更している処理を指定する。図6(c)の例では、情報603の記述「Effect:thread_2」は、図6(a)に例示されるループ分割情報130において処理「thread_2」の中で、ループ終了後に利用されるデータを変更する処理が行われていることを示す。
この例では、ループ分割情報130によって設定された処理名を用いて変更処理を指定しているが、指定方法はこれに限らない。ループ分割情報130のように、プログラム中の行数でループ終了後に利用されるデータの変更コードを指定し、プログラム並列化部102にてループ分割情報130の情報と組み合わせることで、ループ終了後に利用されるデータを変更している処理を指定してもよい。また、逐次プログラム110中に変更処理コードを直接指定してもよいし、その指定した部分にラベルを付け、これを変更情報121にそのラベルで指定してもよい。このように、変更処理を行う部分をどの処理が行うのかを指定できれば、変更情報121における構文の文法は問わない。
なお、図6(c)の情報603の例では、ループ終了後に利用されるデータを変更する処理を指定していたが、データを変更する処理を指定する代わりに、ループ終了後に利用されるデータを変更しない処理を、例えば記述「Noeffect:thread_1」といったように指定してもよい。
データ依存情報122について説明する。データ依存情報122は、ループ分割情報130に基づきループを分割した際に分割された処理間で利用するデータの依存関係の情報を示す。図6(d)の例では、情報604の記述「thread_2:total->thread_3:total」は、ループ分割情報130において処理「thread_2」の中で変更される変数totalから、同じイタレーション回数の処理「thread_3」で利用されるデータtotalに対してデータの依存関係があることを示す。
なお、上述の例では、同じイタレーション回数のスレッドにデータ依存関係が存在したが、異なるイタレーション回数のスレッドに対してデータ依存関係を設定することもできる。例えば、イタレーション回数[i]のスレッドthread_2の変数totalが、次のイタレーション回数[i+1]のスレッドthread_3の変数totalとして使われる場合、データ依存情報122を、「thread_2[0]:total->thread_3[1]:total」などと記述することで実現できる。
この例では、逐次プログラム110内の変数名によってデータ依存情報を指定しているが、指定方法はこれに限らない。ループ分割情報130のように、プログラム中の行数でデータ依存コードを指定し、プログラム並列化部102にてループ分割情報130の情報と組み合わせることで、ループ終了後に利用されるデータを変更している処理を指定してもよい。また、逐次プログラム110中にデータ依存コードを直接指定してもよいし、その指定した部分にラベルを付け、これをデータ依存情報121にそのラベルで指定してもよい。このように、データ依存処理を行う部分をどの処理が行うのかを指定できれば、データ依存情報121における構文の文法は問わない。
次に、プログラム並列化部102の機能について、図1および図3の機能ブロック図と、図4のフローチャートとを参照しながら説明する。プログラム並列化部102は、既に述べたように、逐次プログラム110、ループ分割情報130、終了制御情報120および変更情報121に基づき逐次プログラム110を並列化し、中間並列化プログラム131を出力する。先ず、図4のステップS110において、逐次プログラム110、ループ分割情報130、終了制御情報120および変更情報121が入力部201に対して入力され、ループ変換部202に供給される。
並列化対象とされる逐次プログラム110は、実行前に反復回数の不明なループを含むものとする。ここで、ループとは、プログラムを何らかの方式でコンパイルし、動作させる計算機用の機械語を生成した際に、同じ処理が繰り返されている部分のことを指す。例えば、C言語やJava(登録商標)言語では、ループ処理は、for文やwhile文などを用いて記述できる。これに限らず、ループ処理は、再帰関数の呼び出しによっても記述できる。また、機械語でループ処理を直接的に記述することもできる。
このループによる繰り返し処理が一定回数ではなく、プログラムへの入力や実行環境などによって変化する場合、ループの反復回数を予め知ることができない。本プログラム並列化システムは、このような、プログラムの実行前にループの反復回数が不明なループを並列化するものである。このような条件を満たさないループを並列化対象とした場合、プログラム並列化部102は、ループを並列実行可能な形に分割する処理のみを行う。並列化するループは、逐次プログラム110の中で1つだけとは限らず、複数存在してもよい。また、並列化するループの内部に1つ以上のループが存在していてもよく、内部のループも並列化対象ループとしてもよい。その場合、上記の条件を満たすループと満たさないループが混在していてもよい。
なお、入力部201に対する逐次プログラム110や各情報の入力の方法として、例えば、一般的に行われている、ファイルシステムを用いる方法が考えられる。例えば、フレキシブルディスク、光ディスク、ハードディスクドライブ、装置に対して着脱可能な不揮発性半導体メモリなどの記憶媒体に逐次プログラム110や各情報を記憶させ、入力部201が、この記憶媒体からこれら逐次プログラム110や各情報を読み出す。
これに限らず、これら逐次プログラム110や各情報を、ネットワークなどを介して予めメモリに読み込ませ、このメモリから逐次プログラム110や各情報を入力部201に入力させてもよい。また、例えばプログラム並列化部102を実行させるためのソースコードやプロファイル情報に、これら逐次プログラム110や各情報を予め組み込んでおいてもよい。さらに、これら逐次プログラム110や各情報を、GUIなどを通じてユーザが直接的に入力部201に入力するようにもできる。さらにまた、プログラム解析部101とプログラム並列化部102とを1つのシステムとすることで、何らかの通信手段を用いてプログラム解析部101からプログラム並列化部102に対して直接的に情報を受け渡してもよい。
次に、図4のステップS111およびステップS112において、ループ変換部202は、入力部201に入力された逐次プログラム110とループ分割情報130とから、逐次プログラム110に含まれる、並列化対象となるループを並列化に適した形式に変換する。なお、逐次プログラム110のソースコードから、並列化対象となるループを検索する方法は、既存の、コンパイラなどでプログラムの構文解析を行う技術を応用することで実現できる。また、逐次プログラム110上に並列化対象となるループをユーザが指定したり、ループ分割情報130のような形で並列化対象ループを指定した情報をプログラム解析部101やプログラム並列化部102に入力してもよい。
図4のフローチャートのステップS111で既に説明したように、ループの変換は、ループの終了制御処理がループ内部の処理以外の形で実現されている場合に限り行われる。すなわち、ループの終了制御処理がループ内部で行われていない場合に、当該ループを、当該ループの終了制御処理を行うための条件文を内包し、この条件文による条件を満たした場合にループを終了する処理を含んだループに変換する。
より具体的な例を、図7および図8を用いて説明する。図7は、ループの条件文として終了制御を行う処理が記述された場合の例である。すなわち、図7(a)に例示されるコード701において、4行目から7行目が条件文whileによるループを構成する。条件文whileは、ループの先頭に置かれ処理がループ内部に移行するか否かの判断を行うもので、終了処理がループ内部の処理ではない。
このコード701の例では、ループの条件文を内部の処理としてループ内部に挿入し、ループ自体は無限ループすなわち反復回数を規定しないループに変換することで、ループ部分の並列化が可能且つ元の逐次プログラムと結果が等価な逐次プログラムへと変換する。図7(b)は、コード701に含まれるループを並列化可能なループに変換した例を示す。図7(b)のコード702において、ループをfor文を用いて無限ループとして構成すると共に、コード701におけるループの条件文whileを条件文ifに変換し、ループ内部に挿入している。この例では、for文を用いて無限ループを構成し、if文を用いて判定処理を行っているが、同様の処理を実現できれば、while文を用いても、アーキテクチャ特有の方法等を用いてもよい。
なお、ループの変換の要否は、例えば、プログラム解析部101によって静的に逐次プログラム110の解析を行い、解析結果に基づき確認する方法が考えられる。この場合、プログラム解析部101から出力される終了制御情報120に対して、終了制御を行う処理がループの条件文として記述されている、あるいは、例外処理を行うコードが含まれているという情報を持たせることで実現できる。コード701の場合、4行目の条件文whileが終了制御命令に該当するため、終了制御情報120は、図7(c)に情報703の記述「4:End:Loop」として例示されるように、終了制御命令が4行目にループの条件文として記述されていることを示すような構成とされる。この終了制御情報120を受けて、ループ変換部202がループの変換を行う。
この場合の終了制御情報120についても、上述の通り必要な情報の受け渡しができる形式ならば文法などは問わない。また、ユーザがソースコードを解析し、ループ変換の要否をプログラム解析部101やループ分割情報130などを通じて、プログラム解析部101あるいはプログラム並列化部102に対して、直接的または出力された情報を修正することにより入力してもよい。
図8は、並列化対象となるループの全体が含まれる例外処理が記述されている場合の例である。なお、C言語には例外処理用の構文が用意されていないため、図8のコード例はC++言語を模した疑似コードを用いている。
例外処理とは、プログラムの実行中に発生した例外に対して、特別な処理を行う機構をいう。すなわち、例外処理では、プログラムのある処理を実行中に何らかの異常が発生した場合に、その処理を中断して別の処理を行う。例えばC++言語やJava(登録商標)言語においては、例外処理構文におけるtry文により、例外が発生する可能性のあるコードを囲み、その内部でエラーが発生した場合は、throw文を用いて例外の発生を通知する。例外発生が通知された場合は、catch文の内部の処理を実行する。これにより、例外に対応した処理を行う。
図8(a)に例示されるコード801において、4行目にtry文が置かれ、try文の括弧の内部(5行目から8行目)に並列化対象のループが記述されている。また、このtry文の直後に、try文に対応するcatch文が記述されている。5行目〜8行目のループにおいて例外が発生した場合に、try文により例外がキャッチされて処理がループ外部のcatch文に移行するため、終了処理がループ内部の処理ではない。
このコード801の例のように、try文の括弧の内部に並列化対象のループが記述されている場合、ループ分割情報130に基づいて分割されたループ内部の各処理をそれぞれtry文の括弧で囲み、その後catch文が実行されるようにループを変換する。さらに、catch文に書かれていた処理の他に、catch文が発生したらループが終了するようにループを変換する。
図8(b)は、コード801に含まれるループを並列化可能なループに変換した例を示す。図8(b)のコード802において、ループ分割情報130に基づいて分割されるコード801におけるループ内部の各処理をそれぞれtry文の括弧で囲むと共に、各try文に対してそれぞれcatch文を記述する。コード802では、コード801の6行目の処理と7行目の処理をそれぞれループ分割情報130によって分割すると仮定している。より具体的には、コード802では、コード801におけるループ内部の6行目の処理に対してtry文および対応するcatch文が記述され(5行目〜11行目)、コード801におけるループ内部の7行目の処理に対してtry文および対応するcatch文が記述される(12行目〜18行目)。
この場合、終了制御情報120は、図8(c)の情報803の記述「End:exception」により、並列化対象となるループ全体が含まれるような例外処理が記述されていることを示すような構成とされる。この情報を受けて、ループ変換部202がループの変換を行う。この場合の終了制御情報120についても、上述の通り必要な情報の受け渡しができる形式ならば、文法などは問わない。また、ユーザがソースコードを解析し、ループ変換の要否をプログラム解析部101やループ分割情報130などを通じて、プログラム解析部101あるいはプログラム並列化部102に対して、直接的または出力された情報を修正することにより入力してもよい。
次に、図4のステップS113において、ループ並列化部203は、逐次プログラム110中の並列化対象となるループを、ループ分割情報130に基づき、各処理に分割する。さらに、ループ並列化部203は、分割された各処理を並列化可能な形式に変更する。本実施形態においてはスレッド形式に変更するが、上述の通り、プロセスなどの形式に変更してもよい。そして、終了制御情報120および変更情報121を用いて、ループ終了後に利用されるデータの値を保証するための処理を各スレッドに追加し、並列化を行う。
この例では、終了制御情報120は、図6(b)で示した情報602とし、スレッドthread_3が終了制御を含む。また、変更情報121は、図6(c)で示した情報603とし、スレッドthread_2がループ終了後に利用されるデータを変更することを示している。図5のコード501を参照すると、スレッドthread_2は、ループ終了後に利用されるデータtotalの値を変更し、スレッドthread_3は、コード「break」による終了制御が行われている。なお、終了制御の数や終了制御を持つスレッドの数は、1つに限定されない。
ループ並列化部203では、終了制御を持つスレッド、ループ終了後に利用されるデータの値を変更するスレッド、それ以外のスレッドの3種のスレッドに対し、それぞれ別の処理を追加する。この例では、ループ制御用の構造体を操作する処理をプログラム内に関数として追加し、この関数を呼び出す形で、ループ制御用の構造体の操作を実現しているが、これはこの例に限定されない。例えば、ループ制御用の構造体の操作処理をライブラリとして用意し、このライブラリから必要な処理を呼び出すようにしてもよい。また、FIFO(First In First Out)やアーキテクチャが用意している専用命令を利用したスレッド間通信を用いてスレッド間で直接構造体のデータをやり取りすることで、ループ制御用の構造体の操作処理を実現してもよい。
図9は、図4のステップS113の処理をより詳細に示す一例のフローチャートである。ループ並列化部203は、先ず、ステップS130で、ループ分割情報130に基づき逐次プログラム110のループ内部の各処理を分割し、スレッド化する。次のステップS131で、ループ制御用の関数、ループ制御用の構造体を各スレッドから実行可能な状態で追加する。さらに、ループ制御用の構造体の初期化処理を追加する。次に、ステップS132で、ステップS130で作成された各スレッドに、ループの反復回数をカウントするための変数を追加する。次のステップS133で、ステップS130で作成されたスレッドのうち、終了制御を持つスレッドに対する処理を行う。
さらに、次のステップS134で、ステップS130で作成されたスレッドのうち、保証する必要のあるデータ、すなわち、ループ終了後に利用されるデータを変更するスレッドに対する処理が行われる。最後に、ステップS135で、その他すなわちステップS133およびステップS134で処理された以外のスレッドに対する処理が行われる。以上のようにして、最終的に、中間並列化プログラム131が作成される。
ステップS130の処理について、より詳細に説明する。図6(a)の情報601に示したように、ループ分割情報130には、分割を行う処理が指定されている。ステップS130で、ループ並列化部203は、この指定に従いループ内部の各処理を分割する。さらに、分割された各処理をスレッド形式に変更する。すなわち、ループ並列化部203は、逐次プログラム110およびループ分割情報130に基づき、例えばC言語の関数に準じた形式で各スレッド内部の処理をそれぞれ独立に記述し、逐次プログラム110の分割を行う。
より具体的には、ループ並列化部203は、情報601として例示されるループ分割情報130に従い、図5に例示されるコード501のうち、7行目をスレッドthread_1、8行目をスレッドthread_2、9行目〜11行目をスレッドthread_3に分割し、コード501のループ部分をそれぞれ独立した3のスレッドthread_1、スレッドthread_2およびスレッドthread_3として記述する。
これらスレッドthread_1、thread_2およびthread_3のうち、スレッドthread_2は、ループ終了後に利用されるデータを変更するスレッドであり、スレッドthread_3は、条件によりループから外に飛び出るスレッドである。スレッドthread_1は、これら何れのタイプのスレッドにも該当しないスレッドである。なお、ループが分割されたスレッド数は、3に限られない。
また、ループの終了制御を持つスレッド、ループ終了後に利用されるデータを変更するスレッド、ならびに、これらのタイプに該当しないスレッドは、1つの入力プログラムに対し、それぞれ1つ以上存在する必要はなく、0であってもよい。各タイプに該当するスレッドが存在しない場合、それらのタイプ向けの処理は実行されない。さらに、ループの終了制御を持つスレッドが存在しない場合、プログラム並列化部102はループを並列実行可能な形式に変換する作業のみを行う。また、終了制御情報120で指定されている処理と変更情報121で指定されている処理は重複していてもよい。これにより、ループの終了制御を持つスレッドが複数存在している場合にも他の終了制御に対する制御処理を挿入することができる。
元のループ内には、各スレッドthread_1、thread_2およびthread_3を呼び出すためのコードと、最後にスレッドの終了を待ち合わせるためのコードとを挿入し、元の処理をこのコードに置き換える。図10と、上述した図5とを用いてより具体的に説明する。図10は、逐次プログラム110に基づきループ並列化部203で生成される、中間並列化プログラム131を構成するコード1001の例を示す。なお、図10において、コード1001は、このコード1001に関する処理が終了し本実施形態の説明に必要な部分が完成した形態で示されている。
ループ並列化部203は、図5のコード501のループ開始行の直前、ループ内部およびループ終了行直後のうち何れかの位置に、図10のコード1001における7行目〜12行目のコードを挿入する。このコード1001における7行目〜12行目のコードは、並列処理を行うことを示すものである。より具体的には、コード1001における7行目のコード「fork(thread_1)」は、スレッドthread_1を生成し、処理を別のコアまたはプロセッサなどにより処理させることを示す。また、コード1001における10行目のコード「join(thread_1)」は、スレッドthread_1の処理が終了するまで待機状態となることを示す。つまり、この例では、各スレッドthread_1、thread_2およびthread_3が複数のコアまたはプロセッサにより並列処理されることが示されている。
なお、逐次プログラム110におけるループのスレッド分割方法は、この方法に限定されない。ループのスレッドへの分割および並列化の方法は、変換された並列化プログラムを動作させるアーキテクチャや、システム、並列処理をどのように実現するかによって異なる。
例えば、C言語の関数に似た形式でスレッド内部の処理を独立に記述し、分割させる方法を用いることができる。C++言語やJava(登録商標)言語のクラスのような形式でスレッド内部の処理を独立に記述し、分割させる方法を用いることもできる。また、分割させる処理をそれぞれ括弧「{}」で囲むことで分割する方法を用いることもできる。さらに、並列処理専用の特別な構文を持つアーキテクチャやプログラム言語を利用する場合、そうした構文を挿入することで分割や並列化を行う方法も考えられる。
さらに、本実施形態のように各スレッドを1回ずつ呼び出す形式ではなく、スレッドの呼び出し部分をループで囲み、複数回スレッドを呼び出すようなコードを記述し、スレッド本体にはループ部分を記述しないという方法も考えられる。さらにまた、アーキテクチャやプログラミング言語にスレッド呼び出し方法が規定されている場合、それに沿ったものにする必要がある。
本実施形態では、ループ内部の処理を単純に分割してスレッド化を行っている。これに限らず、ループのイタレーション回数に応じて分割を行うこともできる。例えば、ループを、ループのイタレーション回数が50回目までと、それ以降とに分割する。この場合、プログラム解析部101では、分割された処理を別々の処理と見做して依存関係などの解析を行う。また、ループ内部の処理を分割する方法と、ループのイタレーション回数に応じて分割する方法とを組み合わせた分割方法も考えられる。
次に、図9のステップS131による、ループ制御用の関数、データ構造および初期化処理を追加する処理について、より詳細に説明する。先ず、図11を用いて、ループ制御に用いるデータ構造および関数の例について説明する。この図11に例示されるコード1101と、上述の図10に例示されるコード1001とから、中間並列化プログラム131が構成される。なお、図11において、コード1101は、このコード1101に関する処理が終了し本実施形態の説明に必要な部分が完成した形態で示されている。
図11のコード1101において、1行目から4行目は、ループが終了したか否かをチェックするためのデータcancel_stateのデータ構造体を定義するためのコードである。2行目のコード「char canceled」は、ループを終了したか否かを示す変数canceledを定義するためのコードである。変数canceledは、「1」でループが終了したことを示し、「0」でループの実行が継続されていることを示す。3行目のコード「unsigned long count」は、ループの終了制御を含む最内周のループのカウント回数を示す変数countを定義するためのコードである。すなわち、このように構造が定義されたデータcancel_stateを用いることで、ループが何回目で終了したかを知ることができ、複数のコアでそれぞれループの終了制御によってループが終了した際のループの進み方を判定できる。
コード1101において、6行目のコード「struct cancel_state cansel[NUM_CONT_STAT]」は、上述のデータ構造「cancel_state」の実体を用意するためのコードである。値「NUM_CONT_STAT」は、並列化対象ループ中に存在する終了制御処理の数を示しており、終了制御処理の数の分だけデータ構造「cancel_state」が用意される。
コード1101において、8行目から13行目のコードは、変数canceledおよび変数countを初期化する関数である。コード1101の15行目から20行目のコードは、ループの終了制御処理を持つスレッドに置かれる関数であって、ループが終了しているか否かを示す値「canceled」と、各終了制御処理固有のIDを示す変数「cancel_ID」とが引数とされる。16行目は、変数canceledを更新するためのコードである。また、17行目のif文により、ループが終了していない場合に18行目で変数countを1だけインクリメントする。
コード1101において、22行目から34行目のコードは、ループ終了後に利用されるデータを変更するスレッド(この例ではスレッドthread_2)のループ回数が、ループの終了制御を持つスレッド(この例ではスレッドthread_3)のループ回数を超えていないかどうかをチェックする関数である。また、この関数は、ループ終了後に利用されるデータを変更しないスレッド(この例ではスレッドthread_1)のループ回数が、ループの終了制御を持つスレッドのループ回数を超えていないか否かをチェックする関数でもある。
22行目の変数countは、スレッドの現在のループ回数を示す引数である。同行の変数effectは、そのスレッドがループ終了後に利用されるデータ、すなわち、ループの外側で保証しなければいけないデータを変更するスレッドか否かを示す引数である。変数effectが値「1」で変更するスレッド、値「0」で変更しないスレッドをそれぞれ示す。同行の変数cancel_IDは、各終了制御処理固有のIDを示す引数である。
コード1101において、23行目のif文および24行目から26行目のwhile文は、ループ終了後に利用されるデータを変更するスレッドにおいて、処理したループの回数が、ループの終了制御を持つスレッドのループ回数と等しくなるまで待機することを示す。
上述した図9のステップS132において、ループ回数を保存するための変数を更新するための構文は、ループの終了制御が行われるか否かが決定された後の部分に挿入される。このため、逐次プログラム110上でループ終了後に利用されるデータを変更するスレッドが終了制御処理を持つスレッドに先行する場合、コード1101の24行目から26行目までのwhile文により、終了制御を持つスレッドのループ反復回数がn回目とすると、ループ終了後に利用されるデータを変更するスレッドも、ループ反復回数n回目の処理までの実行が許可される。そうでない場合には(n−1)回目の処理までの実行が許可される。
27行目のif文は、ループが終了したか否かを実際にチェックする。30行目のif文は、保証しなければならないデータを変更しないスレッドに対してループが終了したか否かをチェックする。このスレッドの場合、終了制御を持つスレッドとの依存関係は存在しないため、待機処理が必要ない。これにより、逐次プログラム110上でループ終了後に利用されるデータを変更しないスレッドが終了制御処理を持つスレッドに先行する場合、コード1101の30行目のif文により、終了制御を持つスレッドのループ反復回数がn回目とすると、ループ終了後に利用されるデータを変更するスレッドもループ反復回数n回目の処理までの実行が保障される。そうでない場合には(n−1)回目の処理までの実行が保障される。何れの場合も、ループが終了した場合には、値「1」が返される。
次に、逐次プログラム110にループ制御用関数とデータ構造を追加する方法について説明する。先ず、図11のコード1101を、図9のステップS130によって作成された各スレッドから実行可能な箇所に挿入する。上述の通り、ループ制御用の処理やデータ構造を、図11のコード1101のように関数やデータ構造として用意していない場合は、用意されている処理とデータ構造とを図9のステップS130によって作成された各スレッドから利用可能な形態にする。また、図11のコード1101における6行目および9行目の値「NUM_CONT_STAT」は、並列化対象ループ中に存在する終了制御処理の数を示しており、終了制御情報120からこれを求め、実数を代入する。
さらに、ループ並列化部203は、ループ制御用のデータ構造のデータを初期化する処理を、図5のコード501のループ部分に挿入する。より具体的には、コード1001に対し、図10のコード1001における6行目に例示されるように、コード「reset_cancel_state()」が挿入される。挿入する場所は、ステップS130にて挿入された並列処理用のコード(コード1001における7行目〜12行目のコード)より前であればよい。
なお、この例では、終了制御を持つスレッドがスレッドthread_3の1つだけなので、ループ制御用のデータ構造も1つ宣言すればよい。一方、終了制御を持つスレッドが2つ以上存在する場合は、終了制御毎に割り当てられる固有IDを使って終了制御毎に処理を行えるようにすることで、終了制御の数が増えても対応できる。また、配列形式ではなく、ループ制御用の変数自体を複数宣言するようにしたり、リスト構造などのデータ構造などを用いて情報を保持してもよい。
次に、図9のステップS132による、ループの反復回数を保存するための変数を図9のステップS130によって作成された各スレッドに追加する処理を行う。より具体的には、図10のコード1001に対して、コード1001における17行目および28行目に示されるように、並列化対象となるループに対し、新たにループの反復回数をカウントする変数countを各スレッドに挿入する。変数countが挿入される位置は、ループよりも前であればよい。さらに、このカウンタをインクリメントする処理をコード1001の23行目および34行目に挿入する。このカウンタインクリメント処理を挿入する位置は、あるイタレーションにおいて、ループの終了制御処理が実行されないことが確定する部分以降であり、且つ次のイタレーションの実行前の部分であればよい。また、終了制御を持つスレッドのループ反復回数は、前述のデータ構造により保持されるため、終了制御を持つスレッドが1つしか存在しない場合は、終了制御を持つスレッドに対して変数countは挿入されない。
ループの反復回数をカウントする変数countを用意することで、元のコード上で宣言されていたループカウンタがループ中で更新されるなどによりカウンタの数がループの反復回数と一致しないループや、元々ループカウンタが宣言されていないループ、ネストしたループなどにおいても、図11のコード1101を用いて並列化を行うことができる。
また、並列化対象ループの持つループカウンタが単純にループの反復回数をカウントしている場合、上述の変数countを挿入せず、このループカウンタを利用してもよい。さらに、終了制御処理を持つスレッドが1つしかない場合、このスレッドでは変数countは必要ないため、図9のステップS132による処理はこのスレッドに対しては実行されない。図5のコード501の場合、終了制御処理が1つしかないため、終了制御処理を持つスレッドに対しては変数countを追加しない。
図12は、図9のステップS133の終了処理を持つスレッドに対する処理をより詳細に示す一例のフローチャートである。先ず、ループ並列化部203は、ステップS140で、上述のステップS130で逐次プログラム110のループを分割して生成されたスレッドから、終了制御を持つスレッドを1つ選択する。終了制御を持つスレッドは、終了制御情報120から知ることができ、この例では、図6(b)の情報602に従い、スレッドthread_3が終了制御を持つスレッドとして選択される。
次のステップS141で、ループ並列化部203は、各終了制御に固有のIDを与える。このIDは、後述する終了制御の種類に関係なく、終了制御全体で固有のIDが与えられる。また、終了制御がある1つの処理に複数存在する場合もそれぞれ固有のIDが与えられる。上述の通り、終了制御が幾つ存在するのかという情報も、終了制御情報120から知ることができる。さらに、この例では、IDは、「0」から順に付与されていくと仮定している。IDの付与方法はこの例に限らず、終了制御固有のIDであればどんな値を付与してもよい。ただし、この例の場合のように、IDをデータ構造にアクセスするための引数として直接用いている場合は、配列外のデータにアクセスするなどにより、プログラムが動作不良を起こすことがないようにIDを付与していく必要がある。この例では、終了制御は1つなので、その1つに対してID「0」を割り付けている。
次のステップS142で、ループ並列化部203は、逐次プログラム110を実行した結果と、最終的な並列化プログラム140を実行した結果とを一致させるための処理を実行する。このステップS142の処理は、ループの終了制御処理の特性によって異なる。終了制御処理が「break」のような最内周のループのみを終了させる処理であれば、並列化対象となるループが複数のループによってネスト(入れ子構造)した構造になっている場合に処理が必要となる。この場合、全スレッドの最内週ループが終了制御処理によって終了するまで、各スレッドは次の処理に移らず、待機状態となるようなコードを挿入する。
全スレッドのループが終了したら、何れか1つのスレッドに、ループ制御用の構造体をリセットするコード「reset_cancel_state()」を実行し、その後他のスレッドの処理を再開するようにコードを挿入する。これによってループ制御用の構造体をリセットした後、各スレッドの処理を再開することができる。また、図5のコード501の例のように、特に処理を行う必要がない場合は、このステップS142による処理は省略される。
次のステップS143で、ループ並列化部203は、ループ制御用のデータ構造の内容を更新する処理を、ステップS140で選択されたスレッドのコードに挿入する。より具体的には、コード1001に対し、41行目のコード「update_cancel_state(1,0)」が挿入される。挿入する場所は、ループの終了制御処理を行うか否かを判定する条件文の内部かつ終了制御処理の後以外の部分であればよい。さらに、同コード1001における44行目に例示されるように、コード「update_cancel_state(0,0)」が挿入される。挿入する場所は、あるイタレーションにおいて、ループの終了制御処理が実行されないことが確定する部分以降であり、且つ次のイタレーションの実行前の部分であればよい。
処理はステップS144に移行され、ループ並列化部203は、終了制御を持ち、選択されていないスレッドが未だ存在するか否かが判定される。若し、終了制御を持ち選択されていないスレッドが存在すると判定されたら、処理はステップS140に戻され、次の終了制御を持つスレッドが1つ選択される。一方、終了制御を持つスレッドが全て選択され上述のステップS141〜ステップS143の処理が終了していると判定されたら、この図12のフローチャートによる一連の処理が終了される。この例の場合、図9のステップS130で分割された3つのスレッドの内、スレッドthread_3のみが終了制御を持つため、ステップS140〜ステップS144まで一連の処理が1度ずつ実行されて、図12のフローチャートによる処理が終了される。
次に、図9のステップS134による、保証する必要のあるデータを変更するスレッドに対する処理について、より詳細に説明する。図13は、図9のステップS134の処理をより詳細に示す一例のフローチャートである。
先ず、ループ並列化部203は、ステップS150で、上述のステップS130で逐次プログラム110のループを分割して生成されたスレッドから、保証する必要のあるデータ、すなわち、ループ終了後に利用されるデータの値を変更するスレッドの中で、ステップS151〜ステップS153の処理を行っていないものが存在するか否かを判定する。若し、そうしたスレッドが存在すると判定されたら、処理はステップS151に移行され、ループ終了後に利用されるデータの値を変更するスレッドを1つ、選択する。
保証する必要のあるデータを変更するスレッド、すなわち、ループ終了後に利用されるデータの値を変更するスレッドは、変更情報120から知ることができる。この例では、終了制御処理を持つスレッドが1つしか存在しないため、図6(c)の情報603に従い、スレッドthread_2が当該スレッドとして選択される。また、図5のコード501のように、終了制御処理を持つスレッドが1つしか存在しない場合は、仮にこの終了制御処理を持つスレッドがループ終了後に利用されるデータの値を変更していたとしても、このスレッドに対してステップS151〜ステップS153の処理は行わないという最適化も可能である。
次のステップS152で、ループ並列化部203は、ループ終了制御処理を、ステップS151で選択されたスレッドのコードに挿入する。より具体的には、コード1001に対して、図10の32行目に示されるように、ループの終了制御であるコード「break」を挿入する。
コード「break」が挿入される位置は、元のループ内部の処理において、スレッド内部の処理と終了制御処理の位置関係を保持した形であればどこでもよい。つまり、元のループ内部の処理において、スレッド内部の処理よりも終了制御処理の方が前に存在している場合、スレッド内部の処理の前に終了制御処理を挿入する。逆に、スレッド内部の処理よりも終了制御処理の方が後ろに存在している場合、スレッド内部の処理の後ろに終了制御処理を挿入する。
また、ここで挿入されるループの終了制御は、図12の各ステップにおいて処理されたスレッドの持つ終了制御と同一のものである。この例の場合、コード「break」が使われているため、これを挿入することになる。ただし、図12の処理ステップS144を実行した際に、ループの終了制御処理が変更されている場合は、変更された処理が挿入される。また、終了制御が複数存在する場合、この挿入処理は終了制御の個数分行われる。終了制御が複数存在する場合の各終了制御の挿入位置は、逐次プログラム110上での各終了制御処理の位置関係を保持した状態で挿入される。
次のステップS153で、ループ並列化部203は、ループ制御用のデータ構造を確認する処理をステップS150で選択されたスレッドのコードに挿入する。より具体的には、コード1001に対して、図10のコード1001における31行目および33行目に示されるように、コード「if(check_cancel_state(count,1,0)==1){」および「}」を挿入する。このコードを挿入する位置は、ステップS152で挿入されたループ終了制御処理の直前および直後とし、終了制御を囲むブロックを構成すればよい。このコード「if(check_cancel_state(count,1,0)==1){」および「}」による処理が挿入されることで、スレッドthread_2の処理が、スレッドthread_3のループ処理が終了されたか継続されたかを確認し、終了した場合はスレッドthread_2でもループ処理を終了し、継続された場合はスレッドthread_2においてもループ処理を継続するものとなる。ステップS153での処理が終了すると、処理がステップS150に戻される。
上述のステップS150で、ループ終了後に利用されるデータの値を変更するスレッドの中でステップS151からステップS153の処理を行っていないものが存在しないと判定されたら、この図13のフローチャートによる一連の処理が終了される。この例の場合、スレッドthread_2のみが対象となるため、ステップS150〜ステップS153の処理が1度ずつ実行されて、図13のフローチャートによる処理が終了される。
次に、図9のステップS135による、その他、すなわち、終了制御を持たず、ループ終了後に利用される値の変更も行わないスレッドに対する処理について、より詳細に説明する。図14は、図9のステップS135の処理をより詳細に示す一例のフローチャートである。
先ず、ループ並列化部203は、ステップS160で、終了制御情報120から、終了制御処理を持つスレッドが複数存在するか否かを判定する。若し、終了制御処理を持つスレッドが複数存在すると判定されたら、処理はステップS161に移行される。
ステップS161で、ループ並列化部203は、上述のステップS130で逐次プログラム110のループを分割して生成されたスレッドのうち、ループ終了後に利用されるデータ、すなわち、保証する必要のあるデータを変更するスレッドの中で、選択されていないスレッド、すなわち、後述するステップS163からステップS165の処理を行っていないスレッドが存在するか否かを判定する。若し、選択されていないスレッドが存在しないと判定されたら、図14のフローチャートによる一連の処理が終了される。一方、選択されていないスレッドが存在すると判定されたら、処理はステップS163に移行され、ループ終了後に利用されるデータの値を変更するスレッドを1つ選択する。
また、上述のステップS160で、終了制御処理を持つスレッドが1つしか存在しないと判定されたら、処理はステップS162に移行される。この例の場合、終了制御処理を持つスレッドは1つなので、ステップS162に処理が移ることになる。
ステップS162で、ループ並列化部203は、上述のステップS130で逐次プログラム110のループが分割されて生成されたスレッドから、上述のステップS133およびステップS134で選択されていないスレッドが存在するか否かを判定する。若し、全てのスレッドが選択されたと判定されたら、図14のフローチャートによる一連の処理が終了される。一方、未だ選択されていないスレッドが存在すると判定されたら、処理はステップS163に移行され、未だ選択されていないスレッドが1つ選択される。この例では、スレッドthread_1がこれまでの処理で1度も選択されていないので、このスレッドthread_1が選択されることになる。
ステップS163で、ループ並列化部203は、上述したように、ステップS161またはステップS162で選択対象とされたスレッドを1つ選択する。この例では、スレッドthread_1がこれまでの処理で1度も選択されていないので、このスレッドthread_1が選択されることになる。
次のステップS164で、ループ並列化部203は、ループ終了制御処理を、プログラムおよびステップS163で選択されたスレッドのコードに挿入する。より具体的には、コード1001に対して、図10の21行目に示されるように、ループの終了制御であるコード「break」を挿入する。
コード「break」を挿入する位置は、元のループ内部の処理において、スレッド内部の処理と終了制御処理の位置関係を保持した形であればどこでもよい。つまり、元のループ内部の処理において、スレッド内部の処理よりも終了制御処理の方が前に存在している場合、スレッド内部の処理の前に終了制御処理を挿入する。逆に、スレッド内部の処理よりも終了制御処理の方が後ろに存在している場合、スレッド内部の処理の後ろに終了制御処理を挿入する。ここで挿入されるループの終了制御は図12の各ステップにおいて処理されたスレッドの持つ終了制御と同一のものである。この例の場合、コード「break」が使われているため、これを挿入することになる。また、終了制御が複数存在する場合、この挿入処理は終了制御の個数分行われる。終了制御が複数存在する場合の各終了制御の挿入位置は、逐次プログラム110上での各終了制御処理の位置関係を保持した状態で挿入される。
次のステップS165で、ループ並列化部203は、ループ制御用のデータ構造を確認する処理を、ステップS163で選択されたスレッドのコードに挿入する。より具体的にはコード1001に対して、図10のコード1001における20行目と22行目に示されるように、コード「if(check_cancel_state(count,0,0)==1){」および「}」を挿入する。
コード「if(check_cancel_state(count,0,0)==1){」および「}」が挿入される位置は、ステップS164で挿入されたループ終了制御処理の直前および直後とし、終了制御を囲むブロックを構成する位置に挿入すればよい。このコード「if(check_cancel_state(count,0,0)==1){」および「}」による処理が挿入されることで、スレッドthread_1の処理が、スレッドthread_3のループ処理が終了されたか、継続されたかを確認し、終了した場合はスレッドthread_1でもスレッドthread_3でループ処理が終了した反復回数分でループ処理を終了し、継続された場合はスレッドthread_1においてもループ処理を継続する。ステップS165での処理が終了すると、処理がステップS160に戻される。
この例の場合、終了制御処理を持つスレッドが1つであり、スレッドthread_3のみが、上述のステップS133およびステップS134で選択されていないスレッドなので、ステップS160、ステップS162〜ステップS165の処理が1度ずつ実行されて、図14のフローチャートによる処理が終了される。それに伴い、図9のフローチャートによる一連の処理が終了され、ループ並列化部203による処理が終了し、中間並列化プログラム131の生成が完了する。この中間並列化プログラム131は、例えば上述のコード1101とコード1001とを含む。
なお、この例では、ループの終了制御にコード「break」が用いられているが、終了制御はこれに限定されるものではない。第1の例として、コード「return」のように、ループ自体を終了させると共に、そのループの所属する関数を終了させる終了制御を用いることができる。図15(a)は、このようなコード「return」を終了制御として用いた逐次プログラム110の例を示す。この図15(a)に例示されるコード1501は、上述した図5のコード501と対応するものである。コード1501の10行目に、ループの終了制御としてのコード「return」が記述されている。9行目のif文が成立し、10行目のコード「return」が実行されると、戻り値として「0」が返され、メインの関数「foo()」が終了される。
図15(b)は、図15(a)のコード1501に対して、上述した図12、図13および図14のフローチャートによる処理を施した結果得られる、中間並列化プログラム131を構成するためのコード1502の例を示す。
この図15(b)のコード1502では、先ず、図12のステップS142にて、元のコード1501の終了制御コード「return」が、各スレッドにおいてそれぞれ終了制御コード「goto」に変更され、この制御コードの分岐先を意味するラベル「loop_end」をスレッド中の並列化対象ループの終了直後に挿入する。この終了制御コードが変更されたコード1501に対し、さらに、コード1502における13行目〜15行目に示されるコードが挿入され、各スレッドthread_1、thread_2およびthread_3が上述の操作により挿入された終了制御コード「goto」によってループが終了したか否かをチェックし、終了した場合に、コード「return」が実行されるようにする。
また、この例では、並列化対象となるループが複数のループによってネストしておらず、単一のループとなっているが、これはこの例に限られず、対象ループが複数のループによってネストした構造になっていてもよい。この例の終了制御処理「return」のように、ループ自体を終了させると共に、そのループの所属する関数を終了させる終了制御を用いる場合、ラベル「loop_end」をネストした最外周のループの終了直後に挿入することで、元の逐次プログラムと結果が異なることを回避している。
また、「break」と同様に、コード「return」が複数存在してもよい。その場合、コード「return」は、それぞれ持っている戻り値が異なる可能性がある。そのため、図12のステップS141にて割り付けられる各終了制御に固有のIDを用い、コード1502における13行目〜15行目に示されるコードに加え、IDによる判定を追加することで、元の逐次プログラムと結果が異なることを回避できる。
第2の例として、コード「goto」を利用したループ外の任意の場所の処理に飛ぶ終了制御を用いることができる。図16(a)は、コード「goto」を終了制御として用いた逐次プログラム110の例を示す。この図16(a)に例示されるコード1601は、上述した図5のコード501と対応するものである。コード1601の10行目に、ループの終了制御としてのコード「goto」が記述されると共に、当該コード「goto」の飛び先として14行目にコード「label_1」が記述される。9行目のif文が成立し、10行目のコード「goto」が実行されると、処理が14行目に飛び、戻り値として「0」が返される。
図16(b)は、図16(a)のコード1601に対して、上述した図12、図13および図14のフローチャートによる処理を施した結果得られる、中間並列化プログラム131を構成するためのコード1602の例を示す。
この図16(b)のコード1602では、先ず、図12のステップS142にて、元のコード1601の終了制御コード「goto」の分岐先ラベルを各スレッドにおいてそれぞれ変更し、この制御コードの分岐先を意味するラベル「loop_end」をスレッド中の並列化対象ループの終了直後に挿入する。この終了制御コードが変更されたコード1601に対して、さらに、コード1602の13行目に示されるコードが挿入され、各スレッドthread_1、thread_2およびthread_3が上述の操作により変更された終了制御コード「goto」によってループが終了したか否かをチェックし、終了した場合に、コード「goto」が実行され、処理が15行目のコード「label_1」に飛ぶようにする。
また、この例では、並列化対象となるループが複数のループによってネストしておらず、単一のループとなっているが、これはこの例に限られず、対象ループが複数のループによってネストした構造になっていてもよい。この例の終了制御コード「goto」のように、ループ外の任意の場所の処理に飛ぶ終了制御を用いる場合、ラベル「loop_end」をネストした最外周のループの終了直後に挿入することで、元の逐次プログラムと結果が異なることを回避している。
また、上述のコード「break」と同様に、終了制御コード「goto」が複数存在してもよい。その場合、コード「goto」はそれぞれ持っている飛び先のラベルが異なる可能性があるため、図12のステップS141にて割り付けられる各終了制御に固有のIDを用い、コード1502における13行目に示されるコードに加え、IDによる判定を追加する。これにより、元の逐次プログラムと結果が異なることを回避できる。
第3の例として、コード「continue」のように、あるイタレーションの一部分の処理だけを飛ばして、次のイタレーションの処理へ移行する終了制御を用いることができる。図17は、コード「continue」を終了制御として用いた逐次プログラム110の例を示す。この図17に例示されるコード1701は、上述した図5のコード501と対応するものである。ただし、コード501とは異なり、終了制御処理がループの最初に行われている。これは、コード「continue」がループの最後にある場合、仮にこのコード「continue」が無くとも処理の結果に変化がなくなってしまうためである。
コード「continue」に対する処理においては、他の終了制御処理とは異なり、スレッドthread_1のような、終了制御を含まず、且つ、ループ終了後に利用される値の変更も行わないスレッドに対しては、コードの挿入は行われない。つまり、図14のフローチャートによる処理が実行されない。これは、コード「continue」が1回のイタレーションの処理のみを飛ばすものであるため、コード「continue」が複数回実行された際にその全てを補足し、処理を飛ばすことよりも、それらを無視して実行してしまった方がオーバーヘッドが小さくなる可能性が高いためである。図12のフローチャートにおけるステップS143にて、図14のフローチャートの処理を実行する処理をその対象から外すことで、上述の処理を実現できる。
コード1701において、8行目に、ループの終了制御としてのコード「continue」が記述されている。7行目のif文が成立し、8行目のコード「continue」が実行されると、ループ内のコード「continue」以降の処理は実行されず、次のイタレーションの処理が実行される。
図18は、図17のコード1701に対して、上述した図12および図13のフローチャートによる処理を施した結果得られる、中間並列化プログラム131を構成するためのコード1801の例を示す。
また、この例では、並列化対象となるループが複数のループによってネストしておらず、単一のループとなっているが、これはこの例に限られず、対象ループが複数のループによってネストした構造になっていてもよい。また、コード「break」、「return」、「goto」および「continue」のような各終了制御処理は、並列化対象ループの内部に1種類のみが存在しているとは限らず、複数の種類の終了制御処理が存在していてもよい。
以上のように、ループ並列化部203は、図11のコード1101で定義されるデータ構造cancel_state、関数reset_cancel_state()、関数update_cancel_state()および関数check_cancel_state()を用いて、逐次プログラム110に対する並列化処理を行ない、中間並列化プログラム131を生成する。なお、この段階で生成される中間並列化プログラム131は、スレッド間のデータ依存関係を保証するためのコードが挿入されていないため、スレッド間にデータ依存関係がある場合は正常に動作しない。この中間並列化プログラム131に対して、後述するプログラム変換部103でデータ依存関係を保証するための変換を施すことで、スレッド間にデータ依存関係がある場合でも正常に動作する並列化プログラム140が得られる。スレッド間にデータの依存関係が無い場合、プログラム変換部103は、中間並列化プログラム131をそのまま並列化プログラム140として出力する。
ループ並列化部203で上述のようにして生成された中間並列化プログラム131は、出力部204から出力される。出力部204から出力される中間並列化プログラム131は、例えば、C言語やJava(登録商標)言語といったプログラミング言語に従い記述される。これに限らず、C言語やJava(登録商標)言語といったプログラム言語を、並列化用の構文を加えて拡張したプログラミング言語で記述してもよい。これに限らず、特定の処理装置に独自のプログラミング言語を用いて記述されていてもよい。さらに、プログラミング言語でなくとも、プログラム並列化部102とプログラム変換部103で中間並列化プログラム131に相当する情報を受け渡すことが可能ならば、プログラム並列化システム向けの中間言語や機械語などを、出力部204から出力してもよい。この中間並列化プログラム131のソースコードは、例えばテキストデータとして出力部204から出力される。ソースコードは、バイナリデータであってもよい。
中間並列化プログラム131のソードコードは、1つのファイルに全ての情報を纏めて格納してもよいし、複数のファイルに情報を分割して格納してもよい。また、入力部201に入力される逐次プログラム110のソースコードと、出力部204から出力される中間並列化プログラム131のソースコードは、同一の形式で記述されていてもよいし、異なる形式で記述されていてもよい。出力部204による中間並列化プログラム131の出力は、例えば、一般的に用いられるファイルシステムを利用して行うことができる。これに限らず、中間並列化プログラム131のソースコードを、ネットワークを介して他の端末などに出力することもできる。さらに例えば、GUIを利用してインタラクティブに出力させることも考えられる。
次に、プログラム変換部103の一例の機能について説明する。プログラム並列化部102から出力された中間並列化プログラム131は、プログラム変換部103に入力される。また、上述したように、プログラム変換部103に対して、プログラム解析部101から出力されたデータ依存情報122が入力される。プログラム変換部103は、これら中間並列化プログラム131とデータ依存情報122とに基づき、中間並列化プログラム131をデータの依存関係を保証した並列化プログラム140に変換して出力する。
以下では、図10に例示したコード1001のプログラムを、図6(d)に情報604として示したデータ依存情報122を用いて変換するものとして説明する。コード1001をデータ依存情報122を反映して変換した、並列化プログラム140を構成するためのコード1901の例を、図19に示す。なお、図19において、コード1901は、このコード1901に関する処理が終了し本実施形態に必要な部分が完成した形態で示されている。また、並列化プログラム140には、コード1901だけでなく、図11に示されるコード1101も必要となる。
まず、図6(d)の情報604における1行目の情報「thread_1:temp[i]->thread_2:temp[i]」により、スレッドthread_1の変数temp[i]から、同じイタレーション回数[i]のスレッドthread_2の変数temp[i]に対してデータ依存関係があることが分かる。これを解決するため、コード1901に対して、図19におけるコード1901の20行目のコード「PUT(thread_2[i],temp[i]);」と、31行目のコード「GET(thread_1[i],temp[i]);」とが挿入される。
ここで、20行目のコード「PUT(thread_2[i],temp[i]);」は、括弧「()」内の変数をメモリに一時的に保持するためのコードであり、31行目のコード「GET(thread_1[i],temp[i]);」は、括弧「()」内の変数をメモリから取得するためのコードである。すなわち、20行目のコード「PUT(thread_2[i],temp[i]);」を用いて、スレッドthread_1から同じイタレーション回数のスレッドthread_2に対して変数temp[i]のデータを渡し、31行目のコードを用いて、スレッドthread_2が同じイタレーション回数のスレッドthread_1から、変数temp[i]のデータを受け取ることができる。
この例では、FIFO(First In First Out)を用いたデータの受け渡しを仮定している。具体的には、コードPUTによってメモリ上のFIFOの内部にデータを格納し、コードGETによってFIFO内部のデータを取り出す形を想定している。FIFOにおけるデータの数を増やせば、命令PUTを実行するスレッドが命令GETを行うスレッドより高速に動作する場合でも、FIFOにデータを置ける間は、先に処理を実行することができる。FIFOが一杯になっている場合は、FIFOに空きがでるまでコードPUTを実行するスレッドは待機状態となる。コードGETを実行するスレッドは、FIFOが空の場合は待機状態となる。これによって、データの依存関係を壊さずに処理を並列に実行することができる。
次に、図6(d)の情報604の2行目の情報により、スレッドthread_2の変数totalから、スレッドthread_3の変数totalに対してデータ依存関係があることが分かる。これを解決するため、コード1901に対して、さらに、図19におけるコード1901の33行目のコード「PUT(thread_3[i],total)」と、43行目のコード「GET(thread_2,[i],total)」とが挿入される。このように、データ依存情報122に記述される全ての情報を確認し、処理を行ったら、図19に例示されるコード1901と、上述したコード1101とを含む並列化プログラム140がプログラム変換部103から出力される。
上述では、変数のスレッド間での受け渡しを、FIFOによるコードGETおよびPUTを用いて行っているが、これはこの例に限定されない。例えば、アーキテクチャや言語固有のコードの中で、上述のコードGETおよびPUTと同様の機能を持つコードに置き換えることや、グローバル変数と一時的に特定のスレッドのみのアクセスを認めるロック機能を利用するなどによりデータ依存関係を満たすことでも、変数のスレッド間での受け渡しを実現できる。
本実施形態では、ループを分割したスレッド間におけるデータ依存関係の保証を、プログラム変換部103により自動的に行っているが、これはこの例に限定されない。例えば、上述したような処理をユーザがテキストエディタなどを用いて直接的に行うことで、中間並列化プログラム131を変換して並列化プログラム140を生成してもよい。
また、プログラム変換部103が出力した並列化プログラム140を、ユーザがテキストエディタなどを用いて直接的に改良して用いてもよい。さらに、プログラム変換部103が出力する並列化プログラム140を、データ依存関係を解決するコードの挿入部分と関係するスレッドおよびデータのみをコメントの形で挿入したものとし、ユーザがこのコメントを参照して、当該並列化プログラム140を、プログラムを実行する環境向けのコードに書き直すようにしてもよい。さらにまた、この場合において、データ依存関係を解決するコードの挿入部分と関係するスレッドおよびデータのみがコメントの形で挿入された並列化プログラム140を、実行環境向けに用意された変換装置で変換してもよい。さらに例えば、GUIを利用してインタラクティブに出力させることも考えられる。
本実施形態では、プログラム解析部101、プログラム並列化部102およびプログラム変換部103を組み合わせて用いたが、これはこの例に限定されるものではない。例えば、プログラム解析部101、プログラム並列化部102およびプログラム変換部103は、本実施形態によるシステム以外の、例えば並列化コンパイラなどの他の装置向けに作成されたシステムを利用してもよいし、当該システムを本実施形態のシステム向けに改造したシステムを利用してもよい。
上述したプログラム並列化システムによって出力された並列化プログラム140は、例えば、マルチコアのアーキテクチャ上で実行される。すなわち、マルチコアを構成するそれぞれのコアで、並列化プログラム140における、逐次プログラム110のループを分割し、並列化したスレッドのそれぞれが実行される。これに限らず、並列化プログラム140は、シングルコアであっても、1コア上で複数のスレッドを実行が可能なアーキテクチャであれば適用可能である。さらに、複数のCPUを搭載したマルチプロセッサや、複数の計算機を用いたシステム上でも、並列に複数のスレッドの実行が可能であれば適用可能である。
プログラム並列化システムから出力された並列化プログラム140は、コンパイラでコンパイルされ、コンピュータ上で実行される。この際、プログラム並列化部102で生成されたデータ構造や関数(図11のコード1101参照)と、このデータ構造を操作する処理(例えば図19のコード1901参照)とによって、実行前にループの反復回数が不明なループを含む逐次プログラム110の動作を、並列的に実行させることができる。上述の通り、図11のコード1101に相当する部分は、ライブラリ等を用いた方法でも実現できるため、そのような場合は、それぞれコンピュータ上で実行可能な形式に変換される。
図20は、逐次プログラム110のループを、並列化した3のスレッドに分割した場合の、各スレッド間における依存関係の例を示す。図20における処理ブロック#1、#2および#3は、1回のイタレーション処理の実行に対応したスレッドを示す。また、図20(a)、図20(b)および図20(c)は、それぞれ1回のイタレーション処理の実行を示す。すなわち、例えば図20(a)に示される処理ブロック#1、#2および#3は、対応するイタレーション回数の処理を示し、図20(a)は1回目のイタレーション、図20(b)は2回目のイタレーション、図20(c)は3回目のイタレーションを示す。また、図20の例では、各処理ブロック#1、#2および#3のイタレーション1回当たりの処理時間は同じであり、同じ処理ブロック#1〜#3は、前のイタレーションの実行が終了するまで次のイタレーションの実行を行わないと仮定している。また、このような仮定が成り立たず、各処理ブロックの処理時間が異なったり、前のイタレーションの実行が終了しなくとも次のイタレーションの実行が行われる場合でも、上述のような依存関係の保証方法を用いることで並列化を行うことができる。
さらに、図20において、各スレッド間の矢印10、11および20は、それぞれスレッド間の依存関係を表している。白抜きの矢印10および11は、データの依存関係を示しており、例えば、処理ブロック#1から処理ブロック#2へと向けた矢印10は、処理ブロック#1で変更されたデータが処理ブロック#2で利用されることを示す。この場合、処理ブロック#2の処理は、処理ブロック#1の処理が終了するまで保留されることになる。矢印11も同様である。
このようなデータの依存関係は、既に説明したように、プログラム変換部103によって挿入されたコードによって保証される。上述のように、データ依存関係の設定方法は、これに限られない。
図20において、塗り潰された矢印20は、ループの終了制御による依存関係を表す。例えば、図20(a)の処理ブロック#3から図20(b)の処理ブロック#2へと向けた矢印20は、処理ブロック#3において、当該処理ブロック#3によるループ終了後に、次のイタレーションにおいて処理ブロック#2で利用されるデータが変更されるため、処理ブロック#3においてループの終了制御処理によりループが終了したか否かの判定後に、次のイタレーションにおける処理ブロック#2を実行しなければならないことを示す。この場合、例えば2回目のイタレーション(図20(b))における処理ブロック#2は、1回目のイタレーション(図20(a))における処理ブロック#3でのループの終了または継続が確定するまで保留されることになる。
このような、ループの終了制御による依存関係は、既に説明したように、終了制御情報120および変更情報121としてプログラム並列化部102に入力され、ループ並列化部203によって中間並列化プログラム131に挿入されるコードによって処理される。
図21は、図20に例示した並列化されたループを実行した結果の例を示す。図21(a)は、本実施形態の方法で並列化した場合の実行結果の例である。また、図21(b)は、従来技術によりロールバックを用いて並列化した場合の実行結果の例を示す。なお、図21(a)および図21(b)において、縦方向の矢印は時間を示し、列P1、列P2および列P3は、それぞれ並列化された処理を実行する1つの処理装置を示し、例えばプロセッサの1つのコアを示す。また、各処理ブロック#1、#2および#3は、本実施形態に対応する図21(a)においては、それぞれ本実施形態において例として挙げてきたスレッドthread_1、thread_2およびthread_3に対応するものとする。さらに、各処理ブロック#1〜#3の数字に付された添字は、イタレーションの回数を示す。例えば、処理ブロック#11は、スレッドthread_1の1回目のイタレーションによる処理を示す。図21では、各処理ブロックは決められたコアによって実行されているが、イタレーション毎に実行するコアを変更してもよい。
先ず、図21(a)および上述の図20(a)〜図20(c)を参照し、本実施形態の方法で並列化した場合について、一例の動作を説明する。本実施形態によるプログラム並列化システムにより生成された、図11のコード1101と、図17のコード1801とからなる並列化プログラム140をそれぞれコンパイルし、リンク処理などを施して生成した実行ファイルが、例えばコンピュータのCPU上で実行されることで、各スレッドthread_1、thread_2およびthread_3が実行される。
図21(a)において、先ず1回目のイタレーションにおけるスレッドthread_1の処理が、CPU上のコアの1つにより実行される。このコアは、処理ブロック#11すなわち1回目のイタレーションにおけるスレッドthread_1に従い、ループ制御用のデータ構造を確認する関数check_cancel_state()を呼び出す。この時点ではループが終了していないので、処理が継続される。
処理ブロック#11の1回目のイタレーションによる実行が終了すると、図19のコード1901における20行目のコードPUTによる処理と、31行目のコードGETによる処理とによって、図20(a)において矢印10で示される、処理ブロック#11から処理ブロック#21へデータが受け渡されることで、のデータ依存関係が解決され、処理ブロック#21の実行が可能となる。一方、処理ブロック#11は、2回目のイタレーションにおける処理ブロック#12に対するデータの依存関係が設定されておらず、処理ブロック#12の実行が可能となっている。そのため、1回目のイタレーションによる処理ブロック#21と、2回目のイタレーションによる処理ブロック#12とがそれぞれ別のコアにより並列に実行される。
スレッドthread_1を実行するコアは、処理ブロック#12すなわち2回目のイタレーションにおけるスレッドthread_1に従い、ループ制御用のデータ構造を確認する関数check_cancel_state()を呼び出す。この時点ではループが終了していないので、処理が継続される。同様に、スレッドthread_2を実行するコアは、処理ブロック#21すなわち1回目のイタレーションにおけるスレッドthread_2に従い、ループ制御用のデータ構造を確認する関数check_cancel_state()を呼び出す。この時点ではループが終了していないので、処理が継続される。
次に、各コアにより、コード1901の33行目のコードPUTによる処理と、43行目のコードGETによる処理とが実行されることによって、図20(a)において矢印11で示される、処理ブロック#21から処理ブロック#31への依存関係が解決され、処理ブロック#31が実行可能となる。一方、処理ブロック#1の次のイタレーションの処理ブロック#13には依存関係が設定されておらず、処理ブロック#13の実行が可能となっている。そのため、1回目のイタレーションによる処理ブロック#31と、3回目のイタレーションによる処理ブロック#13とがそれぞれ別のコアにより並列に実行される。
スレッドthread_1を実行するコアは、処理ブロック#13すなわち3回目のイタレーションにおけるスレッドthread_1に従い、ループ制御用のデータ構造を確認する関数check_cancel_state()を呼び出す。この時点ではループが終了していないので、処理が継続される。
一方、スレッドthread_3を実行するコアは、処理ブロック#31すなわち1回目のイタレーションにおけるスレッドthread_3に従い、ループ制御用のデータ構造を更新する関数update_cancel_state()を呼び出す。この時点では、ループ終了の条件を満たさなかったため、このコアは、構造体cancelのメンバ変数countを更新し、スレッドthread_3の実行を待っている処理(この例では処理ブロック#22すなわち2回目のイタレーションにおけるスレッドthread_2)に対して、1回目のイタレーションの処理が終了したことを通知し、処理を継続すると共に、図20(a)において矢印20で示される、処理ブロック#22の依存関係が解決される。
一方、次のイタレーションの処理ブロック#14には依存関係が設定されていない。そのため、4回目のイタレーションによる処理ブロック#14と、2回目のイタレーションによる処理ブロック#22がそれぞれ別のコアにより実行される。
スレッドthread_1を実行するコアは、処理ブロック#14すなわち4回目のイタレーションにおけるスレッドthread_1から、ループ制御用のデータ構造を確認する関数check_cancel_state()を呼び出す。この時点ではループが終了していないので、処理が継続される。同様に、スレッドthread_2を実行するコアは、処理ブロック#22すなわち2回目のイタレーションにおけるスレッドthread_2に従い、ループ制御用のデータ構造を確認する関数check_cancel_state()を呼び出す。この時点ではループが終了していないので、処理が継続される。
次に、それぞれ別のコアにより、処理ブロック#32と、5回目のループイタレーションの処理ブロック#15とが実行される。スレッドthread_3を実行するコアは、処理ブロック#32すなわち2回目のイタレーションにおけるスレッドthread_3に従い、ループ制御用のデータ構造を更新する関数update_cancel_state()を呼び出す。この時点では、ループがスレッドthread_1により終了され、ループ終了の条件を満たしたため、スレッドthread_3を実行するコアは、構造体cancelのメンバ変数canceledを「1」に更新し、スレッドthread_1およびthread_2に対して、2回目のイタレーションの処理でループが終了したことを通知する。各コアは、次にこれらのスレッドthread_1およびthread_2を実行した際に、関数check_cancel_state()を呼び出してこの通知を確認し、ループを終了させる。
次に、図21(b)に例示される、従来技術によるロールバックを用いてループを並列化した場合の処理について説明する。なお、各処理ブロック#1’、#2’および#3’の依存関係は、上述の図20に例示した依存関係と同一であるものとする。すなわち、同一イタレーションにおける処理ブロック#1’から処理ブロック#2’に対してデータ依存関係があり、同様に、同一イタレーションにおける処理ブロック#2’から処理ブロック#3’に対してデータ依存関係がある。また、処理ブロック#3’は、次のイタレーションにおける処理ブロック#2’に対して依存関係がある。
ロールバックを用いる場合、図20の処理ブロック#2xで変更されるデータをメモリ上に保存した上で各処理ブロック#1〜#3を実行できる。そのため、図20において矢印20で示した、イタレーション間での依存関係を守る必要がなくなり、ループが終了した場合は、メモリに保存してあるデータを読み出すことで対応することになる。したがって、上述した図21(a)で説明した本実施形態による処理と比較すると、この図21(b)に示される従来技術による処理では、処理ブロック#2xが処理ブロック#3x-1の実行を待たずに処理を進められる。
さらに、この従来技術によれば、処理ブロック#32’ループが終了した後に、図21(b)に処理ブロック#2R’で示される処理により、メモリ上に保存してデータを読み出して、ループが終了した後に利用される値を保証する。データを保証するために、図21(b)において斜線を付して示される処理ブロック#21’、#22’および#23’のデータがメモリ上に保存されている必要がある。処理ブロック#2R’は、このメモリ上に保存されているデータの中から、ループ終了が発生した2回目のイタレーションにおける処理ブロック#22’のデータを呼び出す必要がある。これに対し、本実施形態では、並列化を行うための余分なメモリ領域を確保せずに、実行前にループの反復回数が不明なループを含むプログラムを並列化できる。したがって、本実施形態は、図21(b)に例示した従来技術による方法と比べて、必要なメモリ領域を削減することができる。
ロールバックを用いる場合、上述のように、余分なメモリ領域を必要とすると共に、メモリへのデータの保存および読み出しが必要となるため、オーバーヘッドが発生し、本実施形態と比較した場合、処理時間が余計にかかってしまう可能性がある。図21(b)の例ではイタレーション毎にデータの保存を行う必要があり、本実施形態に比べてオーバーヘッドが大きくなってしまう。
そこで、比較例(特開平11−120003号公報)に示されるように、所定回数毎、例えば10回分のイタレーションが実行される毎に、データ保存を行うことで、保存するデータ量を軽減する方法が提案されている。また、比較例において、データ保存の際、過去2回分のみのデータを保存することによって、保存するデータ量をさらに削減することができる。この場合、データを保存する時点で、例えば10回前と20回前のデータを保存してあることになる。
図21(b)を用いて説明すると、処理ブロック#11は、処理ブロック#1の1回目〜10回目までの実行を示すことになる。他のブロックも同様となるため、図21(b)の例では、処理ブロック#31でループの終了が検出されることになる。この後、ループ実行前の初期状態のデータをメモリから読み出した後に、処理ブロック#1、#2および#3の1回目のループの結果と2回目のループの結果とを再計算することになる。本実施形態の場合、予め計算した部分が完全に無駄になってしまうため、所定回数毎にデータ保存を行うようにしたロールバックを用いる方法に比べて、オーバーヘッドが大きくなるおそれがある。
このように、比較例に示される従来技術では、ロールバックにおいてメモリが圧迫されるという問題は、軽減されている。しかしながら、データを保存するという操作は必要であるため、過去2回分のデータに関してはデータ保存用のメモリ領域が必要となる。このため、並列化前の逐次プログラムの時点ですでにメモリ領域にそれほど余裕がない場合は適用できない可能性がある。
本実施形態によれば、比較例に対し、メモリ領域の削減と共に、並列化プログラムの制御を簡略化できる。図22は、比較例による並列化プログラムの制御方法を概略的に示す一例のフローチャートである。比較例によりループが並列化された並列化プログラムを実行する場合、スレッドを実行する各コアは、実行対象の処理ブロックが実行可能となるまで待機し(ステップS200)、当該処理ブロックが実行されると、当該処理ブロックにおける終了処理により、ループからの飛び出し処理が発生したか否かを判定する(ステップS201)。若し、終了制御による終了処理が発生したと判定したら、各コアは、プログラムの実行中に処理ブロックによりメモリに保存されたたデータをロードして(ステップS204)、ロードしたデータを用いて再計算を行い(ステップS205)、ループを終了させる。
各コアは、ステップS201でループの終了処理が発生していないと判定したら、処理をステップS202に移行させ、ループが規定の回数に達したか否かを判定する。若し、規定の回数に達していないと判定したら、各コアは、処理をステップS200に戻し、例えば次の処理ブロックの処理を実行する。一方、ループが規定の回数に達したと判定したら、各コアは、処理をステップS203に移行させて、実行中の処理ブロックで出力されるデータをメモリに保存し、処理をステップS200に戻す。
この図22のフローチャートによる処理において、斜線を付して示したステップS202、ステップS203、ステップS204およびステップS205の処理は、比較例に特有の処理であって、本実施形態では不要な処理である。したがって、本実施形態では、比較例の処理に対して、ループが規定回数に達したかどうかの判定、必要なデータの保存、保存したデータのロード、ロードしたデータによる再計算といった処理が削減され、全体として処理が簡略化されている。
特に、必要なデータの保存、保存されたデータのロードは、比較例において、比較的負荷の大きな処理である。すなわち、比較例では、必要なデータ全てをメモリ領域の別の場所に保存しておく必要があるため、データの大きさやアーキテクチャによってはデータの保存に長時間を要する場合がある。また、データのロードの際にも、保存されているデータの中から正しいデータを読み出し、適切なデータに上書きすることが必要になるため、データの保存に対して長時間を要する。本実施形態では、これらの比較的負荷の大きな処理が省略されているため、並列化によるプログラムの実行速度の向上の観点から、比較例に対して有利である。
さらに、比較例では、必要なデータがどれなのか、それがどの程度のデータ量なのかを解析することで、必要なメモリ領域を確保し、プログラムの並列化を実現している。しかしながら、必要なデータの中にポインタを介したメモリアクセスを行うデータが含まれているなどの場合は、このような解析を行うことが難しく、並列化を実現することが困難になる。本実施形態によれば、ロールバックのためのデータ保存を行わないため、ループ終了後に利用されるデータの値を変更するか否かだけをスレッド毎に判定すればよい。それと共に、必要なデータの保存を行わないために、データ量の解析は不要となり、データ解析処理を簡略化することができる。これにより、比較例に対して、並列化を実行できるループの種類が多くなる。
次に、本実施形態によるプログラム並列化システムを実現可能な構成について、図23を用いて説明する。図23に例示されるように、本実施形態によるプログラム並列化システムは、例えば一般的なコンピュータにより実現可能である。
図23において、バス300に対してCPU310、RAM(Random Access Memory)311、ROM(Read Only Memory)312、表示制御部313および通信I/F(インターフェイス)314が接続される。また、バス300に対して、ハードディスクドライブ(HDD)315、ドライブ装置316および入力I/F317が接続される。
CPU310は、ROM312やHDD315に記憶されるプログラムに従い、RAM311をワークメモリとして用いて、このコンピュータの全体を制御する。表示制御部313は、CPU310により生成された表示制御信号を、表示装置320が表示可能な信号に変換して出力する。
HDD315は、上述のCPU310が実行するためのプログラムや、プログラムによって用いられるデータなどが格納される。ドライブ装置316は、脱着可能な記録媒体321が装填可能とされ、当該記録媒体321に対するデータの読み書きを行うことができる。ドライブ装置316が対応可能な記録媒体321としては、CD(Compact Disk)、DVD(Digital Versatile Disk)、フレキシブルディスクといったディスク記録媒体や、読み書き可能で不揮発性の半導体メモリが考えられる。
入力I/F317は、外部からのデータの入力を行う。例えば、入力I/F317は、USB(Universal Serial Bus)やIEEE1394(Institute of Electrical and Electronics Engineers 1394)といった所定のインターフェイスを有し、このインターフェイスにより外部の機器からのデータ入力を行う。また、入力I/F317に対して、キーボード322やマウス323といった入力デバイスが接続される。ユーザは、例えば表示装置320に対する表示に応じてこれら入力デバイスを操作することで、このコンピュータに対して指示を出すことができる。
通信I/F314は、所定のプロトコルを用いて外部の通信ネットワークと通信を行う。
上述したプログラム並列化システムにおけるプログラム解析部101、プログラム並列化部102およびプログラム変換部103は、CPU310上で動作するプログラムによって実現される。逐次プログラム110やループ分割情報130は、例えば他のコンピュータで作成され記録媒体321に記録されてこのコンピュータに供給される。これに限らず、逐次プログラム110やループ分割情報130は、外部からネットワークを介してこのコンピュータに供給するようにしてもよいし、キーボード322から入力してもよい。このコンピュータに供給された逐次プログラム110やループ分割情報130は、例えばHDD315やRAM311に記憶される。
本実施形態に係るプログラム並列化システムを実行するためのプログラムは、インストール可能な形式又は実行可能な形式のファイルでCD−ROM、フレキシブルディスク、DVDなどのコンピュータで読み取り可能な記録媒体に記録して提供される。これに限らず、プログラム並列化システムを実行するためのプログラムを、ROM312に予め記憶させて提供してもよい。
さらに、本実施形態に係るプログラム並列化システムを実行するためのプログラムを、インターネットなどのネットワークに接続されたコンピュータ上に格納し、ネットワーク経由でダウンロードさせることにより提供するように構成してもよい。また、本実施形態に係るプログラム並列化システムを実行するためのプログラムを、インターネットなどのネットワーク経由で提供または配布するように構成してもよい。
本実施形態に係るプログラム並列化システムを実行するためのプログラムは、上述した各部(プログラム解析部101、プログラム並列化部102およびプログラム変換部103)を含むモジュール構成となっており、実際のハードウェアとしては、CPU310が例えばHDD315から当該プログラムを読み出して実行することにより上述の各部がRAM311上にロードされ、各部がRAM311上に生成されるようになっている。
一例として、CPU310は、プログラム解析部101により、HDD315やRAM311から読み出した逐次プログラム110およびループ分割情報130に基づき逐次プログラム110を解析し、終了制御情報120、変更情報121およびデータ依存情報122を出力する。これら終了制御情報120、変更情報121およびデータ依存情報122は、HDD315やRAM311を介してプログラム並列化部102に渡される。CPU310は、プログラム並列化部102により、これら終了制御情報120および変更情報121と、HDD315やRAM311から読み出した逐次プログラム110およびループ分割情報130とに基づき中間並列化プログラム131を出力する。この中間並列化プログラム131は、HDD315やRAM311を介してプログラム変換部103に渡される。CPU310は、プログラム変換部103により、この中間並列化プログラム131と、HDD315やRAM311から読み出したデータ依存情報122に基づき並列化プログラム140を生成する。生成された並列化プログラム140は、例えばドライブ装置316により記録媒体321に記録されたり、通信I/F314からネットワークに向けて送信されるなどして、外部に出力される。
なお、上述では、プログラム解析部101、プログラム並列化部102およびプログラム変換部103が1つのコンピュータ上で動作するように説明したが、これはこの例に限られない。例えば、プログラム解析部101、プログラム並列化部102およびプログラム変換部103のうち1または複数がそれぞれ異なるコンピュータ上で動作するようにしてもよい。この場合、終了制御情報120、変更情報121およびデータ依存情報122は、記録媒体321やネットワークを介してプログラム並列化部102やプログラム変換部103に供給される。同様に、中間並列化プログラム131は、記録媒体321やネットワークを介してプログラム変換部103に供給される。
なお、本実施形態は、上述したそのままに限定されるものではなく、実施段階ではその要旨を逸脱しない範囲で構成要素を変形して具体化できる。また、上述の実施形態に開示されている複数の構成要素の適宜な組み合わせにより、種々の発明を形成できる。例えば、実施形態に示される全構成要素から幾つかの構成要素を削除してもよい。さらに、異なる実施形態にわたる構成要素を適宜組み合わせてもよい。