PCI ExpressのDMAを高速化したい
PCI ExpressのDMAを高速化したいと思って実験を重ねてきました。
EXPARTAN-6TでスキャッタギャザーDMAを使って、FPGA→PC方向の転送をしてみました。
下の図の緑色の濃いひと固まりが128バイトなので、転送開始の時点では、256バイトの送信に1.216usかかっているので、210MB/secで転送できていることがわかります。
といっても、これは実際にバスに送信される速度ではなく、FPGA内のBlockRAMに蓄えられているだけです。実際にはルートコンプレックス(PCの中のチップセット。NorthBridge)がWAITをかけてくるので、次第に速度は落ちます。
64kB転送した時点で、256バイトのデータを送るのに1.440u秒かかるようになりました。よって、速度は178MB/secに下がってしまいました。
このような速度の低下がなぜ生じるのか、なぜ、RootComplexはブレーキをかけてくるのか、ということをもう3年くらい悩んできました。
「DMAでPCのメインメモリに直接送りこんでも、Windowsのカーネル(HAL)がキャッシュにライトバックするから、その待ち時間がかかる」という仮説のもとに、いろいろ実験を重ねてきました。
その検証方法として、スキャッタギャザーをさらにバラバラにして32バイトごとに次のページに飛ぶようにしたり、PCI ExpressのパケットのRelaxOrderingやNoSnoopビットをONにしたり、そんなことをいろいろ重ねてきました。
また、ドライバの中でも、KeFlushBuffersをコメントアウトしてみたり、いろいろやってきました。
でも、どうやってもDMAの後半で速度が落ちることを回避できませんでした。だから、やっぱりキャッシュじゃないんじゃないか・・と思い始めてきたのです。
で、ようやくたどり着いたのが、この文章。
「物理アドレス拡張 - PAE メモリと Windows」
http://msdn.microsoft.com/ja-jp/library/windows/hardware/gg487503.aspx
つまり、ある条件のもとでは、HALの中でダブルバッファをしてしまうんだそうです。OSがメモリ空間を拡張している場合、PCI(Express)が32bitのメモリ空間しか指定してこなければ、PCIの中からメインメモリの全域をターゲットにはDMAできません。当然といえば当然ですよね。
本来ならば、物理アドレスは、Dual Address Cycle (DAC) コマンドといって、上下32bitの2回にわけて指定するようになっています。でも、ハードウェア側がそれをサポートしていない、つまり純然たる32bitアドレスで出来ている場合、HALが先頭4GBの適当なアドレスをハードウェアに教えて、ハードウェアにそのアドレスにDMAさせて、その内容をHALが本来のメモリの中にコピーする。そういうことが行われてしまうようです。
上のページには、次のような表があります。
| バス | アダプタ | 結果 |
| DAC | DAC | 最も高いパフォーマンスと安定性。 |
| DAC | DAC 以外 | ダブル バッファリングが必要。 1 2 |
| DAC 以外 | DAC | PCI 標準に準拠していないため、メモリ破損が生じる可能性。Windows は特定の回避操作を実行。3 |
| DAC 以外 | DAC 以外 | ダブル バッファリングが必要。4 |
このダブルバッファが起こる条件とは、DMAアダプタがDACをサポートしていない場合に生じます。バスが非DACで、アダプタが非DACの場合でも起こります。
DMAアダプタを作る際にDma64BitAddresses フラグをTRUEにしたとしても、バスが64bitアドレスをサポートしていないと、強制的にFALSEにされてしまうそうです。
まぁ、よくわかりませんが、PCI Expressデバイスが64bitのアドレスを指定できなければ、アダプタは強制的に非DACになってしまって、ダブルバッファが使われてしまうと考えられます。したがって、FPGAがPCI Expressのトランザクションを発行する際に、64bitアドレスを指定できるようにすればいいのだと思います。
| 固定リンク




コメント