- PR -

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

投稿者投稿内容
ばーど
常連さん
会議室デビュー日: 2005/08/03
投稿数: 32
投稿日時: 2005-12-26 16:27
[引用文]
邪道です。他のアプリケーションの処理を大きく阻害し、CPUリソースを無駄に消費するからです。

昨日、示しましたが以下の用に簡単にfor文を使ってダミー処理しています
for(y=0;y<150000;y++){
total += y;
}

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

C言語を操るのもまだ、ままらなく、ネット上で検索していたところ昨日示しましたホームページ上にいきあたり、これは使えるのではないかと思ったしだいです。

ぜひ、QueryPerformanceCounterをつかった例を教えていただけたらと思います。


.NETの掲示板なのですが、もう一つ質問させていただきます。


@
start_time = timeGetTime();
for(x=1;x<=10000;x++){
Num_n1++;
printf("○");
//sendto関数を記述
}
end_time = timeGetTime() - start_time;


A
start_time = timeGetTime();
for(x=1;x<=10000;x++){
Num_n1++;
//sendto関数を記述
if(Num_n1%1000 == 0){
end_time = timeGetTime() - start_time;
printf("%dミリ秒経過%dパケット送出\\n",end_time,Num_n1);
}
}
end_time = timeGetTime() - start_time;

上記に示します二つのプログラムの処理時間は、異なるのはあたりまえなのでしょうか?Aの方が早かったです。

いま、ソケットプログラミングにてスループットを計算しているのですが、上記@とAで処理時間(パケット送信時間)が異なるため、どちらが正しいかわからない状態です。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2005-12-26 19:49
引用:

ばーどさんの書き込み (2005-12-26 16:27) より:
引用:

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


昨日、示しましたが以下の用に簡単にfor文を使ってダミー処理しています
for(y=0;y<150000;y++){
total += y;
}


@
start_time = timeGetTime();
for(x=1;x<=10000;x++){
Num_n1++;
printf("○");
//sendto関数を記述
}
end_time = timeGetTime() - start_time;


A
start_time = timeGetTime();
for(x=1;x<=10000;x++){
Num_n1++;
//sendto関数を記述
if(Num_n1%1000 == 0){
end_time = timeGetTime() - start_time;
printf("%dミリ秒経過%dパケット送出\n",end_time,Num_n1);
}
}
end_time = timeGetTime() - start_time;

上記に示します二つのプログラムの処理時間は、異なるのはあたりまえなのでしょうか?Aの方が早かったです。


 ここの掲示板は、[quote]から[/quote]までを「引用文」として扱います(投稿時に「この投稿でBBコードを使わない」にチェックしなければ)。利用してください。

 で、異なるのは当たり前です。なぜかは、甕星さんらが書かれているように、
引用:

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

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

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


_________________
すなめり
常連さん
会議室デビュー日: 2003/01/29
投稿数: 37
お住まい・勤務地: 横浜
投稿日時: 2005-12-26 20:45
引用:

ばーどさんの書き込み (2005-12-26 16:27) より:
[引用文]
邪道です。他のアプリケーションの処理を大きく阻害し、CPUリソースを無駄に消費するからです。

昨日、示しましたが以下の用に簡単にfor文を使ってダミー処理しています
for(y=0;y<150000;y++){
total += y;
}


このダミー処理が駄目なのです。
理由は、私が思いつくだけで三つあります。
1.このような処理がある場合、他のプロセスにCPUを明渡すタイミングが難しくなります。結果、この基本的に何もしない処理が、他のプロセスの実行を阻害します。

2.このような処理がある場合、プロセスに与えられたCPU時間を使い切ってから他のプロセスに処理がわたることが多くなります。その場合、スケジューリングのやり方によっては、この処理の優先度が極端に落とされる場合があり、結局このプロセスの実行も阻害されます。

3.コンパイラの最適化によっては、このループは何もしないとみなされ、単一の代入文に置き換えられる可能性があります。

引用:

