いきさつ
AMDのK6-2の新コアにはMTRR(Memory Type Range Register)なるものがあり、Write-Combiningの設定ができるようになっている。うれしいことにWAmonitorIIなるツールがあって簡単に設定できる。振り返ってIntelを見てみると、もっと前から同様の機能を持っているのだった。実際にはPentiumPRO以降のP6family(PenPRO,Pen2,Celeron,Pen3)ではMTRRが使えるようになっている。こいつらの設定はMSR(Model Specific Register)というCPU上のレジスタをいじるようになっている。そこでうちのCeleronマシンではこのMTRRがどのように設定されているかを見て、 もしもうっかり設定されていないようなら設定を追加してパフォーマンスアップをはかってやろうと考えたのである。
MSR自体はPentium以降で使えるようである。ここで登場するのはMSRを手軽に読み書きする簡単なプログラムである。
MSRRW.EXE(34.5K)
使い方は下のMSRrw98.exeまたはMSRrwNT.exeを参照のこと。
といった手続きで行うことになっている。MSRRing0.TXTに出ていたControlCodeとInBuff、OutBuffというものはDeviceIoControl()で使うものである。
そこで次のようなMSRの読み出しプログラムをさらっと書いてみた。(動くようになるまで結構かかっているのだが...)
これはVariable MTRRを8セット読むプログラムである(Intel P6Family用)。
#include <windows.h> #include <winbase.h> #include <stdio.h> main() { int i; HANDLE hVxD; int InBuff[0x10]; int OutBuff[0x10]; ULONG BytesReturn; hVxD = CreateFile("\\\\.\\msrring0.VXD", 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL); if( hVxD == INVALID_HANDLE_VALUE){ printf("VxD Open Error%d\n",GetLastError()); exit(1); } for(i=0x200;i<=0x20f;i++){ InBuff[0] = i; DeviceIoControl( hVxD, 2, // control code:Read InBuff, 0x4, OutBuff, 0x40, &BytesReturn, 0); printf("%04X %08X:%08X\n", i, OutBuff[2], OutBuff[1]); } CloseHandle(hVxD); }
ちなみにライト系は
InBuff[0] = iMSRAdd; InBuff[2] = iMSRHigh; InBuff[1] = iMSRLow; DeviceIoControl( hVxD, 3, // control code:Write InBuff, 0xC, OutBuff, 0x0, &BytesReturn, 0);
のようになる。
ここまでで動くことを確認できたので、ちゃんとした読み書きプログラムを書いてみたのが、これ。MSRを連続して読みこんで表示する、またはレジスタを指定して値を書きこむことができます。どこのアドレスにどのようなレジスタがあるかはIntel Architecture Software Developer's Manual Volume3のAppendix B(Intel CPUの場合)などをお調べください。今のところWindows95/98のMS-DOSプロンプトでしか動きません。NTに関しては研究中。
またMSR自体はPentium以降のCPUにあり、このツールが使えますが、CPUのモデルにより内容が違います。PentiumやK6-2/3にどのようなMSRがあるかは調べてみてください。
MSRrw98.exe(34K)
フリーウェアとして使用料は無料としますが、配布不可にしておきます。
このプログラムを使った結果がどうなろうと製作者は一切責任を負いません。すべての責任は使用者で負っていただきます。CPUIDもなにも見ていないし、MSRアドレスの範囲チェックも行っていないので、なにも知らずに使うと青画面連発となることでしょう。
使い方(Windows95/98編):
MSR read/write Ver.1.00 MSRrw R Add1 Add2 : Read MSR Add1 to Add2 MSRrw W Add RegHigh RegLow : Write MSR Add RegHigh:RegLow
ここからは本来の目的であった「P6family」のMTRRに関して書いておく。
MTRRはMSRの0x200から0x20Fに設定する。まずはそこを読み出してみる。うちでは
MSRRW98 R 200 20F MSR read/write Ver.1.00 0200 00000000:00000006 メインメモリ(00000000-07FFFFFF) 0201 0000000F:F8000800 0202 00000000:E2000000 82443BX Processor to PCI Bridge(with GART support)(E2000000-E27FFFFF) 0203 0000000F:FF800800 0204 00000000:E2800001 同上(E2800000-E2FFFFFF) 0205 0000000F:FF800800 0206 00000000:E3000001 82443BX AGP controllerとRAGE PRO(E3000000-E37FFFFF) 0207 0000000F:FF800800 0208 00000000:E6000001 Voodoo Graphics 3D Accelerator(E6000000-E6FFFFFF) 0209 0000000F:FF000800 020A 00000000:E6000000 同上(E6000000-E6000FFF) 020B 0000000F:FFFFF800 020C 00000000:00000000 未使用 020D 00000000:00000000 020E 00000000:00000000 未使用 020F 00000000:00000000
と出た。隣には使っているデバイスを書き加えてある。レジスタは2つ1組で、1つ目の0000000X:XXXXX000がベースアドレス、00000000:000000XXがメモリのタイプを表す。メモリのタイプは
0 Uncacheable(UC)
1 Write Combining(WC)
4 Write Through(WT)
5 Write Protected(WP)
6 WriteBack(WB)
2,3,7-255 Reserved
となっている。
2つ目は0000000X:XXXXX000がマスク、00000000:00000800のビットが有効=1/無効=0を示している。
例えば上の例で、
0206 00000000:E3000001 0207 0000000F:FF800800とあるが、これはメモリのE3000000からE37FFFFFをWriteCombiningにするという意味である。上ではE6000000からE6000FFFが他と重なっているが、このようにWCとUCが重なったときはUCになる、とDeveloper's Manualには出ている。
MSRRW98 W 200 0 0とする。とたんにめちゃくちゃ遅くなるだろう。なんせL1キャッシュが効いていないのだから。戻すには
MSRRW98 W 200 0 6だ。(ライトバックである)
と、ここまでやっておきながら、私の場合は新たに設定してもさっぱり効果が見られなかった。元々必要そうなところ(RagePROとVoodoo)にはWCの設定が入っちゃってるので仕方がないか。
#include <windows.h> #include <winbase.h> #include <stdio.h> main() { DWORD i; HANDLE hVxD; DWORD InBuff[0x10]; DWORD OutBuff[0x10]; DWORD BytesReturn; //ドライバの名前とオープンのパラメータが違う hVxD = CreateFile("\\\\.\\msrtouch", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ| FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if( hVxD == INVALID_HANDLE_VALUE){ printf("device Open Error %d\n",GetLastError()); exit(1); } for(i=0x200;i<=0x20f;i++){ //InBuffの順番が違う 0=下位のデータ、1=MSRアドレス、2=上位のデータ InBuff[1] = i; DeviceIoControl( hVxD, 0x85002000, //コントロールコードが違う(Read) InBuff, 0x10, OutBuff, 0x10, &BytesReturn, 0); //OutBuffの順番も違う 0=下位のデータ、1=MSRアドレス、2=上位のデータ printf("%04X %08X:%08X\n", i, OutBuff[2], OutBuff[0]); } CloseHandle(hVxD); exit(0); }
ちなみにライト系は
//InBuffの順番が違う 0=下位のデータ、1=MSRアドレス、2=上位のデータ InBuff[1] = iMSRAdd; InBuff[2] = iMSRHigh; InBuff[0] = iMSRLow; printf("%04X %08X:%08X\n", InBuff[1], InBuff[2], InBuff[0]); DeviceIoControl( hVxD, 0x85002004, //コントロールコードが違う(Write) InBuff, 0x10, OutBuff, 0x10, &BytesReturn, 0);
のようになる。
これを動かすにはドライバを組み込んで再起動する必要がある。この点については下の配布版を参照。
ちゃんと動くことを確認できたので、簡単な読み書きプログラムを書いてみたのが、これ(WindowsNT用)。MSRを連続して読みこんで表示する、またはレジスタを指定して値を書きこむことができます。どこのアドレスにどのようなレジスタがあるかはIntel Architecture Software Developer's Manual Volume3のAppendix B(Intel CPUの場合)などをお調べください。
MSRrwNT.exe(35.5K)
※公開当時のものとは変更してVer.1.01になっています。
フリーウェアとして使用料は無料としますが、配布不可にしておきます。
このプログラムを使った結果がどうなろうと製作者は一切責任を負いません。すべての責任は使用者で負っていただきます。CPUIDもなにも見ていないし、MSRアドレスの範囲チェックも行っていないので、なにも知らずに使うと青画面連発(=再起動)となることでしょう。
使い方(WindowsNT編):
MSR read/write for NT Ver.1.01 MSRrwNT R Add1 Add2 : Read MSR Add1 to Add2 MSRrwNT W Add RegHigh RegLow : Write MSR Add RegHigh:RegLow
ここからは私の会社マシン(WindowsNT,PentiumPRO)に入れてみたときの話を書いておく。グラフィックボードはMillennium4Mである。
MTRRはMSRの0x200から0x20Fに設定する。まずはそこを読み出してみる。
MSRRWNT R 200 20F MSR read/write Ver.1.00 0200 00000000:00000006 メインメモリ(00000000-03FFFFFF) 0201 0000000F:FC000800 0202 00000000:00000000 未使用 0203 00000000:00000000 0204 00000000:00000000 未使用 0205 00000000:00000000 0206 00000000:00000000 未使用 0207 00000000:00000000 0208 00000000:00000000 未使用 0209 00000000:00000000 020A 00000000:00000000 未使用 020B 00000000:00000000 020C 00000000:00000000 未使用 020D 00000000:00000000 020E 00000000:00000000 未使用 020F 00000000:00000000
と出た。単にメインメモリ(64Mバイト)をライトバックにしてるだけ。レジスタは2つ1組で、1つ目の0000000X:XXXXX000がベースアドレス、00000000:000000XXがメモリのタイプを表す。メモリのタイプは
0 Uncacheable(UC)
1 Write Combining(WC)
4 Write Through(WT)
5 Write Protected(WP)
6 WriteBack(WB)
2,3,7-255 Reserved
となっている。
2つ目は0000000X:XXXXX000がマスク、00000000:00000800のビットが有効=1/無効=0を示している。
例えば上の例で、
0200 00000000:00000006 0201 0000000F:FC000800とあるが、これはメモリの00000000から03FFFFFFをWriteBackにするという意味である。
MSRRWNT W 202 0 40000001 MSRRWNT W 203 F FFC00800としてみる。なんとなく速くなった気分。なんかわかりやすい違いはないかと探してみると、ウインドウの内容を表示したままドラッグが明らかに速い。今まではウインドウの跡の書き換えがもたついて白く残像が残っていたのが、ほとんどなくなってごく普通に使えるようになった。明らかな改善である。
250 06060606:06060606 258 06060606:06060606 259 01010101:00000000 268 05050505:05050505 269 00000000:00000000 26a 00000000:00000000 26b 00000000:00000000 26c 00000000:00000000 26d 00000000:00000000 26e 00000000:00000000 26f 00000000:00000000だった。頭の640K空間はライトバック、VRAMはWC、VIDEO BIOSとSCSI BIOSはライトプロテクト、他はキャッシュしないになっている。まあ効果はわからないが、
259 01010101:01010101 269 06060606:06060606 26a 06060606:06060606 26b 06060606:06060606 26c 06060606:06060606 26d 06060606:06060606 26e 06060606:06060606 26f 06060606:06060606としてみた。
0FE 00000000:00000508 MTRRcap 2FF 00000000:00000C00 MTRRdefTypeMTRRcapの0400ビットはWCをサポートしている、0100ビットはFIXED MTRRをサポートしている、08はVariable MTRRの使える数を示している。
msrrw98 W 202 00000000 E6000000 Intel 82443BX Pentium(r)II Processor to PCI bridge(with GART support) msrrw98 W 203 0000000F FFE00800 msrrw98 W 204 00000000 E6200001 同上 msrrw98 W 205 0000000F FFE00800 msrrw98 W 206 00000000 E2000001 Intel 82443BX Pentium(r)II Processor to AGP controllerと msrrw98 W 207 0000000F FF800800 RAGE PRO TURBO AGP 2X(English)(DirectX) msrrw98 W 208 00000000 E5000001 Voodoo Graphics 3D Accelerator msrrw98 W 209 0000000F FF000800 msrrw98 W 20a 00000000 E5000000 同上 msrrw98 W 20b 0000000F FFFFF800 msrrw98 W 20c 00000000 E6400001 Monster Sound II Multifunction Parentと msrrw98 W 20d 0000000F FFF80800 Monster Sound II PCI Audioと Adaptec AHA-2040/AHA-2040W PCI SCSI Controllerと TVチューナー&ビデオキャプチャボードGV-BCTVシリーズと PCI Fast Ethernet DEC 21143 Based Adapter
http://www10.plala.or.jp/p205tb16/msr.html
坂井瑞穂