@IT会議室は、ITエンジニアに特化した質問・回答コミュニティ「QA@IT」に生まれ変わりました。ぜひご利用ください。
- PR -

1msの分解能を得る方法について

投稿者投稿内容
ばーど
常連さん
会議室デビュー日: 2005/08/03
投稿数: 32
投稿日時: 2005-12-25 16:36
こんにちは。
僕は、コンパイラとしてVisual C++.NETを使用しC言語の練習をしています。

一定時間、待機するプログラムを作成しています。
C言語にSleep関数があり、それを使用しているのですがSleep関数は約10ms待機するのが限界であるということをネットを通して知りました。

自分は、1msの待機時間を得たいと思っているのですが、Windowsプログラミングの関数にはそのような関数はあるのでしょうか?もし、使用方法まで教えていただけたらと思います。

また、常に1msや10msの待機時間を得ることは可能でしょうか?やはり、PC内で走っているプロセスやPCの種類等によって1ms確保することは不可能なのでしょうか?

よろしくお願いします。
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2005-12-25 17:28
引用:

C言語にSleep関数があり、それを使用しているのですがSleep関数は約10ms待機するのが限界であるということをネットを通して知りました。


どっかで聞いた事ありますね。(ソース忘れました^^;)
因みに言語の限界ではなくて、Windows OS の限界ですね。

引用:

また、常に1msや10msの待機時間を得ることは可能でしょうか?やはり、PC内で走っているプロセスやPCの種類等によって1ms確保することは不可能なのでしょうか?


リアルタイム OS ではないので、やはり、「おおよそ」 10ms になってしまいます。

起動するプロセスのプライオリティを最大にすれば、期待値に近づくでしょうけど、やはりおおよそでしょうね。
_________________
囚人のジレンマな日々
Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2005-12-25 17:43
こんばんは。

引用:

ばーどさんの書き込み (2005-12-25 16:36) より:

一定時間、待機するプログラムを作成しています。
C言語にSleep関数があり、それを使用しているのですがSleep関数は約10ms待機するのが限界であるということをネットを通して知りました。



私もそのような話を聞いたことあります。システムタイマの10ms以下はあてにはならないようです。

引用:

自分は、1msの待機時間を得たいと思っているのですが、Windowsプログラミングの関数にはそのような関数はあるのでしょうか?もし、使用方法まで教えていただけたらと思います。



どこまで待機時間の誤差が許容範囲か分かりませんが…
「マルチメディアタイマー」
「高分解能カウンター」
を使えば、可能なのではないでしょうか。

一応、
「システムタイマー」「マルチメディアタイマー」「高分解能カウンター」の分解能を調べる
テストプログラムを作成してみました。
#正しいのか自信はないのですが(~_~;)

コード:
#include <windows.h>
#include <stdio.h>

#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")

void main()
{
	DWORD dwTimeAdjustment;
	DWORD dwTimeIncrement;
	BOOL bTimeAdjustmentDisabled;

	if (::GetSystemTimeAdjustment(&dwTimeAdjustment, &dwTimeIncrement, &bTimeAdjustmentDisabled)) {
		printf("システムタイマー分解能(クロック割り込み間隔):%f ms\\n", (double)dwTimeIncrement / 10000.0);
	}

	TIMECAPS timeCaps;
	if (::timeGetDevCaps(&timeCaps, sizeof(timeCaps)) == TIMERR_NOERROR) {
		printf("マルチメディアタイマー分解能:%d ms\\n", timeCaps.wPeriodMin);
	}

	LARGE_INTEGER liFrequency;
	if (::QueryPerformanceFrequency(&liFrequency)) {
		printf("高分解能カウンター分解能:%f ms\\n", (double)1000.0 / liFrequency.QuadPart);
	}
	
}



私の使用しているPCでは次のような結果になりました。
引用:

システムタイマー分解能(クロック割り込み間隔):15.625000 ms
マルチメディアタイマー分解能:1 ms
高分解能カウンター分解能:0.000279 ms


渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2005-12-25 17:50
引用:

また、常に1msや10msの待機時間を得ることは可能でしょうか?やはり、PC内で走っているプロセスやPCの種類等によって1ms確保することは不可能なのでしょうか?



分解能と精度が別な物なのは分かってますよね?

1ms の「精度」のタイマは無理です。
実行されているプロセスや割り込みの量などによって変動してしまいます。
リアルタイムOSではないので、変動の範囲も様々です。

1ms, 10ms の「分解能」のカウンタは、既出の方法で利用可能です。
ばーど
常連さん
会議室デビュー日: 2005/08/03
投稿数: 32
投稿日時: 2005-12-25 18:15
返信ありがとうございます。

Windowsの場合10msが限界なのですね・・・。Linuxの場合、およそ1msを得ることができるとネット上に記載されていました。しかし、Linuxをほとんど触ったことがないため、あまりLinuxへと移行する気になれません ^^;

そこで、ダミー処理をかますことで、大体1msを得ることができないかと思っています。
ダミー処理は、for文を用いました。

以下に行ったことを示します。

