Windows PC向けにPCIデバイスの制御を行うドライバを作成しているのですが、コンフィグレーションレジスタへのアクセス速度が非常に遅く、なぜ遅いのか原因が分からず悩んでいます。
PCIバスのスペックではPCIコンフィグレーションサイクルが6サイクルなので、PCIバスのクロックが33MHzでウェイトがなければ1サイクル180nsで完了するはずなのですが、テストプログラムを作成して速度を計測したところ、PCIデバイスのコンフィグレーションレジスタへのアクセスに920nsを要しています。プログラム上のオーバーヘッドは、レジスタアクセス1回あたり約3nsで、ほとんど無視できる程度です。
いくらなんでもあんまり遅いので、これはPCIデバイス自体あるいはPCI-PCIブリッジに問題があるのかと思い、比較のためノースブリッジ内にあるデバイスにアクセスしてみたのですが、CPUにいちばん近く、かつPCIクロックに制限されないデバイスにもかかわらずサイクルタイムは271nsまでしか縮みませんでした。
こんな速度では大昔のISAのプログラムI/Oデバイスよりも遅いことになってしまうので、何かやり方に問題があるのかと思うのですが、どう変更すればいいものか全く見当がつきません。(ループの中はI/Oアクセス命令しかないような状態です。)
原因あるいは解法がお分かりの方ありましたら、教えていただけませんでしょうか。
なおテスト環境はCPU P4-2.8GHz (FSB800)、メモリ1.5GB、OSはWindows XPです。
※質問の文字数制限のためサンプルプログラムは掲載しませんでしたが、いただいた回答への補足として掲載可能です。
A 回答 (5件)
- 最新から表示
- 回答順に表示
No.5
- 回答日時:
一回ごとの値を計測する件ですが、たとえ計測精度に30%の誤差があっても、推定値と実測値の数倍の差を埋める情報は得られる可能性があるかと考えます。
1000回実行の平均時間は必ずしも一回の実行時間を反映するわけではないからです。同じ平均900nsでも、900ns×1000回と、200ns×900回+7200ns×100回では随分と違うでしょう。
実際問題としてI/Oレジスタを1000回(100万回)連続で参照するパターンがあまり一般的じゃないので、それゆえに遅いという可能性もあるわけです。
あと、カウンタがTSCじゃないとすると外部をみているのでしょうか。そっちのオーバーヘッドも気になるところです。
全くおっしゃるとおりです。特異的なばらつきがあるかもしれないという可能性をすっかり失念していました。
さっそく、1回の計測では1回のI/Oだけを行い、それを200回行って分布を調べるプログラムを作成して試してみたところ
19カウント: 7回
20カウント: 143回
21カウント: 49回
という結果になりました(端数があっていないのは、2回以下を表示しないようにしたからです)。1回の計測を「1回のI/Oを100回試行した最小値」と変更すると
19カウント: 200回
となりますので、これと比較的よく符号する結果です。
また、カウンタへのアクセス(やその他計測系そのもの)のオーバーヘッドについても同様に調べてみたところ、こんな感じでした。(I/Oを行う命令だけを削除)
7カウント: 19回
8カウント: 78回
9カウント: 60回
10カウント: 30回
11カウント: 11回
残念ながらどちらも特異な分布は示さず、アクセスが遅い原因に迫ることはできませんでしたが、推測のあらをまた1つ潰したという点で意味がありました。
アドバイスありがとうございました。
No.4
- 回答日時:
あまり自信はないですが、本当に測りたい時間を測れてるのかちょっと疑問に思います。
フリーランのカウンタってのはTSCで良いのかな? 70nsの分解度なら1000回ループなんてせずに一回ごとの時間を測ってみては?
あと100回の最小値でなく100回それぞれの時間を記録して分布を見るべきかと。
コメントありがとうございます。
TSCを使用すると分解能がCPUのコアクロックによって変化してしまいCPUごとに調整が必要となる等不便ですので、今回は使用しておりません。
1000回ループではなく1回ごとの時間を計測してはとのご意見ですが、1回の実行のみで計測するのでは計測制度が70nsになってしまい、仮に最短のPCIバスサイクルとなった場合には計測誤差が30%にもなってしまいます。また計測そのものに要する時間が誤差として加わるわけですが、これも1000回ループ時と比較して1回ごとに計測すると影響が1000倍になってしまいます。
次に経過時間の分布を見てはとのご意見ですが、分布を見ることによって原因を類推するヒントになるのではないかという意味合いでしたらおっしゃるとおりかと思います。ここに掲載するテストプログラムのコードは最短としたかったため、実際の実行時間に最も近い値となるのが確実である、最小値を求めるコードとしました。実際には分布を見るテストも念のため行っておりますが、その結果、やはり最小値あるいはその周辺が最も高頻度となっておりました。
No.3
- 回答日時:
なるほど、そういう事ですか。
恐らく、連続したアドレスにwriteトランザクションを掛ければバースト転送をしてくれると思うので早くなる可能性があります。
readトランザクションを早くするには、、、対象のPCIデバイスがDMA機能を持っていれば早くなると思います。
その時のコードの書き方は以下を参照。
http://support.microsoft.com/default.aspx?scid=k …
う~ん、適当なデバイスが無いのでテストできないのがモドカシイ。FPGAが載っている安いPCIボードが欲しいですね。
PCIのスペック上、メモリサイクルはコンバインやプリフェッチが許されるので昇順に連続すれば速くなる可能性があるのですが(そして普通は速くなるわけですが)、I/Oサイクルはコンバイン・プリフェッチとも許されない(Strong Order)なので、残念ながら、単独で遅ければ連続しても遅い可能性が高いです。
動作自体に特に問題はないので、激しく困ったというほど切羽詰ってもいないのがまた困るところ(笑)
No.2
- 回答日時:
なるほどぉ。
。。もしかしたらIRQLを上げて実行してみるとちょっとは改善するかも。
後は、PCIのバスの状態をロジアナとかバスアナで見て原因を考えるとか。。。
読み込んでるデータ自体は正常なんですよね?
そもそもコンフィグレーション空間へそんなに頻繁にアクセスするかなぁって気もしますが。
これ以上は分かりそうもないです。スンマセン。
コメントありがとうございます。
念のためIRQLを上げることも試してはみたのですが、得られる数字は変わりませんでした。いちばん頻繁に発生する割り込みであるタイマー割り込みでも間隔が10msあり、1ms以内で終わる1回の試行に影響を及ぼす頻度は少ないと考えられるので、納得できる結果ではあります。
確かにおっしゃるとおり、コンフィグレーション空間は通常、大量にアクセスするわけではないので、少々遅かろうが実用上は差し支えありません。が、コンフィグレーション空間へのアクセスの次はメモリサイクルないしI/Oサイクルでのアクセスがあるわけですが、実はI/Oサイクルもまた同じくらい遅いのです。(I/Oサイクルでは完全にデバイス固有の話になってしまって質問しづらい(質問しても回答してもらいにくい)のでコンフィグレーションレジスタに関する質問にしました。)
メモリサイクル以外は全部遅いのが(今回使用している)チップセットの仕様!とでも判明すれば楽なんですけどね(苦笑)
ちなみにチップセットはインテルのE7221(915のサーバ版)+ICH6Rです。データシートにはソフト的な記述は豊富なのに、ハード的な記述(特にタイミング関係)はほとんど載ってないのが辛いところです。
No.1
- 回答日時:
そもそも、どのようにして時間を計ったのでしょうか?
この回答への補足
テストプログラムの主要部分は以下のようなものです。
ULONG ulTrial = 100; // 試行回数
ULONG ulNumAccess = 1000; // 試行1回ごとのI/Oアクセス回数
ULONG ulMinElapsed = -1; // 経過時間:全試行回数の中でもっとも短いもの
for (ULONG trial = 0; trial < ulTrial; ++trial) {
ULONG ulBefore = *pRealTimeCounter;
for (ULONG n = 0; n < ulNumAccess; n += 1) {
// (1) Accessing PCI Device Configuration Register
// Cycle Time: 920ns, Frequency: 1.09MHz
__asm mov dx, 0x0cfc;
__asm in eax, dx;
// (2) dummy - no I/O access
// Cycle Time: 2.9ns, Frequency: 341 MHz
//volatile PULONG p = &n;
}
ULONG ulAfter = *pRealTimeCounter;
ULONG ulElapsed = ulAfter - ulBefore; // 今回の経過時間
if (ulElapsed < ulMinElapsed) {
ulMinElapsed = ulElapsed;
}
}
pRealTimeCounterはフリーランのカウンタの値が取得できるポインタで、I/Oアクセスループの前後でカウンタの値を取得し、その差を経過時間として使用しています。カウントアップ間隔が約70nsなので、1000回のI/Oアクセスを行うことで0.1ns単位程度の精度を確保しています。
このプログラムの実行中、割り込みを一切禁止していないため、割り込みが発生するとその回の試行では経過時間が大きく計測されます。その影響を避けるため100回の試行を行い、その中で最も経過時間の短いものを最終結果として使用しています。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- システム CPUの問題について 2 2022/07/09 12:04
- BTOパソコン マザーボードのチップセットのレーン数について 3 2022/10/13 19:21
- デスクトップパソコン 古ーいパソコン/Atheros AR2181 PCIe Gigabit LAN コントローラー 7 2022/09/07 12:58
- 統計学 至急!!下の問題が全く分からないです。 教えてください!! 工程能力指数 PCI, PCIkは1.3 8 2022/07/23 09:04
- CPU・メモリ・マザーボード パソコン作りたいです 教えてください 4 2023/03/08 00:34
- その他(パソコン・周辺機器) ATX電源の仕様について教えてください。 2 2022/11/03 17:54
- ビデオカード・サウンドカード 価格.comに記載されているグラフィックボードのバスインターフェースについて 5 2023/04/23 23:09
- ソフトウェア 工場の生産用PCにpciボート(pci2768c)を拡張するのですがドライバがわかりません。インター 1 2022/06/16 22:29
- ドライブ・ストレージ M.2 PCI Express 接続 M.2 PCIe Gen4 x4 接続 SAMSUNG PM9 3 2023/03/14 11:35
- その他(OS) OSとCPUの関係について 2 2023/05/04 23:33
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Macターミナルで実行中のプログ...
-
MACで動く実行ファイルをWindow...
-
プログラムの再起動
-
【C言語】if文内の演算子の優先...
-
プログラミング ソースコード
-
C言語で途中までしか、プログラ...
-
なんかC言語でプログラム書いて...
-
タスクバーのインジケータを作...
-
C# 変数の動的な再定義
-
Borland C++Builder6で、デバッ...
-
ヘッダファイル? malloc.hと...
-
sendkeysにてALT+CTRL+INSERTを...
-
C言語でフォルダを開く
-
一定時間たつと、リセットしたい
-
C言語 fork()について
-
FORTRANについて
-
アクセス[ファイルを開かずに、...
-
他の実行ファイルを実行するプ...
-
SNMPマネージャAPIでメモリリー...
-
”行数のカウント”はどうすれば...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Macターミナルで実行中のプログ...
-
なんかC言語でプログラム書いて...
-
プログラミング ソースコード
-
MACで動く実行ファイルをWindow...
-
実行時エラー429
-
Windows10でDOSゲーム
-
VB上で実行中の無限ループの止め方
-
他のPC上にあるexeを、そのP...
-
sendkeysにてALT+CTRL+INSERTを...
-
VBAで外部プログラムを非表示で...
-
システム資源とは?
-
プロセス間通信について
-
アクセス[ファイルを開かずに、...
-
C言語でプログラムを再起動
-
C言語で途中までしか、プログラ...
-
system関数を使用してsuコマン...
-
終了してもプログラムが実行し...
-
PIC のデータEEPROMに書き込み...
-
実行中の実行ファイルの上書き
-
他の実行ファイルを実行するプ...
おすすめ情報