
処理が重くてプログラムが回らないので、どうにかして実行量を下げ
ようとしています。
CPUはSH2(80MHz)、内蔵メモリ(ROM、RAM)と、
外付けのフラッシュROM、RAMがあります。
OSはuItron仕様のRTOSで、プログラムはC(一部アセンブラ)
で記述しています。
作成開始前の想定では、昔、68000の12MHzで動かしていた
ソフトにシリアル通信が少し増えた程度なので、CPUの能力不足で
困るなどとは想像してなかったのですが、CPUは高速化したものの
外付けメモリの速度が足りないので外部のバスアクセスは実質10M
Hz程度しか出ないということが後で分かりました。
内蔵メモリだけで動かせば外部使用時の数倍のパフォーマンスが出る
のですが、容量が少なくてソフト全体の20%ほどしか使えません。
I2Cバス(400kbps)と子局機器とのシリアル通信(115
kbps)がメインなので、これらの割り込み処理だけでも内蔵メモ
リで駆動できないかと模索中です。
他には、関数の引数(スタック待避・復帰の処理量)を減らすなどを
試していますが、これといった効果が出ていません。
ソースは10万行くらいあり、コーディング流儀の微細な変更でも、
”積もれば山”の可能性があります。
何かいい案があったら教えてください。
No.10ベストアンサー
- 回答日時:
私も今月から SH7085 + NORTi を使い始めました.
昔8ビットマイコンを自作したことはありますが,本格的な組込みの仕事は初めてです.
新しい A/D,D/A 変換基板用に別の人が作りかけていたソフトと,
その元になったソフト (別の基板用に基板メーカが作成したもの) を渡されて,
「まずハードウェアの評価をしないといけないので,とりあえず至急これを動かしてくれ」
と言われ,ようやく先日完成しました.
その過程で,あまり効率の良くないコードがたくさん目に付いたので,
製品版のソフトを開発する際には大幅に書き直してやろうと考えています.
以下,改良できそうな点のリストです.組込の専門家には常識と思いますが,
(自分用の備忘録を兼ねて) 一応ご参考まで.
(上記のソフトも組込みの専門家が書いたはずなんですが….
組込みは初めてなので,どの程度効くかはわかりませんし,
間違っているところもあるかもしれません.)
(1) 割込みハンドラに余計な仕事をさせている.
複数のアナログ入力を A/D 変換したデータを多重化し,SSU で受信している (約1ms周期).
その受信割り込みハンドラで,データのチェックとフォーマット変換を行って受信バッファに
書き込んでいた.1ms の割込みハンドラにそんなことまでさせるなよ!
受信データをそのままバッファに書き込んで,あとはデータ収集タスクにやらせりゃええやん!
(2) I/O レジスタを操作するのにビットフィールドを使い,
複数のビットをセット (または複数のビットをリセット) している.例えば,
#define SCI0 ((volatile t_SCI*)0xFFFFC000)
// 受信エラーリセット
SCI0.SCSSR.BIT.ORER = 0; // Overrun Error
SCI0.SCSSR.BIT.FER = 0; // Framing Error
SCI0.SCSSR.BIT.PER = 0; // Parity Error
これでは SCSSR が6回もアクセスされてしまう (read/write 各3回).
I/O レジスタのため volatile が付いており,最適化はされない.
これを次のようにすれば2回のアクセスですむ (read/write 各1回).
SCI0.SCSSR.BYTE &= ~(SCSSR_ORER | SCSSR_FER | SCSSR_PER);
(3) 排他制御
・排他制御の粒度が粗すぎる.受信割込みハンドラが書き込んだバッファの内容をを別の
場所にコピーする間ずっと,バッファ全体を排他制御をしている.これではオーバーラン
エラーが多発するはず.リングバッファであれば,書き込みポインタが読み出しポインタ
を追い越さないようにするだけでいいはず (iTRON でどうやればいいのかまだわからないが).
いやそれ以前に,コピーすること自体を見直した方がよい.
・排他制御すべきコード範囲が非常に短く,すぐ終わる処理ならば,セマフォなどを使わず
一時的に割込み禁止にするだけの方が効率いいはず (マルチプロセッサではないので).
例えば送受信などにリングバッファを使用している部分があるが,リングバッファの排他
制御期間は非常に短くてすむので,これをセマフォではなく割込み禁止で行う.
(4) SH7085 (または SH-2) 固有の問題
・データキャッシュがない
SH7085 には命令キャッシュはあるようだが,データキャッシュはないそうなので,
(特に外部) メモリアクセスの回数を極力減らすことが必要.逆に参照の局所性は問題に
ならず,ランダムアクセスを多用してもペナルティは発生しない (はず).したがって
メモリアクセス順序がランダムになっても (特に外部) メモリアクセス回数を減らす
方法があれば,そうする方がよい.(キャッシュがある場合とは逆)
・除算命令がない
SH-2 には除算命令がない (1ステップ除算命令というのはあるが,これは商の1ビット
だけを計算するものであり,商のビット数分繰り返す必要があるらしい) ので,
特に高速化が必要な部分 (短周期割込み用ハンドラなど) ではできるだけ除算を避ける.
ちなみに上記の 1ms 受信割り込みハンドラでは除算を (複数回) 使用していた.(-_-#)
・乗算命令の問題
SH-2 の乗算命令は2ステート (32bit 乗算の場合) または4ステート (64bit の場合)
で実行されるが,その間パイプラインがストールするうえメモリアクセス競合も発生する
そうなので,使わなくてすむなら使わない方がよさそう.
・シフト命令
・SH-2 にはバレルシフタがない.→ 右辺が定数でないシフト演算子はなるべく避ける.
・SH-2 のシフト命令は,シフト数が 1/2/8/16 のものだけ.
ただし算術シフト命令は1ビット用だけ.
→・シフト演算子の右辺がなるべく 1/2/8/16 になるようにする.
(ビットフィールドの配置を工夫するなど.)
・符号付整数のシフトはなるべく避ける.
・外部メモリ上のバイトまたはワード (2バイト) データのうち,同時にアクセスする
ことが多いものはできるだけ同じ1ロングワード (4バイト) 内にまとめ,1回の
メモリアクセスで読み書きできるようにする.
(ただし SH7085 の外部データバスは 8/16/32 ビットから選択できるようなので,
32ビット・データバスでなければ効果がない.)
(5) (特に多次元) 配列は添字ではなくポインタでアクセスする.
受信バッファとして,チャネル番号,サンプル番号等を添字とする多次元配列が多用され,
それらを添字でアクセスしている.多次元になるほど,添字から配列要素のアドレスを
計算する手間がかかるので,なるべく添字ではなくポインタでアクセスする.
(6) パイプライン的なデータ処理の高速化
A/D 変換したデータに対し,ノイズ除去,移動平均,平滑化などの信号処理をパイプライ
ン的に行っている.これらは別々の関数として実装されており,したがって別々のループ
で処理されるが,わかりやすく再利用しやすい反面,実行速度はイマイチ (のはず).
これらの処理を1つのループに融合し,入力データから一気に最終データまで計算する
方が,途中結果をいちいち (外部) メモリに書き出して後でまた読み込む,ということを
何度も繰り返す必要がなくなる.また,CPU 内の演算パイプラインが効くようになるはず
なので,その分の高速化も期待できそう.
(余談:参照の局所性も高まるので,データキャッシュのある CPU ならさらに効果的.
以前同様のことを画像処理 (多数の画像を演算して1枚の画像を作成する) で行った
ことがある.)
(7) 不必要なバッファコピーが多い.
処理の都合上,受信バッファから最終的な出力バッファの間に中間バッファが存在し,
コピーを複数回行っている.中間バッファを使用せず,受信バッファから直接出力バッ
ファにコピーできないか.
(8) 同じような処理がやたら多い.
多数のバッファのそれぞれについて,それらをリングバッファとして使うためのコード
が書かれている.リングバッファの処理を共通化すれば,コードサイズが小さくなって
ROM の使用量が減るとともに,命令キャッシュの効きが良くなるかもしれない.おまけに
ソースもわかりやすくなるはず.それ以外にも,共通化できる処理はできるだけ共通化する.
(9) 内蔵 RAM (32KB) に配置するデータは極力無駄を省き,できるだけ多くのデータを内蔵
RAM に置けるようにする.ブール型の変数1個に4バイト整数丸ごと使うなんて論外!
調べればまだ他にも改善点が出てきそうですが,とりあえずこの辺で.
色々とありがとうございます。
いくつか期待できそうなので、さっそく試してみます。
で、近況ですが、おかげさまで、いくつか試してなんとか
予定域まで効率の引き上げつつあります。
やったことは、
1)欲しい演算処理を割り込みの中で行う。
下層タスクで演算させると、途中に割り込まれる度にジャンプ処理
とスタック操作に時間を食われて演算完了が遅れるので、いっその
こと他に影響のない範囲で押し込んでしまえばと試したら最終目的
には近づきました。(その分他がとばっちりですが)
2)頻度の多い処理だけを厳選して内蔵ROMに。
デバッグライトをソフト各部に埋め込んで1分あたりの実行回数を
計測し、上位10%を選んで内蔵ROMに詰め込んでみるとかなり
の効果がありました。
今分析結果を基に呼び元の処理を見直し中です。
No.9
- 回答日時:
使ったことはありませんが、シリアル調歩同期にDTC(Data Transfer Controller)を
利用していますか? どうも32byteに1回CPUが処理すればいい(割り込み)みたいです。
Renesasのアプリケーションノートにありました。
URLを参照ください。
参考URL:http://documentation.renesas.com/jpn/products/mp …
No.8
- 回答日時:
>セマフォの資源操作を実行するとカーネルの重い処理が走るのかな
>と考えているのですが、そのへんご存じないですか?
セマフォからのタスクスケジュールは、そのITRONの純粋にスケジューラ
(ディスパッチ)の性能かと思います。
といいますか、セマフォ処理は、あまり工夫しようのない部分ですね。
ミューテックスなら話は別ですが,,,
タイムラグがあるということですが、どの程度なのでしょうか?
ミスポさんはわかりませんが、itronベンダーに問い合わせれば、カーネル
性能データを出してくれるところもあります。最近は、なぜか削除されて
いますが、古いバージョンでは、マニュアルに記載しているものもあります。
ハードウエアに関係せずに純粋に測るならHEWのシミュレータでも
計測できると思います。
それからベンダーによるかもしれませんが、
1)速度をあげたい とか
2)使用メモリを減らしたい
とか要望を出すと、対応したライブラリを出してくる場合があります。
問い合わせみるのもいいかもしれません。
それから、いろいろ対応されているようなので対処済みかもしれませんが、
Nortiのマニュアルに記載がありましたが
「静的エラーチェックしないライブラリ(カーネルのことでしょう)」がある
ようですね。使っていなければ切り替えてみましょう。
No.6
- 回答日時:
タイムティックが、1/1 ms(スタンダードプロファイル標準)なら 10ms程度に
間隔をあけてみるのも負荷を減らせますね。
TIC_NUMEを10程度にするとisig_timの周期が10分の1になります。
ただし、Nortiは、タイムアウトの仕様が厳密に4.0仕様に合致していなかった
ようなので、若干注意が必要かと思います。
ありがとうございます。
うちのシステムの計時周期は10msで、これをいじるのは無理
みたいです。
セマフォ待ちでタスクを休眠させると、待ち解除した時にスケジュ
ーラの定時起動タイミング外でもすぐに起床しますが、パラレルポ
ートから信号出してタイミングを測ると、資源解放から起床までに
少しタイムラグがあります。
セマフォの資源操作を実行するとカーネルの重い処理が走るのかな
と考えているのですが、そのへんご存じないですか?
No.5
- 回答日時:
はずしていると思いますが、自分でもミスった経験あることとしては、
「CPUの分周をセットしていない」とかであれば、いきなり今の4倍で動いたりします。
ですが、外部メモリのボトルネックということで、これはないでしょうね。
次に、微々たる?対応方法についてですが、
ITRONカーネル速度を上げる一般的な方法として(Nortiがそうかはよく知りません)
1)タスク優先度レベルを小さくする。
たとえば、優先度を5飛ばしや10飛ばしで定義している場合
例) タスクA:10 タスクB:20 タスクC:30
できるだけ、最大値を小さく、詰めて定義します。
-> タスクA:1 タスクB:2 タスクC:3
理由:スケジューラのアルゴリズムにもよりますが、優先度別キューの上位から
の検索を行うアルゴリズムなら、優先度200なら200回先頭キューを比較しなければ
スケジュールしない場合が考えられるから。
何ゆえ、最大優先度をコンフュギュレータで指定するかと言うと、固定最大値だと
遅くなるためです。ばかばかしいかもしれませんが、実際これで回避した
ケースの報告を聞いたことがあります。
2)優先度待ち(TA_TPRI)をやめて、できるだけFIFO待ちにする。
優先度待ちのアルゴリズムは大抵先頭から順番に比較するというあまり賢くないもの
です。優先度待ちに多く並んでいた場合にさらに待つとカーネルが多くのCPU時間を
使います。
TOPPERS/JSP FI4もこれです。というよりそうでないものは知りません。
3)周期ハンドラアラームハンドラのID数を減らします。
周期ハンドラの定義数分だけ、isig_tim時に分まわります。(そうでないのもあります,TOPPERSはその辺賢いです)
定義だけというのもやめて必要数だけ生成する。
4)可変長メモリプール使わず、できるだけ固定長メモリプールでサイズを分けましょう
可変長メモリプールのメモリが返されたときのマージ処理は非常に重い場合があります。
5)多重割り込みを禁止できるなら禁止にする。
割り込みハンドラや、周期、アラームハンドラなど、多重割り込みが可能にしてあるなら
禁止にする。そうすることで多重割り込みにかかわる負荷が減ります。ただし、割り込み
処理が逐次処理されるので割り込みが間に合わない場合は禁止できないです。
6)カーネル管理外割り込みを利用する
サービスコールを使わない割り込み処理でいいならカーネル管理外割り込みとすれば
カーネルが動作しない分だけ処理が軽くなります。
ありがとうございます。
1~3は実施済み、4は返却しないのでカーネルに任せず自主管理。
5は間に合わないので無理、6もカーネルを介してません。
TOPPERSはまだ使ったことないんですが、やはり対処は同じような
感じなんですね。
No.4
- 回答日時:
私も#3の回答にあるような原因ではないかと思うのですが...
とりあえず小手先の改善策だけでも書いておきます。
1. スタックを内蔵メモリに配置する。
2. 最適化オプションは、プログラムサイズが「最小」になるように設定する。
3. カーネルやライブラリを内蔵メモリに配置する。
4. 静的記憶域期間のデータには、intやlongではなく、可能な限りshortやcharを使用する。
5. 複数ビットのビットフィールドはなるべく使用しない。
他はソースをざっとでも見ないと判断できませんね。
ところで、外部のバスアクセスが10MHzしか出せないというのは、ハードウェアの設計ミスのような気がします。
No.3
- 回答日時:
なんとなくの印象ですが、
処理を急ぎすぎて、かえって速度を落としているパターンだったりしないかなぁと。
処理を急ぎたいがために、
割込みで実処理を行ってしまったり、
タスクの優先順位を不用意に上げたりして、
かえってパフォーマンスを落としているとか。
割込みで行っている処理というのは、具体的にどんな処理なんでしょうか。
ありがとうございます。
> 割込みで行っている処理
シリアルの送受信レジスタ制御
I2C送受信レジスタ制御は
RS485の送信イネーブルのカット
A/D変換ICの読み出し
メインはこんなところです。
No.2
- 回答日時:
ITRONユーザです。
NORTi 使ってます。> CPUは高速化したものの外付けメモリの速度が足りないので外部
> のバスアクセスは実質10MHz程度しか出ないということが後で
> 分かりました。
SH2って、内部クロック(Iφ)、バスクロック(Bφ)、周辺クロック(Pφ)、およびMTU2 モジュール用クロック(MPφ)をそれぞれ設定できるんですよね。SH2のどの型式かわかりませんが、CPUコアが80MHzなら、バスクロックは40MHzくらいまでいけるようですね。(SH7146のハードウェアマニュアルを見ながら回答書いています。) 詳しくは、お持ちのSH2のハードウェアマニュアルの、クロック発信機(CPG)の章を参照してください。
って、実はバスの速度じゃなくて、外付けしたRAMのほうが遅くて、っていう話でしたっけ? 外付けはDRAMですか?
ソースコードの行数からして、素人ではなくお仕事でプログラムを書かれている方だと思いますので、割り込みの中にいろいろ書いちゃうような変なことはしていないと思いますが、いかがでしょうか。
差し支えなければ、SH2の型番、各タスクとその優先度、タスクに割り当てたスタックサイズ、処理周期、全体で必要なRAM容量など書いていただければ、また違った回答があるかもしれません。
Sectionでどこにどのメモリを割り当てているかとか。処理速度に効きそうですよね。高速化が必要な部分のメモリだけ内部メモリに割り当てるなんていう案を今思いつきました。
> ソースは10万行くらいあり、コーディング流儀の微細な変更でも、
> ”積もれば山”の可能性があります。
プログラムの処理速度にもパレートの法則が当てはまるものと思います。ですから、ボトルネックとなっている2割のコードを改善すれば8割の改善は見込めるんじゃないでしょうか。
この回答への補足
言い忘れてました。^^;)
ありがとうございます。
クロックセッティングはIφ=80MHz,Bφ=Pφ=MPφ=MIφ=40MHz
(CPU使用範囲で最速)です。
外付けRAMは70nsのルネサス製SRAMで、基板に付けた電池で
バックアップして停電保護メモリも兼ねています。
12nsの高速タイプもあるのですが、消費電力が桁違いでバックアップ
の寿命が足りないためハード担当と思案中です。
主用途は電圧値のデジタル変換と監視(比較信号の出力)で、
タスクは最優先から、
電圧値のデジタル変換、パラレルIO制御:10ms定周期
キー検出(別基板からのシリアル受信):30ms遅延
ウォッチドグ制御:100ms定周期
電圧値の演算と信号比較:200ms定周期
シリアル(子局からの電圧値受信):100ms定周期
シリアル(その他アプリ用):50ms遅延(*3本)
画面制御(表示基板へのシリアル送信):100ms遅延
エラー監視:200ms遅延
自己診断(定期のハードチェック):500ms遅延
USBポート制御:不定期(*2本)
こんな感じです。
上層のタスクが排他で”待ち”(休眠)に入っているのなら、
下層のタスクはまわるはずなんですが、めいっぱい働いてしま
っているので下がまわらないようです。
No.1
- 回答日時:
処理が重くなった原因が外部メモリの速度にあることははっきりしているのでしょうか? (少し増えたといわれる)シリアル通信に関連して、セマフォ等による排他制御が足を引っ張っていることも考えられます。
また、処理速度を何パーセント程度向上したいのでしょうか? それによっても選択肢が変わってきます。
いずれにしても、実際のソースをざっとでも見ないと適切な判断が出来ませんが、そうもいかないと思うので、可能な限りの情報を提供してください。
CPUの型番、RTOSやコンパイラの製品名も補足してください。
回答ありがとうございます。
CPUはSH7085、コンパイラはルネサスのSHC(Ver4.0)、
OSはミスポのnortiです。
I2Cが10ms毎に40byteほど、シリアルは115kで100ms
毎に200byte程度と、19.2kで100ms毎に80byte、
他に400kの同期1本と9.6kの調歩が3本。
通信のハード制御は、カーネル資源では制御が間に合わないので、ほとんど
割り込みで駆動させています。
現在無駄処理がないかソースを検索中ですが、I2Cを組み込んだ時に、カ
ーネル資源を多用するとディスパッチが重くなることが分かって、ほとんど
削除したので無駄な排他が見つかる見込みは少ないです。
向上の希望量は、”可能な限り”です。現状の2倍以上のパフォーマンスが
ないと、最下層のタスクで制御させているUSBポートがメモリを装着して
も認識してくれません。
115kのシリアルを入れるまでは最下層のタスクも悠々だったのですが、
入れた途端に全然言うことを聞かなくなり、排他か割り込みの制御ミスか
と調査したら時間不足になったようです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- CPU・メモリ・マザーボード Windows11アップデート後の不具合(メモリ不足)について 9 2023/01/04 11:34
- デスクトップパソコン 仕事で使うPC 10 2023/04/23 00:27
- システム CPUの問題について 2 2022/07/09 12:04
- ビデオカード・サウンドカード グラフィックボード増設について 9 2023/05/17 11:06
- デスクトップパソコン ん~…分からん 7 2022/06/10 10:47
- 画像編集・動画編集・音楽編集 動画編集の処理時間と編集後の動画容量について 2 2022/12/29 21:27
- BTOパソコン PCの選び方 6 2022/09/11 00:16
- CPU・メモリ・マザーボード CPUで動作しているOSについての質問です。 3 2023/05/05 00:10
- その他(コンピューター・テクノロジー) 量子コンピュータの動作原理がわかりません。同じビットが、1でも0でも有って良いだろうか? 3 2023/02/04 03:20
- ノートパソコン パソコンを起動させ続けるとどうなりますか? 8 2022/06/18 12:49
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ロータリーエンコーダがうまく...
-
PICマイコン 割り込み実行時間...
-
音声ファイル再生時のフリーズ
-
このレジの並び方は間違ってま...
-
VB.NET スレッドからのイベント...
-
マイコン C言語 割り込み処理...
-
pic 複数の割り込み関数 切り分...
-
Macターミナルで実行中のプログ...
-
CGIの記述について教えてくださ...
-
PerlScriptでMSAgentをプログラ...
-
winsockを使った通信方法
-
MFCスレッド CriticalSection
-
テキストファイルを読み込んで...
-
マイコンからプログラムを読み...
-
家電製品の電力周波数を変える機械
-
VBAの配列サイズとメモリに関して
-
メモリ解析の方法
-
アセンブリ言語の問題
-
MACアドレスの調べ方
-
PC-98で拡張メモリを使え...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
電車で待機列の割り込みについ...
-
スーパーのレジで並んでいたら...
-
CPU負荷率の安全な上限と計...
-
マイコン C言語 割り込み処理...
-
このレジの並び方は間違ってま...
-
USB機器からのデータ受信による...
-
【組込み】割り込み中のstatic...
-
VB6でSendKeyを利用したTab移動...
-
一定時間操作がなかったら、と...
-
VB.NET スレッドからのイベント...
-
irqbalance って
-
ウォッチドッグタイマ(WDT)の...
-
Timerコントロールによる動作の...
-
pic 複数の割り込み関数 切り分...
-
マイコンSH-2の割り込みを用い...
-
Amazonfireタブレットにわから...
-
STATUSのZフラグについて
-
マイコンの割り込みについて教...
-
Timerコンポーネントのインター...
-
電車乗車時、並んでいるのに割...
おすすめ情報