編集: これは Intel の進行中の混乱により、もはや 100% 正しくありません。
私が質問を理解する方法は、システム内の論理コアと物理コアの数を検出するのとは異なる、CPU コアと CPU スレッドの数を検出する方法を尋ねているということです。CPU コアは、独自のパッケージまたはダイがない限り、OS によって物理コアと見なされないことがよくあります。たとえば、OS は Core 2 Duo に 1 つの物理 CPU と 2 つの論理 CPU があると報告し、ハイパースレッドを備えた Intel P4 はまったく同じように報告されますが、2 つのハイパースレッド対 2 つの CPU コアは非常にパフォーマンスに関しては別物です。
以下のソリューションを組み合わせるまで、私はこれに苦労しました。これは、AMD プロセッサと Intel プロセッサの両方で機能すると信じています。私の知る限り、AMD にはまだ CPU スレッドがありませんが、CPU スレッドを持つ可能性のある将来の AMD プロセッサで動作すると思われるそれらを検出する方法を提供しています。
簡単に言えば、CPUID 命令を使用する手順は次のとおりです。
- CPUID 関数 0 を使用して CPU ベンダーを検出する
- CPU ID 機能 1 からの CPU 機能 EDX の HTT ビット 28 を確認します。
- CPUID 関数 1 から EBX[23:16] から論理コア数を取得します。
- 実際の非スレッド CPU コア数を取得する
- vendor == 'GenuineIntel' の場合、これは 1 に CPUID 関数 4 の EAX[31:26] を加えたものです。
- vendor == 'AuthenticAMD' の場合、これは CPUID 関数 0x80000008 からの 1 プラス ECX[7:0] です。
難しそうに聞こえますが、うまくいけば、このトリックを実行するプラットフォームに依存しない C++ プログラムを次に示します。
#include <iostream>
#include <string>
using namespace std;
void cpuID(unsigned i, unsigned regs[4]) {
#ifdef _WIN32
__cpuid((int *)regs, (int)i);
#else
asm volatile
("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
: "a" (i), "c" (0));
// ECX is set to zero for CPUID function 4
#endif
}
int main(int argc, char *argv[]) {
unsigned regs[4];
// Get vendor
char vendor[12];
cpuID(0, regs);
((unsigned *)vendor)[0] = regs[1]; // EBX
((unsigned *)vendor)[1] = regs[3]; // EDX
((unsigned *)vendor)[2] = regs[2]; // ECX
string cpuVendor = string(vendor, 12);
// Get CPU features
cpuID(1, regs);
unsigned cpuFeatures = regs[3]; // EDX
// Logical core count per CPU
cpuID(1, regs);
unsigned logical = (regs[1] >> 16) & 0xff; // EBX[23:16]
cout << " logical cpus: " << logical << endl;
unsigned cores = logical;
if (cpuVendor == "GenuineIntel") {
// Get DCP cache info
cpuID(4, regs);
cores = ((regs[0] >> 26) & 0x3f) + 1; // EAX[31:26] + 1
} else if (cpuVendor == "AuthenticAMD") {
// Get NC: Number of CPU cores - 1
cpuID(0x80000008, regs);
cores = ((unsigned)(regs[2] & 0xff)) + 1; // ECX[7:0] + 1
}
cout << " cpu cores: " << cores << endl;
// Detect hyper-threads
bool hyperThreads = cpuFeatures & (1 << 28) && cores < logical;
cout << "hyper-threads: " << (hyperThreads ? "true" : "false") << endl;
return 0;
}
Windows または OSX でこれを実際にテストしたことはまだありませんが、CPUID 命令は i686 マシンで有効であるため、動作するはずです。明らかに、これは PowerPC では機能しませんが、ハイパースレッドもありません。
以下は、いくつかの異なる Intel マシンでの出力です。
Intel(R) Core(TM)2 Duo CPU T7500 @ 2.20GHz:
logical cpus: 2
cpu cores: 2
hyper-threads: false
Intel(R) Core(TM)2 Quad CPU Q8400 @ 2.66GHz:
logical cpus: 4
cpu cores: 4
hyper-threads: false
Intel(R) Xeon(R) CPU E5520 @ 2.27GHz (x2 物理 CPU パッケージ付き):
logical cpus: 16
cpu cores: 8
hyper-threads: true
Intel(R) Pentium(R) 4 CPU 3.00GHz:
logical cpus: 2
cpu cores: 1
hyper-threads: true