@
start_time = timeGetTime();
for(x=1;x<=10000;x++){
Num_n1++;
printf("○");
//sendto関数を記述
}
end_time = timeGetTime() - start_time;


A
start_time = timeGetTime();
for(x=1;x<=10000;x++){
Num_n1++;
//sendto関数を記述
if(Num_n1%1000 == 0){
end_time = timeGetTime() - start_time;
printf("%dミリ秒経過%dパケット送出\\n",end_time,Num_n1);
}
}
end_time = timeGetTime() - start_time;

上記に示します二つのプログラムの処理時間は、異なるのはあたりまえなのでしょうか?Aの方が早かったです。

いま、ソケットプログラミングにてスループットを計算しているのですが、上記@とAで処理時間(パケット送信時間)が異なるため、どちらが正しいかわからない状態です。



2が速いのがあたりまえです。
1は、ループ内でprintf関数を1万回呼びますが、2では高々10回です。
printfは、実行するのにかなりCPU時間を食いますので、printfの実行回数が少ないほうが実行時間が短くなるのはあたりまえです。
ばーど
常連さん
会議室デビュー日: 2005/08/03
投稿数: 32
投稿日時: 2005-12-26 21:39
甕星さん、jittaさん、すなめりさん返信ありがとうございます。
今まで、引用方法の仕方が分かっていなかったのですが、さきほど分かりましたので使用します。

引用:

すなめりさんの書き込み (2005-12-26 20:45) より:

このダミー処理が駄目なのです。
理由は、私が思いつくだけで三つあります。
1.このような処理がある場合、他のプロセスにCPUを明渡すタイミングが難しくなります。結果、この基本的に何もしない処理が、他のプロセスの実行を阻害します。

2.このような処理がある場合、プロセスに与えられたCPU時間を使い切ってから他のプロセスに処理がわたることが多くなります。その場合、スケジューリングのやり方によっては、この処理の優先度が極端に落とされる場合があり、結局このプロセスの実行も阻害されます。

3.コンパイラの最適化によっては、このループは何もしないとみなされ、単一の代入文に置き換えられる可能性があります。



for文のようなダミー処理ではなく、QueryPerformanceCounter、QueryPerformancefrequency関数を用いた方法が考えられるのでしょうか?

いま、その関数を用いておおよそ1msの待機時間(または、2ms、3ms、10ms等の待機時間)の作成中なのですが、うまくいきません。以下のようなプログラムを作っています。

double count_time = 0;
LONGLONG freq, cnt1, cnt2;
int y;

QueryPerformanceFrequency( (LARGE_INTEGER *)&freq );
while(1){
  QueryPerformanceCounter( (LARGE_INTEGER *)&cnt1 );
  for(y=0;y<10;y++);
  QueryPerformanceCounter( (LARGE_INTEGER *)&cnt2 );
  if((count_time += (double)(cnt2-cnt1) / freq * 1000000.0) > (double)1000)
    break;
}

上記プログラムは、double型のcount_timeにfor文の処理時間の合計を取得し、1000より大きくなったら、ループを抜けるというふうにしました。しかし、実際のところ、うまくいっていません。おそらく、if文の記述の仕方が悪いのだと思います。違う方法などがありましたら、教えていただけないでしょうか?ご教授お願いします。

引用:

@
start_time = timeGetTime();
for(x=1;x<=10000;x++){
Num_n1++;
printf("○");
//sendto関数を記述
}
end_time = timeGetTime() - start_time;


A
start_time = timeGetTime();
for(x=1;x<=10000;x++){
Num_n1++;
//sendto関数を記述
if(Num_n1%1000 == 0){
end_time = timeGetTime() - start_time;
printf("%dミリ秒経過%dパケット送出\\n",end_time,Num_n1);
}
}
end_time = timeGetTime() - start_time;

上記に示します二つのプログラムの処理時間は、異なるのはあたりまえなのでしょうか?Aの方が早かったです。

いま、ソケットプログラミングにてスループットを計算しているのですが、上記@とAで処理時間(パケット送信時間)が異なるため、どちらが正しいかわからない状態です。



