rdtsc命令でお聞きしたいことがあります


TOYAMA  2008-11-12 16:29:07  No: 69222

遠山といいます。
 
以下のホームページでお聞きしたいことがあります。
http://www.cycleof5th.com/tips/index.php?date=2007-06-07/2
 
rdtsc(Read Time Stamp Counter)のクラス化
 
のところでクラス化によって若干パフォーマンスが悪くなるとありますが、
私も同じような現象で悩んでいます。
 
私の実装はクラスのヘッダーをヘッダーファイルに定義して実装を別の
モジュールに書き実装モジュールに以下のような感じで書いています。
 
#pragma warning( disable : 4035 )
inline static __int64 getRdTsc()
{
   _asm
   {
      rdtsc
   }
}
#pragma warning( default : 4035 )
 
CClass::Func()    // 実装は違いますがこのような感じで実装モジュールに書いています。
{
   static LONGLONG TSC;
 
   TSC = getRdTsc();
}
 
実際ミリ秒単位での時間が経過したら別の処理をしたいと考えているのですが
正確な時間が取得できなくて悩んでいます。解決策はあるのでしょうか。
コンパイルはVC++6.0Professionalで実行速度の最適化を掛けてコンパイル
しています。

rdtsc命令関連で詳しいかたいますでしょうか。
実際は正確な時間が取得できていて他のところに問題があるとも考えられます。
解決策がありましたらご教授願いたいのですが、宜しくお願いします。


tetrapod  2008-11-12 18:37:24  No: 69223

最近の CPU はコアが2つ以上入っているわけだが、
そもそも RDTSC は今そのスレッドが走っているコアでの TimeStamp を返す。
一方 Windows Kernel の挙動として、あるスレッドをどの物理コア上で走らせるかは決まっておらず、
また、いったん特定コア上で走り出したスレッドがあったとしても
API 呼び出し等で停止した後、再開する際には違うコアにて走る可能性すらあり、
基本的に RDTSC で経過時間を得ようという案そのものが悲惨な結果を招くと思われる

それでも RDTSC を使いたいというなら止めないけど。


aetos  2008-11-12 21:36:40  No: 69224

> 一方 Windows Kernel の挙動として、あるスレッドをどの物理コア上で走らせるかは決まっておらず

推奨するわけではないけれど、興味本位として、SetThreadAffinityMask で固定できない?
まぁ、SetThreadAffinityMask が 64 CPU までしか対応できない以上、Windows 7 + 64 個を超える CPU で動かしたら破綻するかもしれんけど。


tetrapod  2008-11-12 21:52:19  No: 69225

> SetThreadAffinityMask で固定できない?
御意、なのだが問題はまだ別に残っており、やはり RDTSC は非推奨

http://mcn.oops.jp/wiki/index.php?Develop%2FTimer
http://d.hatena.ne.jp/NyaRuRu/20060705/p1
http://d.hatena.ne.jp/NyaRuRu/20081107/p1

俺も RDTSC で痛い目にあっているので・・・


TOYAMA  2008-11-12 22:10:08  No: 69226

遠山です。

以下のサイトにも同じようなことが書いてありますが、
http://www.02.246.ne.jp/~torutk/cxx/clock/cpucounter.html

>SetThreadAffinityMask で固定できない?
SetSetThreadAffinityMaskはデュアルコアの場合だと思いますので
私のコンピュータではほとんど意味を持たないと思います。
私のコンピュータはPentiumⅢでスペックは700MHzです。OSはWindowsMeです。
celelon 1.6GHzのパソコンでも余計なクロック数が増えているように
思います。余計なクロック数が増えているというのはgetRdTsc()でループを
掛けて取得しているのですが指定(例えば700MHzで10msだとしたら7000000となります)
した時間より長くかかってしまうという事です。


tetrapod  2008-11-12 23:06:29  No: 69227

> 例えば700MHzで10msだとしたら7000000となります
大きく勘違いしている気がする

Pentium 系 CPU のクロック値の表記は瞬間最大風速みたいなもので
・すべての命令語すべてのデータが L1 cache に載っていて
・割り込み等が一切入らず
・命令の平行実行・投機実行が完全にヒットした
場合に数値どおりの性能が出ることになるわけだが、現実的にはそういうことはありえない。

やりたいことは、時間の計測ではないのだよね?
ならば RDTSC が期待通りに動かない理由を深く追求するのは方向違い。

とりあえず数msecで処理を切り替える必然は何?
Windows はリアルタイムOSではないのでそういう用途には向かない。
マルチスレッドでだめな理由は?


TOYAMA  2008-11-12 23:48:51  No: 69228

やりたいことは、時間の計測ではなく
仮想マシンをVC++でエミュレートしたいと思っているのですが、

例えば仮想マシンがInterval Timerを持っていて10ms後に割り込み処理をしたい、
ということです。
方法が思いつかずrdtscか別の方法でどのように実現すればよいのでしょうか。
同じ考えでQueryPerformanceCounterでも同じ結果になりました。宜しくお願いします。


TOYAMA  2008-11-13 06:58:35  No: 69229

実際に以下のコードで試しに経過時間を計測してみました。
PentiumⅢ700MHzでテストしています。
7000000の指定でmillSecondが10msその半分の
3500000の指定でmillSecondが5msを得ました。
このコードだと正確に時間を測定できています。

実際のプログラム上で誤差が出るのはどういうことなのでしょうか。
>Pentium 系 CPU のクロック値の表記は瞬間最大風速みたいなもので
こちらのことが原因と考えられるのでしょうか。そもそもエミュレート自体が問題?

timeBeginPeriod( 1 );
BeforeCount = getRdTsc();

beforetime = timeGetTime();
while( getRdTsc() < BeforeCount + 7000000 ){
}
aftertime = timeGetTime();

millSecond = aftertime - beforetime;
timeEndPeriod( 1 );


tetrapod  2008-11-13 18:42:26  No: 69230

仮想マシンのエミュレートっつのがよくわからんが
(Emulate という文言は通常ハードウェア実装に対して使う)
VMware のように ix86 の仮想マシンを作る?
ARM/SH 等、マイコンのシミュレータ?

ix86 の仮想マシンがほしいなら自作するなんて遠回りせず VMware でも使ったほうが面倒がない。

マイコンの(コアだけでなく周辺を含めた)シミュレータだとして
リアルタイム性が強く要求される代物なの?
ならば Windows という非リアルタイムOS上でソフトウェアだけで実装するのが間違い。
どう構成すればよいかは詳細次第で違うし、答えられない。

で、提示コードだけど典型的「瞬間最大風速測定コード」だね
L1cache にすべて乗る程度のコード+データアクセス量0でページフォルト皆無
正しい測定ができてしかるべきコードだと思う。
実際のエミュレータコードで測定できない理由は判断つかない。

getRdTsc()<BeforeCount+NNN は要修正(バグっているよ)

オーバーヘッドを気にしているようだけど、実際生成されているコード見た?
__inline __int64 rdtsc() { __asm rdtsc; }
に対して最適化ありで生成されるコードはオーバーヘッド0とみなしていいよ。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加