(57)【特許請求の範囲】
【請求項１】
クロック駆動プログラミング（ＣＤＰ）プログラムを格納するメモリを有するコンピュータが、周期的なタイマーによりプログラムを処理する方法であって、前記ＣＤＰプログラムは、内部変数、インタフェース関数、リセット関数、タスク本体関数を記述するタスクプログラムと、前記タスク本体関数を周期的に実行するためのタイマーを有する実行プログラムとを含み、前記コンピュータは、
前記リセット関数の呼び出しを前記実行プログラムから受け取り、前記タスクプログラムの前記内部変数を初期化するステップと、
前記タイマーの周期、および第１の関数を含むタイマー設定要求を前記実行プログラムから受け取り、前記実行プログラムのタイマーの周期を前記タイマー設定要求に含まれる周期に設定し、前記実行プログラムのタイマーのタイマーイベントハンドラーとして前記タイマー設定要求に含まれる前記第１の関数を登録するステップであって、前記第１の関数は、前記タスクプログラムの前記タスク本体関数の呼び出しを含む、ステップと、
前記タイマーの周期で前記第１の関数を呼び出すことにより、前記タスク本体関数を呼び出すステップであって、前記タスク本体関数において、前記内部変数のうち当該タスクプログラムの状態を示す状態内部変数に基づいて、当該タスクプログラムの状態に対応する処理を実行し、当該対応する処理の実行の進捗に応じて、前記状態内部変数を更新する、ステップと、
前記タスクプログラムに処理結果を要求する前記インタフェース関数の呼び出しを前記実行プログラムから受け取り、前記状態内部変数に基づいて処理結果要求を受け入れるか否かを判定する、ステップと
を含むことを特徴とする方法。
【請求項２】
前記タスクプログラムは複数であり、前記第１の関数において、複数のタスクプログラムの各タスク本体関数を呼び出すスケジュールを指定することを特徴とする請求項１に記載の方法。
【請求項３】
前記複数のタスクプログラムから同時に呼び出され得るインタフェース関数は、Bernstein’s conditionを満たすことを特徴とする請求項２に記載の方法。
【請求項４】
前記タスクプログラムは配列化されており、前記第１の関数において、配列化されたタスクプログラムの各タスク本体関数を呼び出すスケジュールを指定することを特徴とする請求項１に記載の方法。
【請求項５】
前記インタフェース関数、前記リセット関数、および前記タスク本体関数は、不定回数ループを含まないことを特徴とする請求項１に記載の方法。
【請求項６】
前記インタフェース関数、前記リセット関数、および前記タスク本体関数において、Blocking I/Oを用いないことを特徴とする請求項１に記載の方法。
【請求項７】
クロック駆動プログラミング（ＣＤＰ）プログラムを格納するメモリと、
プロセッサと
を備えたプログラム処理システムであって、
前記ＣＤＰプログラムは、内部変数、インタフェース関数、リセット関数、タスク本体関数を記述するタスクプログラムと、前記タスク本体関数を周期的に実行するためのタイマーを有する実行プログラムとを含み、
前記プロセッサは、
前記リセット関数の呼び出しを前記実行プログラムから受け取り、前記タスクプログラムの前記内部変数を初期化するステップと、
前記タイマーの周期、および第１の関数を含むタイマー設定要求を前記実行プログラムから受け取り、前記実行プログラムのタイマーの周期を前記タイマー設定要求に含まれる周期に設定し、前記実行プログラムのタイマーのタイマーイベントハンドラーとして前記タイマー設定要求に含まれる前記第１の関数を登録するステップであって、前記第１の関数は、前記タスクプログラムの前記タスク本体関数の呼び出しを含む、ステップと、
前記タイマーの周期で前記第１の関数を呼び出すことにより、前記タスク本体関数を呼び出すステップであって、前記タスク本体関数において、前記内部変数のうち当該タスクプログラムの状態を示す状態内部変数に基づいて、当該タスクプログラムの状態に対応する処理を実行し、当該対応する処理の実行の進捗に応じて、前記状態内部変数を更新する、ステップと、
前記タスクプログラムに処理結果を要求する前記インタフェース関数の呼び出しを前記実行プログラムから受け取り、前記状態内部変数に基づいて処理結果要求を受け入れるか否かを判定する、ステップと
を実行するよう構成されることを特徴とするプログラム処理システム。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、プログラム処理方法およびそのシステムに関し、より詳細には、周期的なタイマーによりプログラムを処理する方法、およびそのシステムに関する。
【背景技術】
【０００２】
クラウドコンピューティングは次世代のコンピューティング環境として期待を集めている。クラウドサービスを利用すると、システムの実行環境（サーバ、ストレージ、ネットワークなど）の調達・増強・縮退が短時間で可能であり、使った時間だけ利用料を払えばよい。従来、ソフトウェアシステムは、運用時にはごく稀にしか起きないピーク性能を基準に実行環境をサイジングし、その固定的な実行環境を前提に構築されてきた。その結果、低い平均負荷、高い運用コストを招いていた。クラウドでは、必要に応じて実行環境のサイズを変えられるので、運用コストの削減が期待できる。
【０００３】
また、従来、ソフトウェアシステムの開発段階において、マシンリソースの不足が開発スケジュール遅延の原因となることが多かった。例えば、試験工程では、マシンリソースの不足により、多くの期間を費やすこととなる。開発段階においてクラウドコンピューティングを利用することで、マシンリソースに制約されない開発が可能になり、開発期間の短縮、開発費の削減が期待できる。このようにクラウドコンピューティングは、従来のソフトウェアシステムの諸問題を解決できる可能性を秘めている。
【０００４】
クラウドコンピューティングには課題もある。一般に、ソフトウェアシステムは、機能要求に加えて、性能要求も満たす必要がある。従来、固定された実行環境において性能試験を行うことにより、一定の性能を保証してきた。従来型システムでは、実際に運用される実行環境が固定されるので、同実行環境における試験結果が、運用時に成り立つと類推可能だからである。一方、クラウドサービスでは、ベストエフォートで実行環境を提供する。
【０００５】
ベストエフォート型では、例えば、ＣＰＵのクロック数に関して、あるユーザーがＣＰＵ負荷の高いプログラムを実行すると、同一環境を利用する別のユーザーの性能は劣化する。また、ストレージに関して、あるユーザーがストレージに過剰な負荷をかける大量のトランザクションを処理すると、同様に、同一環境を利用する別のユーザーのＩ／Ｏ性能は劣化する。ネットワークに関しても同様である。これでは、実行環境を特定することができず、従って、性能試験の結果が運用時にも成り立つとの類推はできない。
【０００６】
非特許文献１では、クラウドを用いたMapReduce environmentの貸出サービスにおいて、クラウドサービスの性能保証に関する問題点を指摘しているが、解決への道筋は示されていない。
【先行技術文献】
【非特許文献】
【０００７】
【非特許文献１】L. Cherkasova. Performance modeling in mapreduce environments: challenges and opportunities. In Proceeding of the second joint WOSP/SIPEW international conference on Performance engineering， ICPE ’11， pages 5-6， New York， NY， USA， 2011. ACM.
【発明の概要】
【発明が解決しようとする課題】
【０００８】
上述したように、クラウドコンピューティングでは、試験による性能保証が困難である。すなわち、所定の性能を実現するために必要な実行環境のサイジングも困難である。
【０００９】
本発明は、このような問題に鑑みてなされたもので、その目的とするところは、実行環境を固定できないクラウドコンピューティングにおいて、システムとしての性能（スループット）を保証する手段を提供することにある。
【課題を解決するための手段】
【００１０】
本発明では、実行環境と独立してソフトウェアの性能を決定し得るプログラムを構成し、処理するために、デジタル回路の論理設計におけるクロック駆動の概念を参考とする。
【００１１】
周知のように、デジタル論理設計は、組み合わせ論理回路(Combinational logic)および順序論理回路(Sequential logic)の二つに分類される。前者は入力のみで出力が決まり、後者は、入力および現状態で出力(および次状態）が決まる。順序論理回路は、イベント駆動およびクロック駆動の二つに分類される。前者は、状態の変化が入力（Event)のタイミングで起きるのに対し、後者では、入力のタイミングにかかわらず、クロックと同期して状態の変化が起きる。イベント駆動とクロック駆動の比較を表1に示す。
【００１２】
【表１】
0005465745.tif 000002
【００１３】
今日、デジタル回路は大規模集積回路(ＬＳＩ)で作られることが通常である。ＬＳＩの各素子（トランジスターなど）は微細加工により作られるので、その特性にはバラつきがある。そのため、イベント駆動設計では、特性のバラつきを考慮して、十分なタイミングマージンをとった設計が要求される。バラつきがマージンより大きいと、回路は正常に動作しない。クロック駆動設計においても、周期以内に回路動作が終了せず、タイミングバイオレーションが起こると、回路は正常に動作しない。ただし、クロック駆動設計では、クロック周波数を下げて、マージンを大きくすることにより、タイミングバイオレーションの発生確率を下げることができる。
【００１４】
さらに、イベント駆動設計では、素子特性のバラつきがそのまま、回路の性能差となって現れる。一方、クロック駆動設計では、クロック周波数が同一であれば、性能は同一になる。すなわち、クロック駆動設計では、イベント駆動設計と比較して、一定の性能保証を容易に行うことができる。
【００１５】
そこで、本発明では、周期的にプログラムを駆動する、Timer interrupt、Timer Signal(POSIX/UNIX（登録商標）/Linux（登録商標）)、Timer Event (Windows（登録商標）)、などを利用することにより、プログラムをクロック駆動する。
【００１６】
本発明のプログラムがタイマーにより駆動されると、定められた一定の処理を実行し、それが終了すると、次にタイマーによりプログラムが駆動されるまで休む。高速マシンを使うと、実行時間は減少するが、その分休止時間が増える。低速マシンを使うと、実行時間が増加し、その分休止時間が減少する。すなわち、高速マシンおよび低速マシンのいずれを用いても、時間当たりの実行ステップ数は同じになる。従って、性能（スループット）はハードウェアには依存せずに同一になる。
【００１７】
以下に示すように、実行時間τと周期Ｔの比をデューティ率Ｄと呼ぶ。
【００１８】
【数１】
0005465745.tif 000003
【００１９】
デューティ率が１００％未満、すなわち実行時間が周期を下回る場合、プログラムの性能は、マシンの性能ではなく、周期Ｔにより決まる。これにより、ハードウェアに依存しない性能設計が可能になる。
【発明の効果】
【００２０】
本発明は、タイマーにより、定められた一定の処理を実行し、それが終了すると、次にタイマーにより駆動されるまで休むよう動作するプログラムを処理することにより、実行環境を固定できないクラウドコンピューティングにおいて、システムとしての性能を保証することができる。
【００２１】
また、本発明は、所定の条件を満たすプログラムを構成することにより性能保証を実現することができるので、クラウドサービスの提供者は、性能保証のために余分な設備を保持する必要はない。さらに、ソフトウェアの開発段階において本発明の特徴を有するプログラムを構成するだけで、求められる性能保証の変更にも、迅速に、的確に対応することができる。
【図面の簡単な説明】
【００２２】
【図１】本発明の一実施形態に係るネットワーク構成を示す図である。
【図２】本発明の一実施形態に係るタスクのプログラム記述例を示す図である。
【図３】本発明の一実施形態に係る別のタスクを利用するタスクのプログラム記述例を示す図である。
【図４】本発明の一実施形態に係るタスク配列のプログラム記述例を示す図である。
【図５】本発明の一実施形態に係るタスクのコールグラフを示す図である。
【図６】本発明の一実施形態に係るタスクのＰＥＲＴ図である。
【図７】本発明の一実施形態に係るタスクのコールグラフを示す図である。
【図８Ａ】ポーリングを用いたタスクのプログラム記述例を示す。
【図８Ｂ】ポーリングを用いたタスクのプログラム記述例を示す。
【図９】本発明の一実施形態に係るタスクのＰＥＲＴ図である。
【図１０】本発明の一実施形態に係るタスク間の先行関係を示す先行関係表である。
【図１１Ａ】変数リネーム技法を適用する前のプログラム記述例を示す図である。
【図１１Ｂ】変数リネーム技法を適用する後のプログラム記述例を示す図である。
【図１２】個別化技法を適用する前後のコールグラフを示す図である。
【図１３Ａ】抽選化技法を適用したタスクのプログラム記述例を示す図である。
【図１３Ｂ】抽選化技法を適用したタスクのプログラム記述例を示す図である。
【図１４】本発明の一実施形態に係るタスクのＰＥＲＴ図である。
【図１５】本発明の一実施形態に係るタスクを実行するプログラム記述例を示す図である。
【図１６】本発明の一実施形態に係るタスクを実行するプログラム記述例を示す図である。
【図１７】本発明の一実施形態に係るタスクを並列実行するシーケンス図である。
【図１８】本発明の一実施形態に係る周期的なタイマーによりプログラムを処理する工程を示すフローチャートである。
【図１９】本発明の一実施形態に係るタスクを実行するプログラム記述例を示す図である。
【発明を実施するための形態】
【００２３】
（システム構成）
図１は、本発明の一実施形態に係るネットワーク構成を示す図である。複数のプログラム処理システム１０１ａ、１０１ｂ、・・・、１０１ｎ（以下、プログラム処理システム１０１と呼ぶ）が、インターネット１０２を介して、複数のクライアントコンピュータ１０３ａ、１０３ｂ、・・・、１０３ｎ（以下、クライアントコンピュータ１０３と呼ぶ）と相互に通信可能に接続される。
【００２４】
プログラム処理システム１０１は、利用者に提供するサービスを実現するためのプログラムを格納するメモリを有し、利用者の要求に応答して、ストレージに格納されたプログラムを処理するために必要なデータを用いて、サービスを提供する。本発明のプログラム処理システム１０１により実行されるプログラムは、所定の条件を満たすよう構成されたクロック駆動プログラミング（ＣＤＰ）プログラムである。
【００２５】
クライアントコンピュータ１０３は、クラウドサービスの利用者によって使用される端末である。利用者は、クライアントコンピュータ１０３を介して、プログラム処理システム１０１が提供するサービスを、サーバ群を意識することなしに利用する。本実施形態では、クライアントコンピュータ１０３は、一般的なパーソナルコンピュータである。
【００２６】
（ＣＤＰプログラム）
ＣＤＰは、イベント駆動プログラミング（ＥＤＰ）の一部である。従って、ＣＤＰは、ＥＤＰをサポートする任意のプログラミング言語、およびＯＳで実践できる。本実施形態では、C言語、およびWindowsを用いるが、これに限定されるものではない。
【００２７】
ＣＤＰとＥＤＰとの違いは、イベントハンドラーの使い方にある。ＥＤＰでは、任意の数のタイマーを利用することができるのに対し、ＣＤＰでは、タイマーイベントハンドラーを提供するタイマーを、必ず１つ利用することが要求される。
【００２８】
また、ＥＤＰでは、タイマーイベントハンドラーを含むすべてのイベントハンドラーにおいて、イベントに対応する処理を行う。一方、ＣＤＰでは、タイマーイベントハンドラー以外のイベントハンドラーにおいて、状態を示すフラグをセットすることにより、イベントの発生を記録するのみで、イベントに対応する処理は、ここでは行わない。ＣＤＰでは、タイマーイベントハンドラーにおいて、状態を示すフラグに基づいて、イベントの発生に対応するタスクを実行する。
【００２９】
ＣＤＰプログラムは、以下の手順で作成される。１）タスクを洗い出し、記述する。２）タスク間の先行関係を把握し、ＰＥＲＴ図を作成する。３）ＰＥＲＴ図によって与えられた先行関係の制約を満たすスケジュールを作成する。タスクの記述、ＰＥＲＴ図の作成、スケジュールの作成を順に説明する。
【００３０】
（タスクの記述）
本発明のＣＤＰのタスクを、図２のプログラム記述例に基づいて説明する。本発明では、ＣＤＰのタスクを以下の要素を用いて定義する。
内部変数：ステート間で値を引継ぐために使用する１以上の変数
インタフェース関数：内部変数を他のタスクが参照または更新するための０以上の関数
リセット関数：内部変数を初期化するための関数
タスク本体関数：タイマーイベントハンドラーによって呼び出される関数
【００３１】
ＣＤＰのタスクは、状態により、実行する動作が変化するステートマシンである。ステート間で値を引継ぐために、内部変数を用いる。図２の例では、行番号L5に、taskA_data_t構造体型の内部変数taskA_dataが定義されている。なお、taskA_data_t構造体型は、同図の行番号L2からL4により示されるように、taskA_state_t列挙型の変数state、int型のx、y、resultをメンバとして含む。
【００３２】
ＣＤＰのタスクは、前述の内部変数を他のタスクが参照または更新するためのインタフェース関数を必要に応じて定義する。図２の例では、行番号L13からL31で定義されるcalcメソッド、行番号L33からL43で定義されるget_resultメソッドがインタフェース関数である。calcメソッドは、図２に記述されるTaskAに処理を要求するための関数、get_resultメソッドは、処理結果を要求するための関数である。
【００３３】
ＣＤＰのタスクはまた、内部変数を初期化するためのリセット関数を定義する。図２の例では、行番号L45からL48で定義されるtaskA_RSTメソッドがリセット関数である。本実施形態では、リセット関数において内部変数taskA_dataのメンバ変数stateを初期化している。
【００３４】
そして、ＣＤＰのタスクは、タイマーイベントハンドラーによって呼び出されるタスク本体関数を定義する。図２の例では、行番号L50からL84で定義されるtaskA_CLKメソッドがタスク本体関数である。図２に示されるように、タスク本体関数は、taskA_data.stateの値に従って計算を実行する。stateがcalc1の場合、Ｆ（ｘ）を計算する。ここで、関数Fは、行番号L11で定義されるように、標準ライブラリなどの他のモジュールで定義される外部関数である。stateがcalc2の場合、定数LIMITを上限として、Ｆ（ｘ）yを計算する。
【００３５】
ここで、タスクの実行時間は、タイマーの周期より短い必要がある。そのため、タスクは次の２つの要求を満たす必要がある。１）タスクは、実行ステップの上限を有する。２）タスクの各ステートメントは、実行時間の上限を有する。
【００３６】
要求１）を満たすために、各関数は、構文的に停止性が保証される形で書く。すなわち、選択(if then else)および順次（;) の組み合わせに展開可能となるように記述する。ループに関しては、反復回数に上限があるものだけが記述可能であり、実行時に反復回数が決まるループを書くことは許されない。不定回数のループは、図２のtaskA_CLKメソッドのように、固定回数のループを周期的に実行することにより実現する。この場合、選択（if then else)によりステップ数は変化するが、１周期で実行されるステップ数には上限が存在するので、要求１）が満たされる。
【００３７】
要求２）を満たすために問題となるのは、ステートメントが関数呼び出しを含む場合である。呼び出す関数が他のタスクのインタフェース関数である場合は、呼び出し先の関数についても実行ステップ数に上限があり、結果として実行時間に上限があるので、問題はない。一方、呼び出す関数が、ライブラリ関数やＯＳの機能を呼び出すＡＰＩなど、ＣＤＰに従わない関数である場合、実行時間に上限がない場合がある。
【００３８】
特に問題となるのが、ＯＳのＡＰＩに存在するblocking I/Oである。例えば、blocking I/OのREAD関数を用いてファイルの読み出しをする場合、ファイルの読み出しが完了するまで、呼び出し側プログラムに制御を戻さない。これでは、要求２）を満たすことができない。そこで、ＣＤＰのタスクでは、原則としてblocking I/Oの代わりに、non-blocking I/Oを用いる。あるいは、select関数等を用いてブロックされないことを確認した上でblocking I/Oを用いる。
【００３９】
続いて、図３に、図２に記載のtaskAを利用するtaskBのプログラム記述例を示す。taskBは、列挙型の変数state、int型のa、b、zをメンバとして含む構造体型の内部変数taskB_dataを持つ。taskBのタスク本体関数では、図３の行番号L34に示されるように、stateがstate_10の場合、calcメソッドを呼ぶことによりtaskAに処理を要求する。図２の行番号L23に示されるように、taskAの状態に従って要求が受け入れられる場合のみ、戻り値として0が返される。従って、taskBは、要求が受け入れられるまでリトライし、要求が受け入れられると、state_11に遷移する。
【００４０】
また、図３の行番号L40に示されるように、stateがstate_11の場合、get_resultメソッドを呼ぶことにより処理結果の取得を試みる。ここでも、図２の行番号L40に示されるように、taskAの状態に従って計算が終わっている場合のみ、戻り値として0が返される。従って、taskBは、戻り値として0が得られるまで、クロック毎にget_resultメソッドを呼び出し、処理結果を取得すると、state_12に遷移する。
【００４１】
（タスクの配列化）
図２の行番号L18に示されるように、taskAはstateがfreeである場合のみ、計算要求を受け入れる。つまり、taskAが先行する計算要求を受け入れ、計算を実行している間は、他のタスクからの計算要求を受け入れることはできない。そこで、同時に複数の計算要求を処理したい場合には、同一機能を持つ複数のタスクを用意するために、タスクを配列化したタスク配列を定義する。図４に、図２に記載のtaskAを配列化したタスク配列のプログラム記述例を示す。
【００４２】
図４の行番号L4に示されるように、タスク配列では、内部変数を配列化する。そして、行番号L7に示されるように、インタフェース関数calcの引数としてインデクスを受け取り、内部変数の参照、更新時には受け取ったインデクスを指定して行う。他の関数においても、同様に引数としてインデクスを受け取り、受け取ったインデクスを指定して内部変数の参照更新を行うことにより、タスクを配列化することができる。内部変数配列の要素数をタスク配列の多重度と呼び、配列化されていないタスク（例えば、図２のtaskA）の多重度は１である。
【００４３】
（ＰＥＲＴ図の作成）
タスクを記述したら、次にタスク間の先行関係を把握しＰＥＲＴ図を作成する。タイマーイベントハンドラーが呼び出すのは、タスク本体関数であり、タスク間の先行関係とは、タスク本体関数間の先行関係である。あるタスクは、そのタスク本体関数において、他のタスクのインタフェース関数を呼び出して、他のタスクの処理結果を取得する。例えば、図３に示すtaskBは、タスク本体関数において、taskAのget_resultメソッドを呼び出して、taskAの処理結果Ｆ（ｘ）yを取得する。このインタフェース関数の静的呼び出し関係を示したものが、図５のコールグラフである。
【００４４】
ここで、taskBが処理結果を得るためには、taskAのタスク本体関数がtaskBのタスク本体関数の実行の前に完了している必要がある。この場合、taskAはtaskBに先行する。完了順序を示すＰＥＲＴ図は、コールグラフの矢印の向きを逆転することにより得ることができる（図６）。しかし、全てのコールグラフからＰＥＲＴ図を得ることができるわけではない。
【００４５】
ＰＥＲＴ図を得るためには、コールグラフがacyclicである（ループがない）必要がある。図７に示すように、コールグラフがacyclicでない場合は、ポーリング（polling）を用いてタスク間のインタフェースの向きを入れ替える必要がある。taskAとtaskBとのコールグラフはacyclicであるので、タスク間のインタフェースの向きを入れ替える必要はない。ポーリングを用いる参考例として、図８Ａおよび図８Ｂに、インタフェース方向を変えたtaskAおよびtaskBのプログラム記述例を示す。
【００４６】
得られたＰＥＲＴ図から、同時実行され得るタスクを判断することができる。コールグラフに基づいて、図９に示すＰＥＲＴ図が得られたものとする。ここで、図９に示すＰＥＲＴ図のグラフＧは、１から９のタスクに対応するノードの集合、およびタスク間の先行関係を表す矢印の集合により構成される。ＰＥＲＴ図には、本来のタスク１から９に対応するノードに加えて、プログラム全体のスタートとフィニッシュをそれぞれ表す端点sと端点tが記されている。
【００４７】
図１０に、図９のＰＥＲＴ図に含まれるタスク間の先行関係を示す先行関係表を示す。図中の◎は、２つのタスクが、直接の先行関係を有することを示す。例えば、タスク１と（タスク１のインタフェース関数を呼び出す）タスク４、タスク１と（タスク１のインタフェース関数を呼び出す）タスク６などは、直接の先行関係を有する。図中の○は、２つのタスクが、間接の先行関係を有することを示す。例えば、タスク１とタスク７、タスク１とタスク８、タスク１とタスク９などは、間接の先行関係を有する。図中の×は、２つのタスクが、先行関係を有し得ないことを示す。
【００４８】
間接の先行関係は、直接の先行関係を有さないが、１または複数のタスクを経由して先行関係を有する２つのタスク間において生じる。例えば、タスク１とタスク７は、タスク１のインタフェース関数を呼び出し、かつタスク７によりそのインタフェース関数を呼び出されるタスク４を経由して、先行関係を有する。同様に、タスク１とタスク８も、タスク４を経由して先行関係を有する。また、タスク１とタスク９は、タスク４およびタスク７を経由して、あるいはタスク６を経由して、先行関係を有する。
【００４９】
ここで、特定のタスクｖのインタフェース関数を呼び出すタスクｕ、およびタスクｗが、直接または間接の先行関係を有する場合、タスクｕとタスクｗとは、同時実行されることはない。例えば、タスク１のインタフェース関数を呼び出すタスク４およびタスク６は、図１０に示されるように直接の先行関係を有するので、同時実行されることはない。一方、タスク３のインタフェース関数を呼び出すタスク５およびタスク８は、図１０に示されるように先行関係を有さないので、同時実行され得る。
【００５０】
複数のタスクが同時に同じタスクのインタフェース関数を呼び出す場合、タスクの実行される順序やインタフェース関数の実行される順序により、結果が変わってしまう可能性がある。そこで、複数のタスクから同時に呼び出され得るインタフェース関数は、Bernstein’s conditionsを満たす必要がある。Bernstein’s conditionsは、プログラムの断片が並列実行できるための、周知の十分条件である。
【００５１】
例えば、タスク５およびタスク８から同時に呼び出され得る、タスク３に含まれる関数ｆ、ｇは、関数ｆの中で構文的に参照される内部変数の集合（Ｒ（ｆ））、関数ｆの中で構文的に代入される内部変数の集合（Ｗ（ｆ））、関数ｇの中で構文的に参照される内部変数の集合（Ｒ（ｇ））、および関数ｇの中で構文的に代入される内部変数の集合（Ｗ（ｇ））について以下の(1)から(3)が成り立つ場合、Bernstein’s conditionsを満たし、並列実行することができる。
R(f) ∩ W(g) ＝ φ・・・(1)  
R(g) ∩ W(f) ＝ φ・・・(2)  
W(f) ∩ W(g) ＝ φ・・・(3)
【００５２】
（Bernstein’s conditionsを満たすプログラムへの書き換え技法）
同時実行され得るタスクがBernstein’s conditionsを満たさない場合、書き替え技法を用いてプログラムを修正する必要がある。代表的な３つの書き換え技法を以下で紹介する。
【００５３】
第１の書き替え技法として、変数リネーム技法がある。図１１Ａおよび図１１Ｂに、変数リネーム技法を適用する前後のプログラム記述例を示す。適用前のプログラム記述例では、図１１Ａに示されるように、インタフェース関数read、writeにおいて、Ｒ（read） ∩ Ｗ（write） ＝ {taskA_x} ≠ φであり、Bernstein’s conditionsを満たさない。一方、適用後のプログラム記述例では、図１１Ｂに示されるように、別途内部変数を用いてプログラムを修正することにより、Ｒ（read） ∩ Ｗ（write） ＝φとなり、Bernstein’s conditionsを満たすことができる。
【００５４】
第２の書き替え技法として、個別化技法がある。個別化技法では、Bernstein’s conditionsを満たさないインタフェース関数を有するタスクを、配列化する。図１２に、個別化技法を適用する前後のコールグラフを示す。適用前のコールグラフでは、図１２（左）に示されるように、インタフェース関数calc_Fの競合がおき、Ｒ（calc_F） ∩ Ｗ（calc_F） ＝ {taskB_data} ≠ φであり、Bernstein’s conditionsを満たさない。一方、適用後のコールグラフでは、図１２（右）に示されるように、taskBを配列化することにより、Ｒ（calc_F(0)) ∩ ）Ｗ（calc_F(1)） ＝ {taskB_data[0]} ∩ {taskB_data[1]} ＝ φとなり、Bernstein’s conditionsを満たすことができる。
【００５５】
第３の書き替え技法として、抽選化技法がある。前述した個別化技法は、唯一のリソースを使用する場合には適用することができない。この場合、内部変数のみを配列化し、タスクは配列化しない抽選化技法により、インタフェース関数の競合を防ぐ。具体的には、図１３Ａに示されるように、競合対象であるtaskBのタスク本体関数において、複数のインタフェース関数呼び出しのうちの１つを選択し（抽選）、選択された（当選した）呼び出しのみ処理を実行し、選択されなかった（落選した）呼び出しについてはエラーを返す。また、図１３Ｂに示されるように、呼び出し側タスクであるtaskC（およびtaskD（図示せず））では、当選するまでインタフェース関数の呼び出しを繰り返す。
【００５６】
（スケジュールの作成）
ＰＥＲＴ図が得られたら、次にスケジュールを作成する。スケジュールは、どのタイミングでどのリソースにタスクを割り当てるかを、ＰＥＲＴ図で与えられた先行関係を満たすように定めたものである。利用可能なリソースの制約の元で、完了時間が最小となるスケジュールを作成することが望ましい。図１４に示すＰＥＲＴ図に基づいて、スケジュールを作成する。
【００５７】
（スケジュールの作成−逐次実行）
逐次実行する場合、ＰＥＲＴ図を既知のアルゴリズムでトポロジカルソートすることにより、容易にスケジュールを作成することができる。図１４のＰＥＲＴ図の場合、以下の３つのスケジュールが作成される。taskX、taskY、taskZ、taskWのタスク本体関数が、それぞれ、taskX_CLK()、taskY_CLK()、taskZ_CLK()、taskW_CLK()であるものとする。  
スケジュール１＝taskX_CLK(); taskY_CLK(); taskW_CLK(); taskZ_CLK();
スケジュール２＝taskX_CLK(); taskY_CLK(); taskZ_CLK(); taskW_CLK();
スケジュール３＝taskX_CLK(); taskZ_CLK(); taskY_CLK(); taskZ_CLK();
【００５８】
ＰＥＲＴ図の先行関係を満たす限り、どの順序で実行しても同一の結果を得ることができ、また、同一の完了時間となる。従って、任意のスケジュールを選択することができる。図１５に、スケジュール１でタスクを実行するプログラム記述例を示す。図１５の行番号L25において、第３引数（presiod）で指定した100ミリ秒ごとに、第４引数（OnTimer）で指定した関数が呼ばれるよう、タイマーの設定が行われている。本実施形態ではスケジュール１を実行するために、図１５の行番号L6からL9に示されるように、タスクの実行順序を定義する。
【００５９】
（スケジュールの作成−並列実行）
並列実行する場合、タスク間の先行関係は同期プリミティブを用いて実現する。本実施形態では、同期プリミティブとして、Windowsの提供するEvent Objectを用いる。Event Objectは、２つの状態（シグナル状態／非シグナル状態）を持つ。SetEvent(e)を呼び出すことにより、引数eのハンドルにより特定されるEvent Objectはシグナル状態になる。WaitForSingleObject(e)を呼び出すと、引数eのハンドルにより特定されるEvent Objectが非シグナル状態である場合、シグナル状態になるまでWaitForSingleObject(e)の呼び出し側スレッドは待機し続ける。他のスレッドによりSetEvent(e)が呼ばれ、eにより特定されるEvent Objectがシグナル状態になると、制御が戻され、呼び出し側スレッドは後続の処理を実行することができる。
【００６０】
例えば、図１４のＰＥＲＴ図を、並列度４で実行する場合を考える。  
スケジュール４−０＝taskX_CLK(); SetEvent(e1); SetEvent(e2);
スケジュール４−１＝WaitForSingleObject(e1); taskZ_CLK();
スケジュール４−２＝WaitForSingleObject(e2); taskY_CLK(); SetEvent(e3);
スケジュール４−３＝WaitForSingleObject(e3); taskW_CLK();
【００６１】
スケジュール４−０では、taskX_CLKメソッドが完了すると、e1およびe2により特定されるEvent Objectをシグナル状態にする。スケジュール４−１では、WaitForSingleObject(e1)を呼び出し、e1により特定されるEvent Objectがシグナル状態になるまで、待機し続ける。taskX_CLKメソッドの完了によりSetEvent(e1)が呼ばれると、スケジュール４−１に対応するスレッドに制御が戻され、taskZ_CLKメソッドが実行される。同様に、スケジュール４−２では、WaitForSingleObject(e2)を呼び出し、e2により特定されるEvent Objectがシグナル状態になるまで、待機し続ける。taskX_CLKメソッドの完了によりSetEvent(e2)が呼ばれると、スケジュール４−２に対応するスレッド制御が戻され、taskY_CLKメソッドが実行される。スケジュール４−２では、taskY_CLKメソッドが完了すると、e3により特定されるEvent Objectをシグナル状態にする。スケジュール４−３も、WaitForSingleObject(e3)を呼び出し、e3により特定されるEvent Objectがシグナル状態になるまで、待機し続ける。taskY_CLKメソッドの完了によりSetEvent(e3)が呼ばれると、スケジュール４−３に対応するスレッドに制御が戻され、taskW_CLKメソッドが実行される。
【００６２】
図１６に、スケジュール４−０から４−３でタスクを実行するプログラム記述例を示す。図１６の行番号L43において、第３引数（presiod）で指定した100ミリ秒ごとに、第４引数（OnTimer）で指定した関数が呼ばれるよう、タイマーの設定が行われている。本実施形態では、図１６の行番号L3からL14に示されるように、スケジュール４−１から４−３に対応するスレッドを用意する。
【００６３】
OnTimerメソッドでは、まず、スレッド１、スレッド２、スレッド３にそれぞれ対応するs[0]、s[1]、s[2]により特定されるEvent Objectをシグナル状態にする。その後、メインスレッドでスケジュール４−０を実行し、スレッド１、スレッド２、スレッド３にそれぞれ対応するt[0]、t[1]、t[2]により特定されるEvent Object のWaitForSingleObjectメソッドを呼び出すことで、Event Objectがシグナル状態になるまで、すなわち該当のスレッドが完了するまで待機し続ける。図１７に、並列実行のシーケンス図を示す。
【００６４】
スケジュール４−１に対応するスレッド１では、WaitForSingleObject(s[0])を呼び出し、s[0]により特定されるEvent Objectがシグナル状態になるまで、待機し続ける。図１６の行番号L18に示されるように、OnTimerメソッド内でSetEvent(s[0])が呼ばれると、スレッド１に制御が戻され、WaitForSingleObject(e1)を呼び出す。その後、e1により特定されるEvent Objectがシグナル状態になるまで、待機し続ける。taskX_CLKメソッドの完了によりSetEvent(e1)が呼ばれると、スレッド１に制御が戻され、taskZ_CLKメソッドが実行される。スレッド１では、taskZ_CLKメソッドが完了すると、t[0]により特定されるEvent Objectをシグナル状態にすることで、スレッドの完了を通知する。
【００６５】
スケジュール４−２に対応するスレッド２（図示せず）においても、スレッド１同様、WaitForSingleObject(s[1])を呼び出し、s[1]により特定されるEvent Objectがシグナル状態になるまで、待機し続ける。図１６の行番号L19に示されるように、OnTimerメソッド内でSetEvent(s[1])が呼ばれると、スレッド２に制御が戻され、WaitForSingleObject(e2)を呼び出す。その後、e2により特定されるEvent Objectがシグナル状態になるまで、待機し続ける。taskX_CLKメソッドの完了によりSetEvent(e2)が呼ばれると、スレッド２に制御が戻され、taskY_CLKメソッドが実行される。スレッド２では、taskY_CLKメソッドが完了すると、taskYの完了を通知するSetEvent(e3)を呼び出し、その後、t[1]により特定されるEvent Objectをシグナル状態にすることで、スレッドの完了を通知する。
【００６６】
スケジュール４−３に対応するスレッド３（図示せず）においても、スレッド１同様、WaitForSingleObject(s[2])を呼び出し、s[2]により特定されるEvent Objectがシグナル状態になるまで、待機し続ける。図１６の行番号L20に示されるように、OnTimerメソッド内でSetEvent(s[2])が呼ばれると、スレッド３に制御が戻され、WaitForSingleObject(e3)を呼び出す。その後、e3により特定されるEvent Objectがシグナル状態になるまで、待機し続ける。taskY_CLKメソッドの完了によりSetEvent(e3)が呼ばれると、スレッド３に制御が戻され、taskW_CLKメソッドが実行される。スレッド３では、taskW_CLKメソッドが完了すると、t[2]により特定されるEvent Objectをシグナル状態にすることで、スレッドの完了を通知する。
【００６７】
（スケジュールの作成−タスク配列）
タスク配列内の各タスク間に先行関係は存在しない。そのため、各タスクをどのような順序でスケジューリングしてもよい。また、タスク配列は、コードは全て同じで、内部変数の場所だけが異なるので、タスク配列内の各タスクの平均の実行時間は、同一であることが期待できる。従って、タスクの多重度がｍ、利用可能なＣＰＵ数がｎである場合、各ＣＰＵにｍ／ｎ個ずつタスクを分配する。
【００６８】
図１４に示すＰＥＲＴ図のtaskYが多重度４のタスク配列で、利用可能なＣＰＵ数が５である場合、以下のスケジュールを作成することができる。  
スケジュール５−０＝taskX_CLK(); SetEvent(e1); SetEvent(e21); SetEvent(e22);
スケジュール５−１＝WaitForSingleObject(e1); taskZ_CLK();
スケジュール５−２＝WaitForSingleObject(e21); taskY_CLK(0); taskY_CLK(2); 
SetEvent(e31);
スケジュール５−３＝WaitForSingleObject(e22); taskY_CLK(1); taskY_CLK(3); 
SetEvent(e32);
スケジュール５−４＝WaitForSingleObject(e31); WaitForSingleObject(e32); 
taskW_CLK();
【００６９】
このように、多重度の数だけ存在するタスク本体関数をインデックス指定して、各ＣＰＵに分配することにより、利用可能なＣＰＵ数に応じてスケジュールを作成することができる。
【００７０】
（ＣＤＰプログラムの性能）
上述のＣＤＰプログラムの性能は、プログラムを代表するタスクのスループットＰ（tps）として、以下の式で求めることができる。
【００７１】
【数２】
0005465745.tif 000004
【００７２】
mはタスクの多重度（同一機能を有するタスクの数）、ｃは一単位処理あたりに呼ばれるタスク本体関数の数(Clocks Per Transaction：ＣＰＴ)、ｆはプログラム駆動周波数（タイマーの周期Ｔの逆数）であり、ここで、周期Ｔを保ってタスク本体関数を呼び出すために、デューティ率は１未満である必要がある。
【００７３】
図２に記述されるtaskAのように、ＣＰＴが変動する場合、平均値を用いる。taskAは、前述のように、固定回数のループを周期的に実行することにより、不定回数のループを実現する。本実施形態では、stateがcalc2の場合にＦ（ｘ）yを計算するが、図２の行番号L62に示されるように、calcメソッドの第２引数yにより指定される不定回数のループを、定数LIMITにより指定される上限で周期的に実行する。
【００７４】
従って、１≦y≦１０１の場合、タスク本体関数は、stateがcalc1で１回、stateがcalc2で１回、合計２回呼ばれ、ＣＰＴは２となる。１０１≦y≦２０１の場合、タスク本体関数は、stateがcalc1で１回、stateがcalc2で２回、合計３回呼ばれ、ＣＰＴは３となる。例えば、ＣＰＴが２となる確率が５０％、ＣＰＴが３となる確率が５０％の場合、ＣＰＴは２．５となる。
【００７５】
ＣＤＰでは、デューティ率が１未満である限り、プログラム駆動周波数ｆに比例するスループットを保証することができる。ＣＤＰでの実行環境の性能差は、デューティ率の差として現れる。プログラムを同一のプログラム駆動周波数で実行する場合、低速ＣＰＵでは、高速ＣＰＵと比べてデューティ率が高くなる。しかし、デューティ率に差はあっても、同一のプログラム駆動周波数であれば、性能は同じである。
【００７６】
（周期的なタイマーによりプログラムを処理する方法）
次に、図１８のフローチャートを参照して、本実施形態に係る周期的なタイマーによりプログラムを処理する工程を説明する。周期的なタイマーによりプログラムを処理するための事前準備として、前述したＣＤＰプログラムを作成し、当該ＣＤＰプログラムを処理するコンピュータのメモリに格納する必要がある。ＣＤＰプログラムは、（タスクの記述）の章で詳述したタスクプログラムと、（スケジュールの作成）の章で詳述した実行プログラムとを含む。
【００７７】
本実施形態では、図２のタスクプログラムtaskAおよび図３のtaskBと、図１９に示される、taskAおよびtaskBを実行する実行プログラムがメモリに格納されているものとする。
【００７８】
ステップＳ１で、リセット関数の呼び出しを実行プログラムから受け取り、タスクプログラムの内部変数を初期化する。本実施形態では、図１９の行番号L21に示されるtaskAのリセット関数の呼び出しを受け、taskAの状態を示す内部変数taskA_data.stateをfreeに初期化する。また、同図の行番号L22に示されるtaskBのリセット関数呼び出しを受け、taskBの状態を示す内部変数taskB_data.stateをstate_10に初期化し、計算に用いる内部変数taskB_data.aおよびtaskB_data.bに実行プログラムの引数で指定されたｘおよびｙを格納する。
【００７９】
ステップＳ２で、タイマーの周期、およびタスクプログラムのタスク本体関数を呼び出す第１の関数を含むタイマー設定要求を実行プログラムから受け取り、タイマーの周期およびタイマーイベントハンドラーを設定する。本実施形態では、図１９の行番号L24に示されるように、タイマーの周期を１００ミリ秒に設定し、タイマーイベントハンドラーとしてOnTimer関数を登録する。
【００８０】
OnTimer関数では、図６のＰＥＲＴ図の先行関係に基づいて、taskA、taskBの順でタスク本体関数を呼び出す。
【００８１】
ステップＳ３で、タイマーの周期で第１の関数を呼び出すことにより、タスク本体関数を呼び出し、呼び出されたタスク本体関数において、状態を示す内部変数に対応する処理を実行する。本実施形態では、taskBのリセット関数呼び出し時に、実行プログラムの引数により、ｘ＝５、ｙ＝３が指定されているものとする。
【００８２】
（タイマー周期１回目）第１の関数であるOnTimer関数を呼び出すことにより、まず、taskAの本体関数を実行する。taskA_data.stateはfreeなので、何もすることなくtaskAの本体関数は終了する。次にTaskBの本体関数を実行する。taskB_data.stateはリセット関数により、state_10に初期化されているので、taskAに処理を要求するインタフェース関数calcを呼び出す。taskAのインタフェース関数calc呼び出し時に、本実施形態では、taskA_data.stateはfreeである。したがって、taskAのインタフェース関数calcにおいて、taskA_data.stateにcalc1が設定され、taskA_data.xおよびtaskA_data.yに、それぞれ５、３が格納される。そして、taskAに対する処理要求の受け入れにより、taskB_data.stateにstate_11が設定される。
【００８３】
（タイマー周期２回目）再度、第１の関数であるOnTimer関数を呼び出す。taskAのタスク本体関数が呼び出され、taskA_data.stateがcalc1であるので、Ｆ（ｘ）が計算され、taskA_data.stateにcalc2が設定される。次に、taskBのタスク本体関数が呼び出され、taskB_data.stateがstate_11であるので、taskAに処理結果を要求するインタフェース関数get_resultを呼び出す。taskAのインタフェース関数get_result呼び出し時に、taskA_data.stateがcalc2であるので、処理が終わっていないことを示す戻り値が返される。
【００８４】
（タイマー周期３回目）再度、第１の関数であるOnTimer関数を呼び出す。taskAのタスク本体関数が呼び出され、taskA_data.stateがcalc2であるので、Ｆ（ｘ）yが計算される。ここでは、ｙ＝３であるので、本タイマー周期でcalc2に対応する処理は完了し、taskA_data.stateにfinが設定される。次に、taskBのタスク本体関数が呼び出され、taskB_data.stateがstate_11であるので、taskAに処理結果を要求するインタフェース関数get_resultを呼び出す。taskAのインタフェース関数get_result呼び出し時に、taskA_data.stateはfinである。したがって、taskAのインタフェース関数get_resultにおいて、taskA_data.stateにfreeを設定する。そして、taskBの本体関数では、taskAからの処理結果の受け取りにより、taskB_data.stateにstate_12が設定され、周期実行の終了を指示するために、endにより特定されるEvent Objectをシグナル状態にする。
【００８５】
タイマー周期３回目の結果、図19の行番号L25のループ継続条件が偽になり、main関数の制御は、L31に移る。最後に、ステップＳ４で、タスクプログラムに処理結果を要求するインタフェース関数の呼び出しを実行プログラムから受け取り、処理結果を取得する。本実施形態では、taskBに処理結果を要求するインタフェース関数get_resultBの呼び出しを実行プログラムから受け取る。taskBのインタフェース関数get_resultB呼び出し時に、taskB_data.stateはstate_12である。したがって、実行プログラムはtaskBから計算結果を取得することができる。
【００８６】
このように、タイマーにより、定められた一定の処理を実行し、それが終了すると、次にタイマーにより駆動されるまで休むよう動作するプログラムを処理する。上述した実施形態において、１≦y≦１０１の制約を課した場合、ＣＰＴは３となり、デューティ率が１未満である限り、数２の式より、１／３×ｆ（タイマーの周期Ｔの逆数）のスループットを保証することができる。システムとしての性能保証を実現することができるので、サービスの提供者は、性能保証のために余分な設備を保持する必要はない。さらに、ソフトウェアの開発段階において本発明の特徴を有するプログラムを構成するだけで、求められる性能保証の変更にも、迅速に、的確に対応することができる。
【図１】
0005465745.tif 000005
【図２】
0005465745.tif 000006
【図３】
0005465745.tif 000007
【図４】
0005465745.tif 000008
【図５】
0005465745.tif 000009
【図６】
0005465745.tif 000010
【図７】
0005465745.tif 000011
【図８Ａ】
0005465745.tif 000012
【図８Ｂ】
0005465745.tif 000013
【図９】
0005465745.tif 000014
【図１０】
0005465745.tif 000015
【図１１Ａ】
0005465745.tif 000016
【図１１Ｂ】
0005465745.tif 000017
【図１２】
0005465745.tif 000018
【図１３Ａ】
0005465745.tif 000019
【図１３Ｂ】
0005465745.tif 000020
【図１４】
0005465745.tif 000021
【図１５】
0005465745.tif 000022
【図１６】
0005465745.tif 000023
【図１７】
0005465745.tif 000024
【図１８】
0005465745.tif 000025
【図１９】
0005465745.tif 000026