タスクスケジューラのCPU負荷の見積もり

Aug 23 2020

まず、ここでどのタグが最適かわからず、スケジューラーなどに関連するタグが見つからないようです。適切なタグでない場合はお知らせください。

loop()の関数を介して呼び出され、関数ポインター(「タスク」)を選択して実行する、シンプルでポータブルなタスクスケジューラ(millis()のみに依存し、Arduinoがサポートするさまざまなシステムで実行されます)があります。 )ステータス、スリープ、および優先度情報を含むタスクのリストから。

タスクの実行とアイドル状態のどちらに費やされているCPU時間を決定し、ユーザーに通知する方法が必要です。

問題は、スケジューラーだけでなく、loop()から呼び出される他の関数が存在する可能性があることです。したがって、合計時間とタスクに費やされた時間の関係を追跡することはお勧めできません。そうすると、loop()内の他のタスクがCPU時間の一部を静かに使用するため、実際のタスク時間はすべてのCPU時間を使用できないため、CPU使用率は常に低くなります。

ただし、スケジューラーでの時間とタスクで費やした時間を具体的に追跡すると、新しい問題が発生します。これまでの合計、その反復の現在のランタイムを追跡する必要があるため、より多くのメモリ(数バイトですが、すでに多くを使用しています...)とCPU *を使用します。スケジューラー。これは、タスクの実行時間を決定する同様の構成の上にあります。ただし、主に問題は、loop()関数とスケジューラーが十分に高速に実行されるため、millis()タイマーがスケジューラーとloop()関数の間の切り替えよりも遅くなる可能性があることです。これにより、タイミングもオフになります。これは、主にloop()の障害であったとしても、スケジューラーでティックが発生した場合にカウントされるためです。

CPU時間を計算するための一般的な方法はありますか?スケジューラーをタイムスライスするのは難しく、とにかく実行速度が遅くなります。タスクを実行する/実行しないスケジューラー呼び出しの割合を数えることはできますが、タスクが実行されない場合に発生するno-opよりもタスクに時間がかかり、タスクの長さを考慮しないため、それは機能しません。

* AVRシステムでは、8ビットCPUは、スリープ時間の計算(公平を期すために、スリープタスクのみ)と以前のCPUに入力された経過時間の計算の間で、これらすべての32ビット操作に驚くべき合計時間を使用します。使用試行。それだけが原因ではありませんでしたが、同様の問題のために、スケジューラーをコーディングしようとしたときにかなりのタイミングのずれが見られました。

回答

1 Majenko Aug 23 2020 at 16:49

あなたが持っている唯一の測定基準は時間です。あなたができる唯一のことは、反復/タスク呼び出しでその時間を比較することです。典型的なアプローチは、タスクの「カチカチ」の開始時に時間を記録し、最後にそれを記録することです。次に、そのタスクの合計に差を追加します。

次に、使用率を確認する場合は、それらの合計をシステムの実行時間の合計と比較できます。

合計実行時間は、の形式ですでに実行されているmillis()ので、心配する必要はありません。

各タスクの合計実行時間をマイクロ秒単位で記録するのは簡単ですが、もちろんオーバーヘッドが伴います。どんな戦略をとっても、それは避けられません。それは一種の量子です:測定するという行為は結果を変えます。

「アイドル」タスクを他のタスクと同じように扱う場合(これは通常の方法です。アイドルタスクは何もしないタスクです)、すべてのタスクのすべての時間の合計=(内一定の粒度)タスクスケジューラが実行されている合計時間。millis()それとシステムランタイム()の違いは、で発生している他のことと比較した、スケジューラーの実行時間の割合ですloop()

システムランタイムと比較するmillis()micros()、システムランタイム用にするかはあなた次第です。micros()タスクごとに保存することで、各タスクの実行時間に対して妥当な解像度が得られます(ただし、ラップするまでの時間には制限がありますが、必要に応じて別の低解像度カウンターに持ち越すことで、ソフトウェアで処理できます)。次に、その時点で必要がない場合は、計算を行うときにその解像度の一部を破棄します。

このような協調マルチタスクシステムのランタイムを見積もることは決して良いことではなく、そのために気にしないことがよくあります。測定はタスクの実行と同期しているため、測定によって結果が歪められることは常にゲストです。

適切なコンテキスト切り替えマルチタスクシステムでは、通常、時間どおりではなく、システムの「ティック」の数を操作します。つまり、コンテキストスイッチャーによってタスクが切り替えられるたびに1を数えるだけです。各タスクにはスケジューラーの粒度によって制御される固定ランタイムがあるため、タスクXがX / TOTAL_TICKS%の時間実行されていることを知るのは簡単です。すべての計算は、それ自体がタスク(アイドルタスク、またはシステムアカウンティングタスク)で実行されます。

JRobert Aug 23 2020 at 20:27

「アイドル状態」を表示するために私が知っている最も安価な(あらゆる意味での)方法は、スケジューラーに入るときに出力ピンを設定し、タスクをディスパッチするときに再びクリアすることです(アイドルタスクがある場合はそれ以外)。または、代わりに負荷を表示する場合は、これを逆にします。これらは、それぞれ1つの命令で実行できます。メモリ、実行時間、組み立て時間、およびウォレットへの影響が少ない。

これをどの程度正確に報告しますか?

  • 出力のLEDは、負荷に応じてフェードして明るくなります。ダンピングが必要な場合(おそらく負荷が短く「ピーク」)、RCフィルターをLED回路に追加します。

  • DVM、またはそれが見つかった場合は機械式VOMを出力に接続し、メーターから負荷を読み取ります。機械式メーターはあなたのためにいくらかの減衰をします。DVMには、おそらく前の提案のフィルターが必要です。

  • フィルタリングされた出力をループしてアナログ入力に戻し、負荷を約0.1%の精度で読み取ります。それは正当化されるよりもはるかに重要なので、あなたが適切と思うようにそれを丸めてください。