引用:

すなめりさんの書き込み (2005-12-26 20:45) より:

2が速いのがあたりまえです。
1は、ループ内でprintf関数を1万回呼びますが、2では高々10回です。
printfは、実行するのにかなりCPU時間を食いますので、printfの実行回数が少ないほうが実行時間が短くなるのはあたりまえです。



スループット計測のためには、printfでCPUの時間を費やすよりも、パケット送出にまわすのべきなのだと、解釈しました。ありがとうございました。

[ メッセージ編集済み 編集者: ばーど 編集日時 2005-12-26 21:44 ]
ジブ
大ベテラン
会議室デビュー日: 2005/09/22
投稿数: 135
投稿日時: 2005-12-26 22:13
引用:

ばーどさんの書き込み (2005-12-26 21:39) より:

コード:

double count_time = 0;
LONGLONG freq, cnt1, cnt2;
int y;

QueryPerformanceFrequency( (LARGE_INTEGER *)&freq );
while(1){
  QueryPerformanceCounter( (LARGE_INTEGER *)&cnt1 );
  for(y=0;y<10;y++);
  QueryPerformanceCounter( (LARGE_INTEGER *)&cnt2 );
  if((count_time += (double)(cnt2-cnt1) / freq * 1000000.0) > (double)1000)
    break;
}


上記プログラムは、double型のcount_timeにfor文の処理時間の合計を取得し、1000より大きくなったら、ループを抜けるというふうにしました。




なぜにcnt1を毎回取得するんでしょう。
高速なfor文の時間を足したって、ものすごく遅そうなif文の中の計算時間を無視していたら
ものすごい誤差が出てるんではないでしょうか?



[ メッセージ編集済み 編集者: ジブ 編集日時 2005-12-26 22:14 ]
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2005-12-26 23:17
引用:

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



そもそも、何のためにそんな高精度なタイマが必要なんでしょうか?

現状のPCシステムは非同期動作が当たり前&各所にバッファが盛り込まれているため、プログラムで高精度なタイマが取得できたとしても、それを正確に外部に反映出来なかったりします。

ありがちなことですが、そもそもの目的を示してもらえれば別解が得られることがあります。


[ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2005-12-26 23:19 ]
ばーど
常連さん
会議室デビュー日: 2005/08/03
投稿数: 32
投稿日時: 2005-12-28 17:17
[quote]
渋木宏明(ひどり)さんの書き込み (2005-12-26 23:17) より:
引用:

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

そもそも、何のためにそんな高精度なタイマが必要なんでしょうか?



私は、ソケットプログラミングを行っています。実際仕事で利用するのではなく趣味で行っています。UDPソケットをつかって、送信側からパケットを受信側へ送信しています。

そこで、送信側で送信間隔(ここでは待機時間)をとることで、パケットを受信側に確実に送信できるのではないかと思ったからです。UDPではなくTCPを使用すべきだとおっしゃるかもしれませんが・・・、ためしにUDPで試作したので行っているしだいです。

C言語に、Sleep関数などがありますがQueryPerformanceCounterとQueryPerformanceFrequencyを使って、Sleep(10)やSleep(1)の実行時間を計測したところ同様であったため、ダミー処理を施すことでおおよそ1msを取得できないか考えたしだいです。
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2005-12-29 00:12
引用:

ばーどさんの書き込み (2005-12-28 17:17) より:
そこで、送信側で送信間隔(ここでは待機時間)をとることで、パケットを受信側に確実に送信できるのではないかと思ったからです。UDPではなくTCPを使用すべきだとおっしゃるかもしれませんが・・・、ためしにUDPで試作したので行っているしだいです。


ネットワーク送信するデータに、ローカルコンピュータですらあてにできない精度での
送信処理を求めることが無茶です。

あと、UDPではどうなるかとかあんまり知らないですが、実際にネットワークに
出て行くまでのレイヤの処理で、すでにそれ以上の遅延やぶれがあると思います、たぶん。

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