C言語関係掲示板

過去ログ

No.1051 CPU負荷率を求めるには

[戻る] [ホームページ]
No.13686

CPU負荷率を求めるには
投稿者---とおり(2004/04/22 11:45:56)


SH2を使った組込みプログラムをしています。
いろいろと機能を追加していくと、今まで安定して動いていた通信機能が不安定になってしまいました。
優先順は、A/D変換割込み>タイマ割込み>通信割込み>メインループ、となっているのですが、
原因は、通信より優先される処理に時間を取られて受信データ処理が間に合ってなかったからでした。
こんなことがあったので、CPUの余力を知りたいと思うようになりました。

プログラムは以下のような考え方で組んでいます。
・タイマ割り込み:10ミリ秒ごとに処理要求フラグを立てる
    if ( /*10ms経過?*/ )
        proc_req |= INTERVAL_10MS;
・メインループ:処理要求フラグが立っていれば処理してから落とす
    while ( 1 ) {
        if ( proc_req & INTERVAL_10MS ) {
            /* 10ms間隔の処理をここに記述   */
            proc_req &= ~INTERVAL_10MS;
        }
    }
負荷率を求める方法を自分では以下のように考え、実装してみました。
・CPUが暇なときは、メインループをなにも処理せずぐるぐる回っている
・忙しいときは回る回数が減るはず
・クロック周波数は28636360Hzなので1秒間に28636360命令こなせるはず
・負荷ゼロをwhile(1){loop_counter++;}と定義し、このコードは4命令だった
・負荷ゼロの時に10ミリ秒でカウントされる値は71590
・10ミリ秒ごとに負荷率を算出し、カウントをクリアする
    #define     CPU_CLOCK       28636360
    #define     LOAD_ZERO       4
    #define     COUNTMAX_10MS   (CPU_CLOCK / LOAD_ZERO / (1000 / 10))
    short cpu_load;         /* CPU負荷率(0.01%単位) */
    long  loop_counter;
        while ( 1 ) {
            loop_counter++;
            if ( proc_req & INTERVAL_10MS ) {
                cpu_load = (short)((COUNTMAX_10MS - loop_counter) * 10000 / COUNTMAX_10MS);
                loop_counter = 0;
                proc_req &= ~INTERVAL_10MS;
            }
        }
これでやってみると98.00%あたりの値が算出されました。
どうも考え方が間違っている気がしてなりません。

いい算出方法を教えていただけると助かります。
よろしくお願いします。



No.13688

Re:CPU負荷率を求めるには
投稿者---あかま(2004/04/22 12:04:36)


んーそんなに詳しくはないし解決策でもないけど。

・クロック周波数は28636360Hzなので1秒間に28636360命令こなせるはず
これは間違いだと思う。1クロック1命令では無いはず。
CPUの種類や命令ごとに必要なクロック数は変わります。

・CPUが暇なときは、メインループをなにも処理せずぐるぐる回っている
・忙しいときは回る回数が減るはず
例えば処理AがCPUを80%独占している状態でこのプログラムが実行されて
OSがCPUを50:50に振り分けてしまったら、処理Aの負荷って変わりますよね。
そういった場合正しい負荷の計測はできないのでは。






No.13689

Re:CPU負荷率を求めるには
投稿者---jacta(2004/04/22 14:48:38)


>・クロック周波数は28636360Hzなので1秒間に28636360命令こなせるはず
>・負荷ゼロをwhile(1){loop_counter++;}と定義し、このコードは4命令だった
>・負荷ゼロの時に10ミリ秒でカウントされる値は71590

