tl;dr: Este es el comportamiento correcto, tal y como lo diseñó Intel.
Detalles:
machdep.cpu.logical_per_package
se implementa en el núcleo en bsd/dev/i386/sysctl.c
:
static int
cpu_logical_per_package SYSCTL_HANDLER_ARGS
{
__unused struct sysctl_oid *unused_oidp = oidp;
__unused void *unused_arg1 = arg1;
__unused int unused_arg2 = arg2;
i386_cpu_info_t *cpu_info = cpuid_info();
if (!(cpuid_features() & CPUID_FEATURE_HTT)) {
return ENOENT;
}
return SYSCTL_OUT(req, &cpu_info->cpuid_logical_per_package,
sizeof(cpu_info->cpuid_logical_per_package));
}
Este sysctl
devuelve el cpuid_logical_per_package
campo del cpu_info
estructura. Para ver cómo se rellena ese campo, examinamos osfmk/i386/cpuid.c
:
static void
cpuid_set_generic_info(i386_cpu_info_t *info_p)
{
...
cpuid_fn(1, reg);
...
if (info_p->cpuid_features & CPUID_FEATURE_HTT) {
info_p->cpuid_logical_per_package =
bitfield32(reg[ebx], 23, 16);
} else {
info_p->cpuid_logical_per_package = 1;
}
...
}
La primera parte de esta función ejecuta el programa Intel x86 CPUID
con un valor de operando de 1
que recopilará cierta información de la CPU y rellenará el archivo E[A,B,C,D]X
se registra con él. Más adelante examinaremos los bits 16-23
de la EBX
y guardarlas en el cpuid_logical_per_package
campo.
Para comprender el significado de lo que se encontrará en ese campo de bits de EBX
pasamos a la Manual del desarrollador de software Intel , Volumen 2A, capítulo 3, página 215 ( CPUID-Identificación de la CPU ) y busque la definición de registro para 1
opcode:
La parte que nos interesa dice:
Bits 23 - 16: Número máximo de ID direccionables para procesadores lógicos en este paquete físico *.
*- El entero de potencia de 2 más cercano que no sea menor que EBX[23:16] es el número de IDs APIC iniciales únicos reservados para el direccionamiento diferentes procesadores lógicos en un paquete físico. Este campo sólo es válido si CPUID.1.EDX.HTT[bit 28]= 1.
Así que lo que esto nos está diciendo es que el sysctl
nombre del selector " cpu_logical_per_package
" es un término equivocado . Te dice el rango válido de números ID que el controlador de interrupciones puede utilizar para identificar CPUs lógicas y esto hace no se corresponden necesariamente con el número de CPU lógicas que tiene en realidad.
La situación es análoga para machdep.cpu.cores_per_package
que se genera en cpuid_set_cache_info()
en el mismo osfmk/i386/cpuid.c
archivo:
static void
cpuid_set_cache_info( i386_cpu_info_t * info_p )
{
...
reg[eax] = 4; /* cpuid request 4 */
reg[ecx] = index; /* index starting at 0 */
cpuid(reg);
...
info_p->cpuid_cores_per_package
= bitfield32(reg[eax], 31, 26) + 1;
...
}
Y mirando el SDM :
Así que la moraleja es:
Debe confiar en machdep.cpu.core_count
y .thread_count
para determinar el número real de núcleos físicos y lógicos, respectivamente, y consideran que los otros dos campos sólo son útiles para los programadores que necesitan trabajar con el núcleo y tienen una necesidad específica de conocer el ID máximo direccionable para los procesadores lógicos y físicos.
Si aún se pregunta por qué un procesador lógico o físico puede tener un ID superior al número real de procesadores disponibles en el silicio, la razón es que es el resultado de la forma en que se fabrica el silicio. La fabricación de chips es un proceso enormemente caro y complejo, y cualquier reducción de la complejidad va a ahorrar millones de dólares. Resulta que es más barato fabricar un chip con ocho núcleos físicos grabados en la matriz y luego quemar unos cuantos fusibles internos programables una sola vez para desconectar cuatro de los núcleos físicos de ese circuito, que crear máscaras y herramientas específicas para una matriz de cuatro núcleos totalmente separada. Así que Intel fabrica un montón de chips de 8 núcleos y luego vende la versión amputada de 4 núcleos más barata.
Sin embargo, la mayor parte del resto del chip sigue pensando que tiene 8 núcleos. Cada subsistema de un procesador tiene un identificador único con el que el resto de subsistemas pueden identificarlo. 1
s y 0
s para representar un número decimal. Como estos ID están hechos de transistores, son partes inmutables de la máscara y no cambian aunque se fundan los fusibles OTP para desactivar la mitad de los núcleos. Por lo tanto, un chip original de 8 núcleos puede tener, por ejemplo, identificadores lógicos de núcleo que oscilen entre 0-15
pero la versión más barata de 4 núcleos sólo utiliza IDs 8-15
y la primera 0-7
no son realmente direccionables. Por lo tanto, el esquema de numeración puede ser mayor que el número real de núcleos disponibles. Espero que esto tenga sentido.