いつもお世話になっています。ミミです。
板違いである事とは認知していますが、何卒よろしくお願いいたします。
環境は、eMbedded Visual C++4.0、Win2000 SP4、ダイアログベースで MFC使用。
実行対象は MIPS II CPU のモバイル機です。
WindowProc をオーバーロードして
Windowsからのメッセージを受信した時の処理を記述しました。
下記に色々と状況を書かせて頂きますが、
今回ご質問したい事そのものは、「WindowProc()の書き方によって、
全体パフォーマンスに影響を与える事があるか否か」です。
分かりにくければご指摘ください。
-------------------------------------------------------------
ダイアログクラスに、
LRESULT CHogeDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == m_nWmWakeup)
{
// 処理1
}
if (message == m_nWmResumed)
{
// 処理2
}
…(省略)…
return CDialog::WindowProc(message, wParam, lParam);
}
void CHogeDlg::OnButton1()
{
// 処理A(少々時間のかかる処理)
}
という様に、WindowProcと、OnButton1を記述しています。
OnButton1()を実行した場合、かつ、
「処理A」の実行中は WindowProc()内の「処理1」「処理2」は実行されない事が
分かっている時、
WindowProc()内の記述を、
1.WindowProc()そのものを削除(オーバーライドしない)
2.WindowProc()内の「処理1」「処理2」を全て注釈にして、if文の枠だけ残す
3.WindowProc()内の「処理1」「処理2」を全て消去して、if文の枠だけ残す
4.WindowProc()内の「処理1」「処理2」は全て有効
と試した所、「処理A」を実行した時、
1<4<3<2
という処理速度が得られました。
WindowProc()を記述しない1.の方が、2.3.と比べて「処理A」の速度が速い事は納得で
きますが、
処理1、処理2が有効な(注釈でもなく削除もしていない)時も、2.3.と比べて
「処理A」の速度が速い事がどうしても納得できません。
何度か試行し、かつ時間測定には、「処理A」の前後に
SYSTEMTIME rtTimeS;
GetLocalTime(&rtTimeS);
という様に、時刻を計測しています。
個人的には、実行モジュールの最適化の関係(根拠全くなし)
かなと予想していますが、今はワラをも掴む状態です。
WindowProc()に記述する時の注意点などや、
過去の実例などがありましたら、どんな些細な情報でも構いませんので
ご教授ください。
いつも、面倒な投稿で大変申し訳なく思います。
以上、宜しくお願いいたします。
追加です。
「…(省略)…」には、処理3、処理4がありますが、
ここも「処理A」の処理には、関係しません。
2と3の違いはコメントを削除してあるかどうかだけですか?
もしそうであれば、2と3の差はないはずです。
> 1<4<3<2
この順序の実際の差はどうなっているのでしょうか?
測定誤差の範囲内の違いしかないような気がします。
>「WindowProc()の書き方によって、
>全体パフォーマンスに影響を与える事があるか否か」
少なくとも今回程度の例では、ほとんど影響ないと思われます。
ミミです。
REE様、ご返信ありがとうございます。
>2と3の違いはコメントを削除してあるかどうかだけですか?
はい。コメントを削除しているだけです。
2も3も、if文の枠のみが有効です。
>> 1<4<3<2
>この順序の実際の差はどうなっているのでしょうか?
1がおよそ17秒程度で、
2がおよそ19秒程度です。
「処理A」と記述していますが、実際はファイル内のレコードをチェックする処理であり、
そのチェックには、DLLを静的に読み込んで処理しています。
個人的には1秒も2秒も気にはならないのですが、
客先に納品するプログラムなので、そうもいかず途方にくれています。
・・・それとも、対象が MIPSIIが原因なのかも知れません。
以前、アライメントのことでちょっと問題になった事もありますので・・。(根拠なし)
>>> 1<4<3<2
>>この順序の実際の差はどうなっているのでしょうか?
>1がおよそ17秒程度で、
>2がおよそ19秒程度です。
1回あたり2秒の差があるのですか?
3、4の値は?
試行回数も教えてください。
REE様、ご返信ありがとうございます。
全てミリセコンド単位で記録していますが、だいたい
1.17秒 (WinProcなし)
2.19秒 (WinProc内、注釈)
3.18秒 (WinProc内、削除)
4.17~18秒(WinProc内、有効)
の範囲で所要時間がかかっています。
上記1~4、いずれとも3回ずつ実行しました。
掲載の値は、Hogeプロジェクトとして作成した、テストプロの値を掲載していますが、
実際に納品するプログラムに組み込んだりもしたテストもいれると、試行回数、50回は超えて
います。
この場合、1.4に関しては17~18秒前後で、2.3に関しては、時に21秒を記録する事
もありました。
もちろん、実際に納品するプログラムの場合も、「処理1」「処理2」は通過していません。
仕様は上記と全く同じです。
注釈、削除って
if(a==b)
{
/* c=d;*/
}
と
if(a==b)
{
}
の速度の比較ということ?
ならば両方ともコンパイル後はifごと消えたものが作られるので
1秒の差になるのがわからん。
測定誤差で数百ミリ秒だとおもうし、平均すればほぼ同じになるはずだが。
そもそもGetLocalTimeの分解能ってどうでしたっけ?
ミリ秒の値ってあてにならなかったような気もしますけれど。
見た感じだとGetTickCountを使った方がいいのでは。
あと、CEだと結構状況によって結果がバラついたりしませんでしたっけ。
こういう測定の場合、通常は数百回とか千回くらいで平均しませんか。
3回ではサンプリングとしては少なすぎるような気がします。
# CEはよく知りませんが、
キャッシュの影響範囲だったりして。
とにかく、その計測結果は本当にアテにある計測結果といえるか微妙な気がします。
# コメントだけの問題なら、充分計測誤差の範囲と思います。
ひょっとして、デバッグビルドのまま計測してませんよね?
デバッグビルドだと最適化がかからないので、
意味のないif文もそのまま評価されてしまいます。
あと、キャッシュの影響はけっこう大きいので、
2回連続で計測して、1回目の計測結果は捨てるなどしないと、
評価は正確ではないと思います。
誤差を平均化するために、WindowProc()を直接呼ぶ、
またはSendMessage()で間接的に呼ぶループを作成して、
試行回数を増やして比較してみるといいと思います。
おはようございます、ミミです。
返信が遅れてしまい申し訳ありません。
超初心者様、PATIO様、PART様、KJ様、ご返信ありがとうございます。
> 注釈、削除っての速度の比較ということ?
はい。そうです。
実際に実機(WinCE機)にて、パフォーマンスに影響が出ているので、両者の速度の比較を調べて
います。
自分の頭の中では、注釈した状態と削除した状態とでは、コンパイル後は同じものと思い込んで
いました。
実行分は機械語になりますが、注釈なんて機械語にはなりませんし。。
(混合モードでも、注釈は注釈として表示されています。)
PATIO様の仰るとおり、テストプロに於いては3回の試行は少なすぎかもしれません。
実際のプログラムに組み込んでみても、時間値こそは違いますが、
同じように時間の差がある事は確認できました。
何せ手作業による調査なので、数百回以上のテストは、かなり厳しいのが本音です。
PART様のご指摘のキャッシュの影響範囲ですが、
確かに色々と試していますが、だいたいの時間値は上記に記した通りですが、
GetLocalTimeによるミリセコンドでの記録では差違は結構あります。
PATIO様もご指摘くださいましたが、バラツキとはこの事なんですね。
GetTickCount、調べてみます。
KJ様のご指摘のDebugビルドはありません。
客先納品に向けてReleseにてテストをしているためです。
(Debugでは致命的なバグ(Access Violation)があっても、壊している領域がシステムでない時
は
スルーしてしまうので、Releaseにてテストしています。)
私的には1秒も2秒も すぐ の時間なのですが、
「速度に遅延がある=どこかしらに遅延させている原因がある。」
ごもっともなご指摘を受けましたし、このまま遅延させているのを野放しにしておくと
万一不測の事態があった場合に問題(考えすぎですね。)なので、
MFCは使用せずに、APIベースでテストプロを構築し、同様に WinProc内に色々と
記述してみて、速度を検証してみます。
(そうすることにより、ブラックボックスであるMFCが原因か否かを見極めるため。)
皆様色々とありがとうございました。
引き続き調査してみます。
なるほどPocketPCではGetLocalTimeって1秒の精度なのか。
それじゃあ信用できないね。
確認していないので想像ですけど
今が00:00:00.999のときにGetLocalTimeすると00:00:00.000が得られ、
それから0.001秒後にGetLocalTimeすると00:00:01.000が得られる訳だから
1秒の測定誤差があっても不思議じゃない。
GetTickCountでも1秒より精度が高いが同じ現象があるはず。
以下でそれを少なくすることが出来るはず。
a=GetTickCount();
while(1) if(a!=GetTickCount()) break; else sleep(0);
それよりQueryPerformanceCounter使えばいい。
精度的にはQueryPerformanceCounterが一番だな。
「OnButton1() 」のところで時間のかかる処理をしてもよかったのでしょうか。
まずかったような気がするのですが。
ソフトそのものが処理終了待ちで固まってしまうのを仕様として許されるなら
アプリとしては許されるかも。ただ、一般的には長くかかる処理は中断できるような
インターフェイスを用意して処理そのものはワーカースレッドで処理させる
というようにすると思います。
Windowsには、ウインドウメッセージのハンドラは処理を速やかに終わらせて
OSに処理を返しなさいと言うUIのガイドラインがあったと思います。
確か、0.1秒ルールとか言ったと思います。
只、テストツールとか試験的に処理を動かしたいだけなら別に問題ないと
思います。但し、その処理が終わるまでそのスレッドの他の処理は進まない
と言う事を理解した上での話だとは思いますけれど。
ミミです。
遅くなり申し訳ありませんでした。
PATIO様と超初心者様が教えて頂きました、
GetTickCount()について調べてみました。
# 他にも timeGetTime()について調べてみましたが、CEでは非サポートでした。
結論から言いますと、あれほど誤差が出て悩んでいたのに、
GetTickCount()ではきれいにほぼ一致しました。
>【ミミ 2005/12/27(火) 17:00:56】
> 1.WindowProc()そのものを削除(オーバーライドしない)
> 2.WindowProc()内の「処理1」「処理2」を全て注釈にして、if文の枠だけ残す
> 3.WindowProc()内の「処理1」「処理2」を全て消去して、if文の枠だけ残す
> 4.WindowProc()内の「処理1」「処理2」は全て有効
→ このパターンは全て、数百ミリ秒程度の誤差範囲内に収まりました。
(但し、例外あり。☆を参照してください。)
>【ミミ 2005/12/27(火) 17:53:28】
>1がおよそ17秒程度で、
>2がおよそ19秒程度です。
→ と前回書き込みさせて頂きましたが、これらも16秒台でした。
・・不思議です。
下記の通り、ただ GetTickCount() を問題の処理の前後に「追加」しただけなのにです。
- dw1 = GetTickCount();
- 処理A
- dw2 = GetTickCount();
- dw2-dw1を表示
しかも、17秒とか19秒等と計測していた GetLocalTime()による差も、
GetTickCount()を追加した事により、GetTickCount()で得た値と一致しました。
(1ミリ秒程度の誤差はありましたが・・。)
ただ1つ気になることがありました。(☆)
今回、GetTickCount()を追加したテストプログラムを、パスを変えただけで、
若干の測定誤差が発生しました。
\root\hoge.exe でテストした場合と、
\root\Test\hoge.exe でテストした場合とで、3のケースだけ、最大2秒の誤差が発生してし
まいました。
>【ミミ 2005/12/27(火) 17:53:28】
>「処理A」と記述していますが、実際はファイル内のレコードをチェックする処理であり、
>そのチェックには、DLLを静的に読み込んで処理しています。
→ ファイルを探しに行く際、フォルダ階層が遠くなった事によるのが処理遅延の原因かなと考
えています。
…の割には、1、2、4のケースでは、処理遅延が発生しない・・。謎です。
現在、GetLocalTime() の精度がどれくらいなものかと、
GetTickCount() を追加したら GetLocalTime() の精度が向上した理由を調べています。
本件について、ご助言いたたげれば幸いです。
# ITO様とPATIO様のご指摘のあった、0.1秒ルール、参考になりました。
# ですが、今回はCE 機という事もあり、処理待ちで固まるのは仕様としています。
# ご指摘ありがとうございました。