この辺りがちょっとおかしいようです。
SH2の場合、乗算のような一部の命令を除いて、1命令1クロックで実行されます。実験されたコードのキャッシュ・ヒット率は十分に高いでしょうから、概ねそれは正しいのですが、分岐命令には3クロックかかるはずです。そのうち1クロック分は遅延スロットですから、実質2クロックでしょうか。
次に、負荷ゼロの定義が間違っています。カウンタのインクリメントより、if文の処理(volatile変数のリード、AND演算、条件分岐)の方が時間がかかるはずです。ざっと数えると全部で10クロック程度ありそうです(コンパイラによります)。
.L2:
	mov.l	@(4,r14),r1
	add	#1,r1
	mov.l	r1,@(4,r14)
	mov.l	.L12,r1
	mov.l	@r1,r0
	and	#1,r0
	tst	r0,r0
	bt	.L2
	mov.l	.L7,r2

.L12:
	.long	_proc_req
.L7:
	.long	71590

あと、(COUNTMAX_10MS - loop_counter) * 10000の部分ですが、簡単にオーバーフローしてしまいます。



No.13691

Re:CPU負荷率を求めるには
投稿者---pi-ta(2004/04/22 15:20:38)


こんにちはpi-taです。
まず、申し訳ないのですが、本来のあなたの求めている回答ではありません。

>・CPUが暇なときは、メインループをなにも処理せずぐるぐる回っている
>・忙しいときは回る回数が減るはず
>・クロック周波数は28636360Hzなので1秒間に28636360命令こなせるはず
いいえ、SH2は基本命令の場合、1命令を1ステートで行います。
で、1ステートは内蔵のメモリアクセスの場合は1クロック、外部メモリの場合は
2、または3クロックです。
外部メモリの場合、ノーウェイトではなくウェイトが入る場合が多いですが、
その場合ですとさらにクロック数は増えますし、アイドルサイクルも考慮する必要
があります。
当然基本命令以外の場合は、1クロックでは動作しませんので上記の定義は間違って
います。
おまけに5段ですがパイプラインも持っていますので、前後の命令の並びなどでも
実行速度は変化します。

SH2クラスですとRTOSを使用する場合が多いので、その場合にはOSによる
タスク切り替えも考慮しなければなりません。

ソフトウェアだけでCPUの負荷率はそんなに簡単には求めることはできません。
たとえば、あるポート出力をメインループ一周ごとに反転させれば、
一定時間ごとのポートの変化数はCPUの負荷状態に反比例しますけどね。

ただ、そんなことに時間を費やすより、元の不安定要因を取り除く努力をした方がよろしいかと思いますが。



No.13699

Re:CPU負荷率を求めるには
投稿者---nop(2004/04/23 00:33:10)


まず、CPUの負荷率は メインに無限ループが存在する時点で100%になります。

# 割り込みが無いときはメインループが
# 割り込み中は割り込み処理がそれぞれ動作しているはず
# = CPU は常に動作している
## Windows のタスクのイメージでも持っておいでなのでしょうか?

なので、CPU の負荷率を求めるのは無駄でしょう。
アルゴリズムの見直しを行い、高速化に勤める方が賢明と言えるでしょう。


>優先順は、A/D変換割込み>タイマ割込み>通信割込み>メインループ、となっているのですが、
>原因は、通信より優先される処理に時間を取られて受信データ処理が間に合ってなかったからでした。

この優先順位の付け方には疑問を感じます。
なぜなら、「タイマ割り込み」は一定周期で動作させるために使うはずなので、
この「タイマ割り込み」の割り込みタイミングがずれるのは大問題です。
そして、その一定周期で行う処理はタイマ割り込みのインターバル未満である必要があります。

通信に支障をきたすなら、この一定周期の処理がタイマインターバル以上の時間が掛かっていることが予想されます。
一度、タイマ割り込み内の処理を見直してみては如何でしょうか?



No.13718

Re:CPU負荷率を求めるには
投稿者---とおり(2004/04/24 03:17:26)


通信の不安定原因がわかり、解決するにはA/D割込みとタイマ割込みを高速化しなくてはいけなくなり、
どれくらいすればいいのかの目安が欲しくて今回の質問をしました。
でも難しいようですね。
A/D割込み・タイマ割込み・通信割込みが同時に発生したときに9600bps時間中にA/D割込みとタイマ割込み
が完了すれば問題ないはずなので、この時間を目安にして高速化してみます。

