MYOS のスケジューラーは SMP に対応しています。
つまり、 CPU を 100% 使おうとする重いタスクが2個あった場合、合計で 200% ほど使うことができるわけです。
これがシングルコアだったら 100% を仲良く分け合って 50% しか使うことができません。
マルチコアすごいですね。
ところで CPU を 100% 使おうとするタスクが1個だけだった場合、どうなるでしょうか?
なんと、 90% くらいで頭打ちになってそれ以上使うことができません!
実はこのような奇妙なバグが以前から放置されていたので修正します。
優先度とプリエンプション
MYOS では優先度ベースのプリエンプティブマルチタスクをサポートしています。
優先度の高いタスクはより多くの CPU 実行時間を割り当ててもらうことができますが、自分より優先度の高いタスクがキューにあったら優先度の低いタスクは優先度の高いタスクに CPU を譲るしかありません。 また、優先度が同じタスクが複数あった場合、一定時間実行した後にタイマー割り込みでスケジューラーがキューにある次のタスクを順番に実行します。 そして、他のすべてのタスクが実行キューになかった時はアイドルタスクが実行されて次の割り込みまで CPU を一時休眠させます。
優先順位の逆転 Priority Inversion
ところで、自分が一番優先度が高くて他にライバルになるタスクがいなかった場合どうなるでしょうか?
この場合も同じようにタイマー割り込みでスケジューラーが起動します。 そして、まだタスク切り替えが行われていないので自分自身はまだキューに存在しません。つまり、自分と同じ優先度のキューには誰も待っていないことになります。 そうすると、スケジューラーは次の優先度のキューを探しに行って実行可能なタスクが見つかるまでキューを探します。ここで優先順位の逆転現象が発生します。 最後に誰も見つからなかったらアイドルタスクを実行し、アイドルタスクでタイマー割り込みが発生してスケジューラーが起動した時には以前実行していたスレッドはキューに戻されているので再度実行されます。
このようにして CPU を奪い合うライバルがいないはずなのに CPU を 100% 使い切ることができません。 これが謎の 90% の正体です。
CPU を 100% 使うタスクが2つ以上ある場合はいい感じにキューにタスクが積まれてすぐに実行されるので、1つの場合よりも多くの CPU 時間を使うことができるようになっていました。
修正
というわけで、優先度の判定と次に実行するタスクを決める処理を修正して、実行キューに他に待機してるタスクがない場合はプリエンプションを抑制するようにしました。
これで、ひとつのタスクだけで CPU をほぼ 100% 使うことができるようになりました💪