diff --git a/src/common/cpu.h b/src/common/cpu.h index 51886b4..54bca8e 100644 --- a/src/common/cpu.h +++ b/src/common/cpu.h @@ -45,8 +45,9 @@ enum { }; enum { - CORE_TYPE_EFFICIENCY, CORE_TYPE_PERFORMANCE, + CORE_TYPE_EFFICIENCY, + CORE_TYPE_LP_EFFICIENCY, CORE_TYPE_UNKNOWN }; diff --git a/src/common/printer.c b/src/common/printer.c index ff2ec53..b3eb65b 100644 --- a/src/common/printer.c +++ b/src/common/printer.c @@ -614,8 +614,9 @@ bool print_cpufetch_x86(struct cpuInfo* cpu, STYLE s, struct color** cs, struct } if(hybrid_architecture) { - if(ptr->core_type == CORE_TYPE_EFFICIENCY) sprintf(cpu_num, "E-cores:"); - else if(ptr->core_type == CORE_TYPE_PERFORMANCE) sprintf(cpu_num, "P-cores:"); + if (ptr->core_type == CORE_TYPE_PERFORMANCE) sprintf(cpu_num, "P-cores:"); + else if (ptr->core_type == CORE_TYPE_EFFICIENCY) sprintf(cpu_num, "E-cores:"); + else if (ptr->core_type == CORE_TYPE_LP_EFFICIENCY) sprintf(cpu_num, "LP-E-cores:"); else printBug("Found invalid core type!\n"); setAttribute(art, ATTRIBUTE_CPU_NUM, cpu_num); diff --git a/src/x86/cpuid.c b/src/x86/cpuid.c index 5d993c9..83a84a8 100644 --- a/src/x86/cpuid.c +++ b/src/x86/cpuid.c @@ -397,6 +397,17 @@ bool set_cpu_module(int m, int total_modules, int32_t* first_core) { uint32_t edx = 0; cpuid(&eax, &ebx, &ecx, &edx); int32_t core_type = eax >> 24 & 0xFF; + + // Here we artificially create a new core type for + // LP-E cores. In case the core has no L3 (on a hybrid) + // architecture, then we now it's an LP-E core. + eax = 0x4; + ebx = 0; + ecx = 0x3; + edx = 0; + cpuid(&eax, &ebx, &ecx, &edx); + core_type += eax == 0; + bool found = false; for(int j=0; j < total_modules && !found; j++) { @@ -423,13 +434,19 @@ bool set_cpu_module(int m, int total_modules, int32_t* first_core) { #endif } else { - // This is a normal architecture + // This is a non-hybrid architecture *first_core = 0; } return true; } +// Difference between E and LP-E cores: +// According to Intel Core Ultra Processor Datasheet Volume 1 of 2 +// (https://www.intel.com/content/www/us/en/content-details/792044/intel-core-ultra-processor-datasheet-volume-1-of-2.html), +// LP-E cores do not have L3 cache. This seems to be the only way of differentiating them. +// - https://community.intel.com/t5/Processors/Detecting-LP-E-Cores-on-Meteor-Lake-in-software/m-p/1584555/highlight/true#M70732 +// - https://x.com/InstLatX64/status/1741416428538941718 int32_t get_core_type(void) { uint32_t eax = 0x0000001A; uint32_t ebx = 0; @@ -440,8 +457,26 @@ int32_t get_core_type(void) { cpuid(&eax, &ebx, &ecx, &edx); int32_t type = eax >> 24 & 0xFF; - if(type == 0x20) return CORE_TYPE_EFFICIENCY; - else if(type == 0x40) return CORE_TYPE_PERFORMANCE; + if (type == 0x40) return CORE_TYPE_PERFORMANCE; + else if (type == 0x20) { + // get_core_type is only called iff hybrid_flag is true, which can only + // happen if CPUID maxLevel >= 0x7 so we can assume the CPU supports + // CPUID leaf 0x4 + eax = 0x4; + ebx = 0; + ecx = 0x3; + edx = 0; + + cpuid(&eax, &ebx, &ecx, &edx); + + if (eax == 0) { + // No L3 access, this is LP-E + return CORE_TYPE_LP_EFFICIENCY; + } + else { + return CORE_TYPE_EFFICIENCY; + } + } else { printErr("Found invalid core type: 0x%.8X\n", type); return CORE_TYPE_UNKNOWN; @@ -456,7 +491,6 @@ struct cpuInfo* get_cpu_info(void) { cpu->cach = NULL; cpu->feat = NULL; - cpu->num_cpus = 1; uint32_t eax = 0; uint32_t ebx = 0; uint32_t ecx = 0; @@ -514,7 +548,13 @@ struct cpuInfo* get_cpu_info(void) { cpu->hybrid_flag = (edx >> 15) & 0x1; } - if(cpu->hybrid_flag) cpu->num_cpus = 2; + if(cpu->hybrid_flag) { + struct uarch* tmp = get_cpu_uarch(cpu); + cpu->num_cpus = get_hybrid_num_cpus(tmp); + } + else { + cpu->num_cpus = 1; + } struct cpuInfo* ptr = cpu; for(uint32_t i=0; i < cpu->num_cpus; i++) { @@ -529,8 +569,9 @@ struct cpuInfo* get_cpu_info(void) { ptr->topo = NULL; ptr->cach = NULL; ptr->feat = NULL; - // We assume that this cores have the - // same cpuid capabilities + // We assume that this core has the + // same cpuid capabilities as the core in the + // first module ptr->cpu_vendor = cpu->cpu_vendor; ptr->maxLevels = cpu->maxLevels; ptr->maxExtendedLevels = cpu->maxExtendedLevels; diff --git a/src/x86/uarch.c b/src/x86/uarch.c index 03872a7..8bf9b18 100644 --- a/src/x86/uarch.c +++ b/src/x86/uarch.c @@ -94,6 +94,7 @@ enum { UARCH_TIGER_LAKE, UARCH_ALDER_LAKE, UARCH_RAPTOR_LAKE, + UARCH_METEOR_LAKE, // AMD // UARCH_AM486, UARCH_AM5X86, @@ -248,6 +249,7 @@ struct uarch* get_uarch_from_cpuid_intel(uint32_t ef, uint32_t f, uint32_t em, u CHECK_UARCH(arch, 0, 6, 10, 5, NA, "Comet Lake", UARCH_COMET_LAKE, 14) // wikichip CHECK_UARCH(arch, 0, 6, 10, 6, NA, "Comet Lake", UARCH_COMET_LAKE, 14) // instlatx64.atw.hu (i7-10710U) CHECK_UARCH(arch, 0, 6, 10, 7, NA, "Rocket Lake", UARCH_ROCKET_LAKE, 14) // instlatx64.atw.hu (i7-11700K) + CHECK_UARCH(arch, 0, 6, 10, 10, NA, "Meteor Lake", UARCH_METEOR_LAKE, 7) // instlatx64.atw.hu (Ultra 7 155H) CHECK_UARCH(arch, 0, 6, 11, 7, NA, "Raptor Lake", UARCH_RAPTOR_LAKE, 10) // instlatx64.atw.hu (i5-13600K) CHECK_UARCH(arch, 0, 6, 11, 10, NA, "Raptor Lake", UARCH_RAPTOR_LAKE, 10) // instlatx64.atw.hu (i7-1370P) CHECK_UARCH(arch, 0, 6, 11, 14, NA, "Alder Lake", UARCH_ALDER_LAKE, 10) // instlatx64.atw.hu (Alder Lake-N) @@ -536,6 +538,7 @@ int get_number_of_vpus(struct cpuInfo* cpu) { case UARCH_TIGER_LAKE: case UARCH_ALDER_LAKE: case UARCH_RAPTOR_LAKE: + case UARCH_METEOR_LAKE: // AMD case UARCH_ZEN2: @@ -549,6 +552,11 @@ int get_number_of_vpus(struct cpuInfo* cpu) { } } +uint32_t get_hybrid_num_cpus(struct uarch* arch) { + if (arch->uarch == UARCH_METEOR_LAKE) return 3; + else return 2; +} + bool choose_new_intel_logo_uarch(struct cpuInfo* cpu) { switch(cpu->arch->uarch) { case UARCH_ALDER_LAKE: diff --git a/src/x86/uarch.h b/src/x86/uarch.h index 68a2d33..5fabecc 100644 --- a/src/x86/uarch.h +++ b/src/x86/uarch.h @@ -12,6 +12,7 @@ char* infer_cpu_name_from_uarch(struct uarch* arch); bool vpus_are_AVX512(struct cpuInfo* cpu); bool is_knights_landing(struct cpuInfo* cpu); int get_number_of_vpus(struct cpuInfo* cpu); +uint32_t get_hybrid_num_cpus(struct uarch* arch); bool choose_new_intel_logo_uarch(struct cpuInfo* cpu); char* get_str_uarch(struct cpuInfo* cpu); char* get_str_process(struct cpuInfo* cpu);