皆さん返信ありがとうございました。



No.13719

Re:CPU負荷率を求めるには
投稿者---pi-ta(2004/04/24 10:17:13)


もう、見てないかな。

>A/D割込み・タイマ割込み・通信割込みが同時に発生したときに9600bps時間中にA/D割込みとタイマ割込み
>が完了すれば問題ないはずなので、この時間を目安にして高速化してみます。

その他にも、通信割り込みそのものの時間も注意しておいた方が良いです。
あと、RTOSを使用しており、割り込みの処理をOSに任せているときはオーバーヘッドがばかになりません。

ただ、SH2を28636360Hzで動作させて9600bps程度の通信でトラブルのは、もっと別な要因のような気がします。

現在私もSH2がらみのプロジェクトを担当していますが、

SH2/7145F 29MHz動作 RTOS使用
割り込みは、シリアルポート送受信割り込み×3、通信速度は38400bps。(1ポートのみ115200bpsへ動的に変更)
I2CBus割り込み、タイマー割り込み(1msec)、IRQ3割り込み。
各割り込み優先順位は同一で、かつ全ての割り込みが1秒に1回以上同時に発生することが多々あり。

といった条件で使用しており、通信でトラぶったことはありません。
高速化ばかりではなく、もっと広く原因を探った方がよろしいのでは?
仮に、通信割り込みの優先順位を最上位に持ってきて、確認するのもいいと思います。

ちょっと板違いな内容になってしまって済みません。 >管理人さん


No.13743

Re:CPU負荷率を求めるには
投稿者---とおり(2004/04/25 13:50:16)


まず、板違いすいません。

> その他にも、通信割り込みそのものの時間も注意しておいた方が良いです。

たしかに必要ですね。考えが抜けてました。

> あと、RTOSを使用しており、割り込みの処理をOSに任せているときはオーバーヘッドがばかになりません。

マイコンプログラムでのOSというものがよくわかっていないのですが、たぶん使っていません。
関係あるかわかりませんが、スタートアップやベクタテーブルもコーディングしています。

> ただ、SH2を28636360Hzで動作させて9600bps程度の通信でトラブルのは、もっと別な要因のような気がします。

考えてみると、9600bpsだと通信割込み(1バイト受信ごとに発生)に大体1ミリ秒も間隔があるんですね。
たしかに別の要因があるような気もしてきました。

各割込みで行っている処理を自分への整理を兼ねて補足します。
電気関係機器の為のプログラムです。
[A/D変換割込み]
・SH2内蔵A/Dを2つ、外付けA/Dを1つ使用
・その3つに4x3=12ヶ所のセンサー検出値を入力(4は1つのA/Dに入力可能な数)
・割込み周期は、45〜65Hzの1波形を180分解する周期(周波数によって動的に変化)
・つまり、最悪(1/(65x180))x10^6=85マイクロ秒周期
・各A/D変換値をXXX_ad_que[180]に格納
・各全加算値をXXX_ad_totalに算出(直流:移動平均値,交流:ゼロ点値)
・交流は以下処理を引き続き行う
・各A/D変換値と各ゼロ点値とサイン・コサインテーブルを使い有効・無効分に分解(d-q軸変換)
・各有効分をXXX_d_que[180]に、無効分をXXX_q_que[180]に格納
・各全加算値をXXX_d_totalとXXX_q_totalに算出(移動平均値)
[タイマ割込み]
・割込みは2ミリ秒周期
・移動平均値にゲインとオフセットを掛けて計測値算出
・計測値をフィードバックとして使った自動制御(多数)
・メインループへの時間隔処理要求フラグセット
[受信完了割込み]
・ボーレートは9600bps
・受信データを受信キューへ格納し、受信完了フラグをクリア

質問したことによって問題点が整理できました。
これをもとに調査を進めてみます。
ありがとうございました。



No.13761

Re:CPU負荷率を求めるには
投稿者---nop(2004/04/25 23:15:05)


>スタートアップやベクタテーブルもコーディングしています。

