HILS高速化(1)マルチレート
今回から数回に分けて、HILS高速化のための方法をご説明します。
いま持っているHILSのパフォーマンスを上げたい。でも、どうやっていいのかがよく分からない、という場合があります。そういう時は、まずHILS高速化のための基本的な概念を理解する必要があります。そうすれば、どんな手を打てばHILS高速化ができそうかイメージが湧いてくるようになります。
さて、HILSのボトルネックは何と言ってもモデルの演算時間です。HILSを高速化するには、演算速度を向上させる必要があります。そのためには、基本的にCPUを高速化するしかありません。
CPUの高速化といってまず思い浮かぶのは動作クロックです。しかこれは、もう頭打ちになっていてこれ以上の向上は望めなさそうです。
次に思い浮かぶのは64ビット化です。これはかなり強力で、同じモデルでも32ビットマシンと64ビットマシンとでは全然スピードが違います。
これらの事はもうやりつくされていますので、最近は並列化に傾いています。とにかくコア数を増やす事で、全体のスピードを稼ぐ方向に向かっています。
そこで、この並列化の流れに着目しつつ、Simulinkモデルと並列化との間にはどんな関係があるのかについて、ご説明します。今回は、ほとんど全てのHILSで使えるテクニックのご紹介です。
2つのムダ
HILS高速化のためには、まずはムダを省いていく必要があります。そのためにまず、HILS装置においてどのようなムダが発生しているのか理解しましょう。
HILSはハードリアルタイムで動いています。(ハードリアルタイムについては、前回の記事をご参照ください。) そのために、実はCPU時間に無駄が生じています。
とあるステップにおける処理が終わったとします。処理がおわったのだから、どんどん次にの処理に取りかかればCPU時間の無駄にはなりません。しかし、そうしてしまうとリアルタイムでは無くなってしまいます。そのため、待機時間が入ってしまうのです。これが、1つ目のムダです。
2つ目のムダは、マルチコアの場合に起きます。せっかくコアが複数あるのに、「モデル演算に使うコアが1つだけ」という事になると、1つのコアが丸々ムダになってしまっています。
実は、これらのムダは、モデルをマルチレート化する事で解消できます。マルチレート化とは、たとえばモデルを「1ms毎に処理しないといけない部分」と「10ms毎に処理すればいい部分」とに分割することです。
もちろん、モデルの全ての部分を1ms毎に処理しないといけないのであれば、どうしようもありません。しかしそうではなく、「この部分は、絶対に1ms毎に処理しないといけない」「この部分は、別に10ms毎でもいい」という風に分離できるのであれば、マルチレート化する事ができます。
たとえば、こんな感じで分離したとします。すると、マルチレート化による恩恵が受けられ、処理が高速化される可能性があります。どうしてそういう事になるのか、詳しく見て行きます。
マルチレート:SingleTasking
「マルチレート化」と「高速化」にどんな関係があるのか理解するために、「マルチレート」について詳しく見て行きましょう。「マルチレート化」には2種類あります。それは「SingleTasking」と「MultiTasking」の2つです。まずこの章では、「SingleTasking」のマルチレートについて見て行きます。
まず2種類のマルチレート化のうち、いずれの場合においても言える事ですが、遅いレートに属する部分を増やせば間違いなくCPU負荷は減ります。それは、たとえばベースレートが1msだったとすると、「サンプルレート=10ms」の部分が、
マルチレート前=>10ms間に10回実行
マルチレート後=>10ms間に1回実行
というように、実行回数が確実に減るからです。しかし、だからといってその分余計に処理を出来るようになる訳ではありません。
これがどういう訳なのか理解するために、2種類のマルチレートについて理解しましょう。これは、モデルのソルバ設定の「周期的なサンプル時間のタスクモード」の設定に依存します。まずは、そんなに高速化に寄与しない方のマルチレートについて見て行きます。
この設定をSingleTaskingに設定すると、高速化にはあまり寄与してくれませんが、比較的安定動作してくれます。このモードを選ばないとモデルをコンパイル出来ない場合もあるため、仕方なくSingleTaskingに設定する場合もあります。
さて、SignleTaskingを選択した場合には、1msの処理、10msの処理、ともに1つのスレッドで実行されます。
このように、1msの処理、10msの処理を直列に実行されるようになっています。RTWで生成されたCコードを見てみると、blog_multirate_update関数だけで、全てのレートの処理を行うようになっています。そのため、もしも10ms部分の処理が長引いたとしたら、オーバーランが発生してしまいます。
HILSとはリアルタイムシステムですから、たとえ10msに1回であろうともオーバーランが出てしまえばアウトです。そのため、SignleTaskingを選択した場合には、CPUコアが1つだろうが複数あろうが関係なく、とにかくあまり高速化してくれません。
マルチレート:MultiTasking
次に、2つ目のマルチレートについて見て行きます。そうすることで、SingleTaskingの場合の制約を超えて「より高速化」するための原理が理解できます。
2つ目のマルチレートとは、モデルのソルバ設定の「周期的なサンプル時間のタスクモード」をMultiTaskingにした場合です。このモードは高速化しやすいのですが、モデルの作り方が悪いとエラーが出やすくなっています。そのため、モデルの作り方に十分注意する必要があります。
さて、このモードでは、1msの処理、10msの処理を別々のスレッドで実行する事ができます。RTWで生成されたCコードを見てみると、blog_multirate_update0関数、blog_multirate_update1関数の2つに処理が分かれています。そのため、別々のスレッドで実行できるのです。
別々のスレッドで実行できると、次のような恩恵をうけられます。
10msの処理が長引いた場合について考えてみます。10msの処理が長引くと、SingleTaskingではオーバーランになってしまいました。しかし、MultiTaskingの場合はそうはなりません。一定時間で処理を終えられなければ、10msの処理はいったん中断します。そして、優先的に1msの処理を行います。1msの処理が終了したら、また10msの処理を再開します。
このように、1ms部分の処理のスキマをぬうように10ms部分の処理を行う事ができるため、CPU処理能力を有効活用できます。結果として、より重い処理をオーバーラン無しに実行できるようになります。
さて、ここまでのMultiTaskingの話は、実はCPUコアが1つの場合の話です。マルチコアの場合にはもっと高速化できます。マルチコアであれば、1msの処理、10msの処理を別々のコアに割り当てられます。そうすると、1msの処理、10msの処理が完全に並列実行されます。そのため、かなりの高速化が実現できます。
HILSに依存します
ここで1つだけ注意点を。
MultiTaskingにおける高速化の話は、実はHILSに依存します。ひょっとしたら、こういった高速化が一切できないようなHILSが存在するかも分かりません。ある程度高性能なHILSであればまず出来るでしょう。このあたりは、HILSシステム依存なので、絶対にこういった事が出来ると言う保証はありません。
なぜなら、RTWは、あくまで各レートの処理を、別々の関数に分けてくれるだけだからです。別々の関数に分けられたのを、きちんと別々のコアに割り当てられるのか、それとも何も考えずに直列に実行してしまうのか、これはHILSのポリシー次第だからです。
次回は
次回は、このマルチレートによる高速化をさらに推し進めた、マルチノードについてご説明します。マルチノードとは、単純に複数のマシンでモデルを並列実行するだけのものです。しかし、1つのモデルを並列に動かそうとしたとたんに、色々な問題に見舞われます。そこで、Simulinkモデルの構造について少し詳しくご説明したあとで、マルチノードによる高速化がどのように行われるのかを見て行きます。