РЕДАКТИРОВАТЬ: это больше не на 100% правильно из-за продолжающегося растерянности Intel.
Насколько я понимаю, вопрос в том, что вы спрашиваете, как определить количество ядер ЦП и потоков ЦП, которое отличается от определения количества логических и физических ядер в системе. Ядра процессора часто не считаются физическими ядрами в ОС, если они не имеют своего собственного пакета или умирают. Таким образом, ОС сообщит, что Core 2 Duo, например, имеет 1 физический и 2 логических ЦП, а Intel P4 с гиперпотоками будет отображаться точно так же, даже если 2 гиперпотока против 2 ядер ЦП очень отличная производительность.
Я боролся с этим, пока не собрал воедино приведенное ниже решение, которое, как мне кажется, работает как для процессоров AMD, так и для процессоров Intel. Насколько я знаю, и я могу ошибаться, у AMD пока нет потоков ЦП, но они предоставили способ их обнаружения, который, я предполагаю, будет работать на будущих процессорах AMD, которые могут иметь потоки ЦП.
Короче, вот шаги с использованием инструкции CPUID:
- Определение поставщика ЦП с помощью функции CPUID 0
- Проверка HTT бита 28 в функциях CPU EDX из функции CPUID 1
- Получить счетчик логических ядер из EBX [23:16] из функции CPUID 1
- Получите фактическое число ядер процессора без потоков
- Если vendor == 'GenuineIntel', это 1 плюс EAX [31:26] от функции CPUID 4
- Если vendor == 'AuthenticAMD', это 1 плюс ECX [7: 0] от функции CPUID 0x80000008
Звучит сложно, но есть, надеюсь, независимая от платформы программа 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® Core ™ 2 Duo T7500 @ 2,20 ГГц:
logical cpus: 2
cpu cores: 2
hyper-threads: false
Процессор Intel® R Core 2 TM Q8400 @ 2,66 ГГц:
logical cpus: 4
cpu cores: 4
hyper-threads: false
Процессор Intel (R) Xeon (R) E5520 @ 2,27 ГГц (с пакетами физических процессоров x2):
logical cpus: 16
cpu cores: 8
hyper-threads: true
Процессор Intel® R Pentium® 4 3,00 ГГц:
logical cpus: 2
cpu cores: 1
hyper-threads: true