基本的なことを聞きますが、割り込み発生時に各レジスタ値の待避(PUSH)、
割り込み処理後に各レジスタ値の復帰(POP)は行ってますよね?


No.13762

Re:CPU負荷率を求めるには
投稿者---とおり(2004/04/26 00:23:55)


> 基本的なことを聞きますが、割り込み発生時に各レジスタ値の待避(PUSH)、
> 割り込み処理後に各レジスタ値の復帰(POP)は行ってますよね?

C言語関数を割込みとして使うときは、
#pragma interrupt(IntervalTimer)
void IntervalTimer(void)
{
    ...
}
と、#pragma指令付きで関数定義することになっています。
アセンブラソースを出力させて見てみないことにははっきりとは言えませんが、
おそらくこの#pragma指令によってレジスタ退避・復帰コードが埋め込まれていると思われます。



No.13764

Re:CPU負荷率を求めるには
投稿者---pi-ta(2004/04/26 01:25:42)


>おそらくこの#pragma指令によってレジスタ退避・復帰コードが埋め込まれていると思われます。

コンパイラはHEWでしょうか?
上記の件は問題ありません。

それよりも、
> [A/D変換割込み]
> ・SH2内蔵A/Dを2つ、外付けA/Dを1つ使用
> ・その3つに4x3=12ヶ所のセンサー検出値を入力(4は1つのA/Dに入力可能な数)
> ・割込み周期は、45〜65Hzの1波形を180分解する周期(周波数によって動的に変化)
> ・つまり、最悪(1/(65x180))x10^6=85マイクロ秒周期
> ・各A/D変換値をXXX_ad_que[180]に格納
> ・各全加算値をXXX_ad_totalに算出(直流:移動平均値,交流:ゼロ点値)
> ・交流は以下処理を引き続き行う
> ・各A/D変換値と各ゼロ点値とサイン・コサインテーブルを使い有効・無効分に分解(d-q軸変換)
> ・各有効分をXXX_d_que[180]に、無効分をXXX_q_que[180]に格納
> ・各全加算値をXXX_d_totalとXXX_q_totalに算出(移動平均値)
> [タイマ割込み]
> ・割込みは2ミリ秒周期
> ・移動平均値にゲインとオフセットを掛けて計測値算出
> ・計測値をフィードバックとして使った自動制御(多数)
> ・メインループへの時間隔処理要求フラグセット

この内容を見ると、割り込み処理ルーチン内の作業にしては負荷がかかりすぎです。
もし上記の処理の中で実数演算を行っているのであれば、DSP内蔵型のSH2でない限り
処理時間は間に合わないでしょう。

当初より仰っていたように、A/D割込みとタイマ割込み時間が他の処理を圧迫しているようですね。
ただ、割り込み優先順位の高い処理は、できるだけ速やかにその処理を終えるようにしないといけません。
ですので、通信処理をできるだけ高速化してやり、この割り込みの優先順位を上げてみてはいかがでしょうか?



No.13774

Re:CPU負荷率を求めるには
投稿者---とおり(2004/04/26 17:32:41)


> コンパイラはHEWでしょうか?

HIM(Hitachi Integration Manager)です。

> この内容を見ると、割り込み処理ルーチン内の作業にしては負荷がかかりすぎです。

処理を羅列してみて改めて重そうだと実感しました。

> もし上記の処理の中で実数演算を行っているのであれば、DSP内蔵型のSH2でない限り
> 処理時間は間に合わないでしょう。

実数演算は一切行っていません。

> ですので、通信処理をできるだけ高速化してやり、この割り込みの優先順位を上げてみてはいかがでしょうか?

なぜか「今の優先順位のままなんとかしなければいけない」という考えに捕らわれていました。
たしかに通信完了割込みは、
> ・受信データを受信キューへ格納し、受信完了フラグをクリア
たったこれだけしかしていないのだから、優先順位を上げても他の割込みへの影響は少なそう。

十分に検討し、この方向で進めてみようと思います。
アドバイスありがとうございました。