1.別プログラム上で、QueryPerformanceFrequencyとQueryPerformanceCounterを用いて、ダミー処理の実行時間を計測。

[プログラム]
#include <stdio.h>
#include <windows.h>

/*==================================================*
* main
*==================================================*/
void main(void)
{

/* LONGLONG, _int64: 64bit integer */
LONGLONG freq, cnt1, cnt2;
int r;
int y;
unsigned long total = 0;

r = QueryPerformanceFrequency( (LARGE_INTEGER *)&freq );
if( r != 0 )
{
/* %I64d は、64bit integer用 */
printf( "freq=%I64d(Hz)\n", freq );
}
else
{
printf( "Not install High-resoution counter\n" );
}

QueryPerformanceCounter( (LARGE_INTEGER *)&cnt1 );

/* 計測したい処理をここに記述する
サンプルは何もしないので、QueryPerformanceCounterの
オーバーヘッドを計測していることになる */

//上記のコメントは、理解できていないのですが、以下にfor文を記述
   しまして、for文の処理時間を計測

for(y=0;y<150000;y++){
total += y;
}

printf("total:%lu\n",total);
QueryPerformanceCounter( (LARGE_INTEGER *)&cnt2 );

/* %I64d は、64bit integer用 */
printf( "cnt1=%I64d\n", cnt1 );
printf( "cnt2=%I64d\n", cnt2 );
printf( "t2-t1=%I64d\n", cnt2 - cnt1 );

printf( "t2-t1=%.1f(usec)\n", (double)(cnt2-cnt1) / freq * 1000000.0 );
}


2.1のプログラムを実行し、だいたい1msとなるループ回数を得て、作成中のプログラムに実装。

あやふやな言い回しかもしれませんが、タイマープログラムを作成しおおよそ1msのダミー処理を作成し、そのダミー処理を作成中のプログラムに実装したということです。


[質問内容]
・タイマープログラムを実行するたびに、処理時間が異なるのは、避けられないのでしょうか?たとえば、1回目が0.5msであったのに対して2回目は1.3msであったりします。

・ダミー処理をほどこすことは、実際の開発現場などでやられているのでしょうか?それとも、邪道なやり方なのでしょうか?

よろしくお願いします。

[参考サイト]
http://homepage1.nifty.com/aok2/004/win01.html


[ メッセージ編集済み 編集者: ばーど 編集日時 2005-12-25 18:17 ]

[ メッセージ編集済み 編集者: ばーど 編集日時 2005-12-25 18:17 ]

[ メッセージ編集済み 編集者: ばーど 編集日時 2005-12-25 18:18 ]
ばーど
常連さん
会議室デビュー日: 2005/08/03
投稿数: 32
投稿日時: 2005-12-25 18:25
囚人さん、Tdnr_Symさん、渋木宏明さん。
書き込みありがとうございます。

[引用文]
分解能と精度が別な物なのは分かってますよね?

すみません。分かっていません。

[引用文]
1ms の「精度」のタイマは無理です。
実行されているプロセスや割り込みの量などによって変動してしまいます。
リアルタイムOSではないので、変動の範囲も様々です。

1msの「精度」のタイマを作ることは不可能なのですか・・・
確かに、変動の範囲が激しいです。
末記人
大ベテラン
会議室デビュー日: 2005/12/05
投稿数: 233
お住まい・勤務地: あわにこ
投稿日時: 2005-12-25 23:20
こんなのとか
http://www.microsoft.com/japan/windows/embedded/partners/product_info/isv/micronet2.asp

こんなのは、いかがでしょう?
http://www.kuka-controls.com/jp/index.html
甕星
ぬし
会議室デビュー日: 2003/03/07
投稿数: 1185
お住まい・勤務地: 湖の見える丘の上
投稿日時: 2005-12-26 10:55
引用:

ばーどさんの書き込み (2005-12-25 18:15) より:
[質問内容]
・タイマープログラムを実行するたびに、処理時間が異なるのは、避けられないのでしょうか?たとえば、1回目が0.5msであったのに対して2回目は1.3msであったりします。


原則として避けられません。WindowsはプリエンプティブマルチタスクOSです。動作しているアプリケーションがあなたのプログラムだけではない以上、何時どのような理由で他の処理が割り込むか分かりません。

アプリケーションの実行プライオリティをRealTimeにすれば外乱要因を大幅に排除する事が出来ますが、無くす事は出来ません。Kernelドライバとして実装するなら外乱要因をなくす事も出来ますが、手間がかかりすぎるでしょう。そして何より他のアプリケーション(OSも含めて)の動作を大きく阻害するので、色々と制約の大きなものになるでしょう。

引用:

・ダミー処理をほどこすことは、実際の開発現場などでやられているのでしょうか?それとも、邪道なやり方なのでしょうか?


邪道です。他のアプリケーションの処理を大きく阻害し、CPUリソースを無駄に消費するからです。

#ところで・・・
#QueryPerformanceCounterで経過時間を測定してLoopを脱出するように、何故しない?

_________________
甕星 <mikahosi@abox9.so-net.ne.jp>
http://blogs.msmvp.jp/mikahosi/

スキルアップ/キャリアアップ(JOB@IT)