山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他CPUID表示プログラム
概要
CPUのファミリー・モデル・ステッピングとキャッシュの構成やサポートする拡張命令を表示するプログラムです。Prescotまで対応。Athlon等はコア名の表示などはサポートしていない。
コマンドラインで動作します。下記は表示例です。
Banias(Pentium-M) CPUID Prescott(Pentium-IV) CPUID Venice(Athlon64) CPUID
用語解説
浮動小数点ユニット
浮動小数点の計算を専門に扱うハードウェア。8086~80386までは、オプションで装着できた。80486DX以降は、CPUに内臓されている。
条件付き転送命令
パイプラインが深くなると条件分岐で予測が外れるとパイプライン内の命令をすべて実行しなおさなければならない。条件付き転送命令は、条件が成立したときにレジスタの値を書き換える。この命令を使用することにより分岐命令の使用を少なくすることができる。
プロセッサシリアル番号
CPU1個1個それぞれに固有の番号を割り当てそれをCPUID命令で読み出すことを可能としている。
この番号によりCPUの特定ができるため、パスワードの代わり等に使うことが可能となるが、プライバシー等の侵害のもつながると判断され評判が悪く取りやめとなった。BIOSで使用しないようにできる。
MMX サポート
FPUレジスタを命令により切り替えて、レジスタ内に割り当てた複数の整数を同時に演算をすることが可能となる。8bit*8個,16bit*4個,32bit*2個 それぞれについて四則算、論理演算を同時に実行できる。FPU命令とMMX命令は同時に使用できない。またマルチタスク環境では、タスク切り替え時FPUとMMX状態を保存・切り替えなどサポートが必要である。
SSE サポート
専用に設けられた128ビットの8個のレジスタを使用し、単精度浮動小数点*4個の同時演算を可能としている。MMX命令と同時に使用することも可能である。またマルチタスク環境では、タスク切り替え時FPUとMMX状態を保存・切り替えなどサポートが必要である。
SSE2 サポート
SSEに加えて倍精度浮動小数点*2や(8,16,32,64)整数*複数の演算も可能となっている。
SSE3 サポート
SSE2に加えて、加算と減算を同時に行う命令等が追加されている。
ハイパー・スレッディング・テクノロジサポート
1個のCPUで内部の実行ユニットは命令の依存関係等でフルに使われることは少ない。ハイパースレッドでは2個のスレッドを実行可能としこれらのスレッドは依存関係が少ないためより効率よく命令を流すことができる。Windows 2000 では2個のCPUと見えるがOSの最適化が進んでいない。Windows XPはサポート。
拡張版Intel SpeedStep ノンサポート
負荷におうじてCPUの周波数と電圧を動的に変化させ省電力化を目指す。
物理プロセッサ数 2
ハイパースレッド対応CPUでは1以上の数字となる
キャッシュ
Pentium4 Prescot 3.2Eでは6.4GByte/秒(400MHz*8byte*2デュアル)のメモリインターフェースを備えている。2次キャッシュは256bit/8bit*3.2GHz/2=51.2GBytes/秒となります。さらに1次キャッシュは、さらに高速となっています。本来のCPU実力はこの程度もっているはずですが、実際にはメモリに抑えられているのです。したがってキャッシュがなければ異様に遅くなるでしょう。下図は、8ウェイ 64バイトラインサイズで16kbyteのキャッシュメモリのブロック図です。(16K バイト、8 ウェイ・セット・アソシアティブ、64バイト・ライン・サイズ 2~6セットは省略)
各セットは16k/8=2kbyteとなります。ブロックは各セットに2kbyte/64=32個あります。1ブロックに1個ずつタグ値とこのブロックに有効なデータが存在するかを示すフラグがあります。
0番地のデータがほしい場合、ブロック(アドレス6~10bitで表せる数値)0で決まる各セット(8ウェイなので8個)のタグの値を読み出し、それぞれのアドレス比較器でアドレスの14~31bitの値と比較し、該当するセット(ここでは0セット目)のデータを取り出します。8ウェイなので、1ブロックで示される領域は8個以上はキャッシュできないこととなります。
ここで意地悪なメモリアクセスを考えます。下図のように2048byte(キャッシュサイズ16kbyte÷8ウェイ=2048byte)のブロックを16個用意し各ブロックの先頭番地を順々に読み出していく場合、かならずキャッシュミスを起こすコードを書くことができます。このCPUでは2048byteごとにブロックを用意した場合、最大で8個しかキャッシュできないことに起因します。たとえば1ウェイとした場合(ダイレクトマップ)、キャッシュミスが多くなることが予測されます。もちろんウェイの数を(16kbyte/64byte=1024個)とすればキャッシュを最大限に生かせますが、タグメモリとアドレスとタグメモリの値を比較する回路が1024個必要になり回路規模の増大と比較時間が長くなるためかえって遅くなる可能性があり現実的ではありません。
ソース
// CPUIDを表示する Presctoまで対応
// Visual C++ 2005 Express 再配布パッケージが必要
#include <windows.h>
#include <stdio.h>
#include <string.h>
struct REG32{
unsigned eax,ebx,ecx,edx;
};
struct EAX1{
unsigned stepping:4;
unsigned model:4;
unsigned family:4;
unsigned processer_type:2;
unsigned resaved1:2;
unsigned ex_model:4;
unsigned ex_family:8;
unsigned resaved2:4;
// ebx;
unsigned brand_index:8;
unsigned line_size:8;
unsigned processer:8;
unsigned resaved22:8;
// ecx
unsigned sse3:1;
unsigned rev3:2;
unsigned monitor:1;
unsigned ds_cpl:1;
unsigned vmx:1; // Virtualization Technology
unsigned rev31:1;
unsigned est:1;
unsigned tm2:1;
unsigned ssse3:1; // Supplemental Streaming SIMD Extensions 3
unsigned cnxt_id:1;
unsigned rev41:21;
// edx
unsigned fpu:1;
unsigned vme:1;
unsigned de:1;
unsigned pse:1;
unsigned tsc:1;
unsigned msr:1;
unsigned pae:1;
unsigned mce:1;
unsigned cx8:1;
unsigned apic:1;
unsigned rev5:1;
unsigned sep:1;
unsigned mtrr:1;
unsigned pge:1;
unsigned mca:1;
unsigned cmov:1;
unsigned pat:1;
unsigned pse_36:1;
unsigned psn:1;
unsigned clfsh:1;
unsigned rev6:1;
unsigned ds:1;
unsigned acpi:1;
unsigned mmx:1;
unsigned fxsr:1;
unsigned sse:1;
unsigned sse2:1;
unsigned ss:1;
unsigned htt:1;
unsigned tm:1;
unsigned ia64:1;
unsigned pbe:1;
};
struct EAX2{
unsigned char count;
unsigned char tlb[15];
};
const int id_max=128;
char* eax2_str(int n);
char* cpu_code_name(int f,int m,int s);
char* brand_index_string(int id,int f,int m,int s);
void cputest(DWORD reg_eax,REG32* ret_reg){
__asm {
push edi
mov eax,reg_eax
cpuid
mov edi,ret_reg
mov [edi],eax
mov [edi+4],ebx
mov [edi+8],ecx
mov [edi+12],edx
pop edi
}
}
char* eax0x80000006_cache_a(int n){
switch(n){
case 0x00: return "Disabled";
case 0x01: return "Direct mapped";
case 0x02: return "2-way";
case 0x04: return "4-way";
case 0x06: return "8-way";
case 0x08: return "16-way";
case 0x0f: return "Fully associative";
default: return "未定";
}
}
int cpuid_str_get(char* id[id_max]){
REG32 reg;
int max=0;
char buf[128];
char* p;
int n=0;
int u;
do{
cputest(n,®);
switch(n){
case 0:
sprintf(buf,"[CPUID eax=%xh]",n);
id[max++]=strdup(buf);
u=reg.eax;
strncpy(buf,(char*)®.ebx,4);
strncpy(buf+4,(char*)®.edx,4);
strncpy(buf+8,(char*)®.ecx,4);
buf[12]='\0';
id[max++]=strdup(buf);
break;
case 1:{
sprintf(buf,"[CPUID eax=%xh]",n);
id[max++]=strdup(buf);
EAX1* eax1=(EAX1*)®
int f=eax1->family;
int m=eax1->model;
int s=eax1->stepping;
int p=eax1->processer_type;
int em=eax1->ex_model;
int ef=eax1->ex_family;
if(f>=0xf){
f=int(ef<<4)+f;
m=int(em<<4)+m;
}
if(eax1->brand_index){
sprintf(buf,"ブランドインデックス %s",brand_index_string(eax1->brand_index ,f,m,s));
id[max++]=strdup(buf);
}
sprintf(buf,"family=%i,model=%i,stepping=%i",f,m,s);
id[max++]=strdup(buf);
id[max++]=cpu_code_name(eax1->family,eax1->model,eax1->stepping);
sprintf(buf,"オンチップ浮動小数点ユニット %s",eax1->fpu ? "搭載" : "無し");
id[max++]=strdup(buf);
sprintf(buf,"条件付き転送命令 %s",eax1->cmov ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"プロセッサシリアル番号 %s",eax1->psn ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"温度モニタおよびソフトウェア制御クロック機能 %s",eax1->acpi ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"MMX %s",eax1->mmx ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"SSE %s",eax1->sse ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"SSE2 %s",eax1->sse2 ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"SSE3 %s",eax1->sse3 ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"SSSE3 %s",eax1->ssse3 ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"Virtualization Techonology %s",eax1->vmx ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"ハイパー・スレッディング・テクノロジ %s",eax1->htt ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"拡張版Intel SpeedStep %s",eax1->est ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"温度モニター2%s",eax1->tm2 ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"物理アドレス拡張 %s",eax1->pae ? "サポート" : "ノンサポート");
id[max++]=strdup(buf);
sprintf(buf,"物理プロセッサ数 %i",eax1->processer);
id[max++]=strdup(buf);
break;
}
case 2:{
sprintf(buf,"[CPUID eax=%xh]",n);
id[max++]=strdup(buf);
EAX2* eax2=(EAX2*)®
for(int u=0;u<15;u++){
char* p=eax2_str(eax2->tlb[u]);
if(p)
id[max++]=p;
}
break;
}
}
}while(n++<=u && n<id_max);
cputest(0x80000000,®);
if(reg.eax & 0x80000000){
id[max++]="[CPUID eax=0x80000000]";
id[max++]="拡張IDサポート";
u=reg.eax;
int s=0x80000001;
do{
cputest(s,®);
switch(s){
case 0x80000001:
sprintf(buf,"[CPUID eax=%xh]",s);
id[max++]=strdup(buf);
if(reg.edx & 0x40000000) // 29bit
id[max++]="EM64T サポート";
else
id[max++]="EM64T ノンサポート";
if(reg.edx & 0x100000) // 20bit
id[max++]="XD Bit サポート";
else
id[max++]="XD Bit ノンサポート";
if(reg.edx & 0x80000000) // 31bit
id[max++]="3DNow! サポート";
else
id[max++]="3DNow! ノンサポート";
if(reg.edx & 0x40000000) // 31bit
id[max++]="E3DNow! サポート";
else
id[max++]="E3DNow! ノンサポート";
break;
case 0x80000002:
strncpy(buf,(char*)®,16);
break;
case 0x80000003:
strncpy(buf+16,((char*)®),16);
break;
case 0x80000004:
id[max++]="[CPUID eax=0x80000002~0x80000004]";
strncpy(buf+32,((char*)®),16);
p=buf;
while(*p == ' ')
++p;
id[max++]=strdup(p);
break;
case 0x80000006:
sprintf(buf,"[CPUID eax=%xh],ecx=%xh",s , reg.ecx);
id[max++]=strdup(buf);
sprintf(buf,"キャッシュラインサイズ %i,L2アソシアティビティ %s,キャッシュサイズ %ik",reg.ecx & 0xff,eax0x80000006_cache_a((reg.ecx>>12) & 0xf),(reg.ecx>>16) & 0xffff);
id[max++]=strdup(buf);
break;
}
}while(s++<u && max<id_max);
}
return max;
}
char* eax2_str(int n){
char* p=0;
switch(n){
case 0x01:
p="命令TLB 4kバイト・ページ、4ウェイセットアソシアティブ、32エントリ ";
break;
case 0x02:
p="命令TLB 4Mバイト・ページ、フルアソシアティブ、2エントリ ";
break;
case 0x03:
p="データTLB 4kバイト・ページ、4ウェイセットアソシアティブ、64エントリ ";
break;
case 0x04:
p="データTLB 4Mバイト・ページ、4ウェイセットアソシアティブ、8エントリ ";
break;
case 0x06:
p="第1 レベルの命令キャッシュ: 8 K バイト、4 ウェイ・セット・アソシアティブ、32 バイト・ライン・サイズ ";
break;
case 0x08:
p="第1 レベルの命令キャッシュ: 16 K バイト、4 ウェイ・セット・アソシアティブ、32 バイト・ライン・サイズ ";
break;
case 0x0a:
p="第1 レベルのデータ・キャッシュ: 8 K バイト、2 ウェイ・セット・アソシアティブ、32バイト・ライン・サイズ";
break;
case 0xc:
p="第1 レベルのデータ・キャッシュ: 16 K バイト、4 ウェイ・セット・アソシアティブ、32バイト・ライン・サイズ ";
break;
case 0x22:
p="第3 レベルのキャッシュ: 512K バイト、4 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ、128 バイト・セクタ・サイズ ";
break;
case 0x23:
p="第3 レベルのキャッシュ: 1M バイト、8 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ、128 バイト・セクタ・サイズ ";
break;
case 0x25:
p="第3 レベルのキャッシュ: 2M バイト、8 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ、128 バイト・セクタ・サイズ ";
break;
case 0x29:
p="第3 レベルのキャッシュ: 4M バイト、8 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ、128 バイト・セクタ・サイズ ";
break;
case 0x2c:
p="第1 レベルのデータ・キャッシュ 32K バイト、8 ウェイ・セット・アソシアティブ、64バイト・ライン・サイズ";
break;
case 0x30:
p="第1 レベルのデータ・キャッシュ: 32K バイト、8 ウェイ・セット・アソシアティブ、64バイト・ライン・サイズ";
break;
case 0x40:
p="第2 レベルのキャッシュなし。プロセッサに有効な第2 レベルのキャッシュが実装されている場合は、第3 レベルのキャッシュなし";
break;
case 0x41:
p="第2 レベルのキャッシュ: 128 K バイト、4 ウェイ・セット・アソシアティブ、32 バイト・ライン・サイズ";
break;
case 0x42:
p="第2 レベルのキャッシュ: 256 K バイト、4 ウェイ・セット・アソシアティブ、32 バイト・ライン・サイズ";
break;
case 0x43:
p="第2 レベルのキャッシュ: 512 K バイト、4 ウェイ・セット・アソシアティブ、32 バイト・ライン・サイズ";
break;
case 0x44:
p="第2 レベルのキャッシュ: 1 M バイト、4 ウェイ・セット・アソシアティブ、32 バイト・ライン・サイズ";
break;
case 0x45:
p="第2 レベルのキャッシュ: 2M バイト、4 ウェイ・セット・アソシアティブ、32 バイト・ライン・サイズ";
break;
case 0x50:
p="命令TLB: 4K バイト、2M バイト、4M バイト・ページ、64 エントリ ";
break;
case 0x51:
p="命令TLB: 4K バイト、2M バイト、4M バイト・ページ、128 エントリ";
break;
case 0x52:
p="命令TLB: 4K バイト、2M バイト、4M バイト・ページ、256 エントリ";
break;
case 0x5b:
p="データTLB: 4K バイト、4M バイト・ページ、64 エントリ ";
break;
case 0x5c:
p="データTLB: 4K バイト、4M バイト・ページ、128 エントリ";
break;
case 0x5d:
p="データTLB: 4K バイト、4M バイト・ページ、256 エントリ";
break;
case 0x60:
p="第1 レベルのデータ・キャッシュ : 16K バイト、8 ウェイ・セット・アソシアティブ、64バイト・ライン・サイズ ";
break;
case 0x66:
p="第1 レベルのデータ・キャッシュ: 8K バイト、4 ウェイ・セット・アソシアティブ、64バイト・ライン・サイズ";
break;
case 0x67:
p="第1 レベルのデータ・キャッシュ: 16K バイト、4 ウェイ・セット・アソシアティブ、64バイト・ライン・サイズ";
break;
case 0x68:
p="第1 レベルのデータ・キャッシュ: 32K バイト、4 ウェイ・セット・アソシアティブ、64バイト・ライン・サイズ";
break;
case 0x70:
p="トレース・キャッシュ: 12K-μop、8 ウェイ・セット・アソシアティブ ";
break;
case 0x71:
p="トレース・キャッシュ: 16K-μop、8 ウェイ・セット・アソシアティブ";
break;
case 0x72:
p="トレース・キャッシュ: 32K-μop、8 ウェイ・セット・アソシアティブ";
break;
case 0x78:
p="第2 レベルのキャッシュ: 1M バイト、8 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ";
break;
case 0x79:
p="第2 レベルのキャッシュ: 128K バイト、8 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ、128 バイト・セクタ・サイズ";
break;
case 0x7a:
p="第2 レベルのキャッシュ: 256K バイト、8 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ、128 バイト・セクタ・サイズ";
break;
case 0x7b:
p="第2 レベルのキャッシュ: 512K バイト、8 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ、128 バイト・セクタ・サイズ";
break;
case 0x7c:
p="第2 レベルのキャッシュ: 1M バイト、8 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ、128 バイト・セクタ・サイズ";
break;
case 0x7d:
p="第2 レベルのキャッシュ : 2M バイト、8 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ";
break;
case 0x82:
p="第2 レベルのキャッシュ: 256K バイト、8 ウェイ・セット・アソシアティブ、32 バイト・ライン・サイズ";
break;
case 0x83:
p="第2 レベルのキャッシュ : 512K バイト、8 ウェイ・セット・アソシアティブ、32 バイト・ライン・サイズ";
break;
case 0x84:
p="第2 レベルのキャッシュ: 1M バイト、8 ウェイ・セット・アソシアティブ、32 バイト・ライン・サイズ";
break;
case 0x85:
p="第2 レベルのキャッシュ: 2M バイト、8 ウェイ・セット・アソシアティブ、32 バイト・ライン・サイズ";
break;
case 0x86:
p="第2 レベルのキャッシュ: 512K バイト、4 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ";
break;
case 0x87:
p="第2 レベルのキャッシュ: 1M バイト、8 ウェイ・セット・アソシアティブ、64 バイト・ライン・サイズ";
break;
case 0xb0:
p="命令TLB: 4K-Byte Pages, 4 ウェイ・セット・アソシアティブ、128 エントリ";
break;
case 0xb3:
p="データTLB: 4K-Byte Pages, 4 ウェイ・セット・アソシアティブ、128 エントリ";
break;
}
return p;
}
char* cpu_code_name(int f,int m,int s){
switch(f){
case 6:
switch(m){
case 1: return "Pentium Pro";
case 3: return "Pentium 2(klamath)";
case 5: return "Pentium 2(Deschutes)/Celeron(Covington)/Xeon";
case 6: return "Celeron(Mendocion)";
case 7: return "Pentium 3(Katmai)/Xeon(Tanner)";
case 8: return "Pentium 3・Celeron(Coppermine)/Xeon(Cascades)";
case 9: return "Pentium M(Banias)";
case 10: return "Pentium 3(Tualatin 256)/Xeon(Cascades)";
case 11: return "Pentium 3(Tualatin 512)/Celeron(Tualatin)";
case 13: return "Pentium M(Dothan)";
default: return "P6 ファミリ";
}
return 0;
case 15:
switch(m){
case 0: return "Pentium 4(Willamette)/Xeon(Foster)";
case 1: return "Pentium 4・Celeron(Willamette)/Xeon(Foster)";
case 2: return "Pentium 4・Celeron(Northwood)/Xeon(Gallatin/Prestonia)";
case 3: return "Pentium 4(Prescot)/Xeon(Nocona)";
default: return "Pentium 4 ファミリ";
}
}
return 0;
}
char* brand_index_string(int id,int f,int m,int s){
switch(id){
case 0x00: return 0;
case 0x01: return "Intel Celeron";
case 0x02: return "Intel Pentium III";
case 0x03:
if(f==6 && m==0xb && s==1)
return "Intel Celeron";
else
return "Intel Pentium III Xeon";
case 0x04: return "Intel Pentium III";
case 0x06: return "Mobile Intel Pentium III-M";
case 0x07: return "Mobile Intel Celeron";
case 0x08: return "Intel Pentium 4";
case 0x09: return "Intel Pentium 4";
case 0x0a: return "Intel Celeron";
case 0x0b:
if(f==0xf && m==0x1 && s==3)
return "Intel Xeon MP";
else
return "Intel Xeon";
case 0x0c: return "Intel Xeon MP";
case 0x0e:
if(f==0xf && m==0x1 && s==3)
return "Intel Xeon";
else
return "Mobile Intel Pentium 4-M";
case 0xf: return "Mobile Intel Celeron";
case 0x13: return "Mobile Intel Celeron";
case 0x16: return "Intel Pentium M";
default: return "予約コード";
}
}
void main(void){
char* id[id_max];
int max=cpuid_str_get(id);
for(int n=0;n<max;n++)
puts(id[n]);
}