From 25d0614811991c855ce7db0d898dbc6200dfa840 Mon Sep 17 00:00:00 2001 From: Xorg Date: Sun, 10 May 2020 11:47:43 +0200 Subject: [PATCH] Add L1 Instruction Cache information Some CPUs does not have the same associativity for L1D and L1I, as reported in X0rg/CPU-X#119 It adds l1_instruction_assoc and l1_instruction_cacheline in cpu_id_t To avoid confusing, also adds l1_data_assoc and l1_data_cacheline l1_assoc and l1_cacheline are leave untouched for backward compatibility --- cpuid_tool/cpuid_tool.c | 20 ++++++++++++++++---- libcpuid/cpuid_main.c | 8 ++++++-- libcpuid/libcpuid.h | 20 ++++++++++++++++++-- libcpuid/recog_amd.c | 15 ++++++++++----- libcpuid/recog_intel.c | 6 ++++-- 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/cpuid_tool/cpuid_tool.c b/cpuid_tool/cpuid_tool.c index 4721904..561cbe6 100644 --- a/cpuid_tool/cpuid_tool.c +++ b/cpuid_tool/cpuid_tool.c @@ -75,10 +75,12 @@ typedef enum { NEED_L3_SIZE, NEED_L4_SIZE, NEED_L1D_ASSOC, + NEED_L1I_ASSOC, NEED_L2_ASSOC, NEED_L3_ASSOC, NEED_L4_ASSOC, NEED_L1D_CACHELINE, + NEED_L1I_CACHELINE, NEED_L2_CACHELINE, NEED_L3_CACHELINE, NEED_L4_CACHELINE, @@ -133,10 +135,12 @@ matchtable[] = { { NEED_L3_SIZE , "--l3-cache" , 1}, { NEED_L4_SIZE , "--l4-cache" , 1}, { NEED_L1D_ASSOC , "--l1d-assoc" , 1}, + { NEED_L1I_ASSOC , "--l1i-assoc" , 1}, { NEED_L2_ASSOC , "--l2-assoc" , 1}, { NEED_L3_ASSOC , "--l3-assoc" , 1}, { NEED_L4_ASSOC , "--l4-assoc" , 1}, { NEED_L1D_CACHELINE, "--l1d-cacheline", 1}, + { NEED_L1I_CACHELINE, "--l1i-cacheline", 1}, { NEED_L2_CACHELINE , "--l2-cacheline" , 1}, { NEED_L3_CACHELINE , "--l3-cacheline" , 1}, { NEED_L4_CACHELINE , "--l4-cacheline" , 1}, @@ -391,7 +395,10 @@ static void print_info(output_data_switch query, struct cpu_raw_data_t* raw, fprintf(fout, "%d\n", data->l4_cache); break; case NEED_L1D_ASSOC: - fprintf(fout, "%d\n", data->l1_assoc); + fprintf(fout, "%d\n", data->l1_data_assoc); + break; + case NEED_L1I_ASSOC: + fprintf(fout, "%d\n", data->l1_instruction_assoc); break; case NEED_L2_ASSOC: fprintf(fout, "%d\n", data->l2_assoc); @@ -403,7 +410,10 @@ static void print_info(output_data_switch query, struct cpu_raw_data_t* raw, fprintf(fout, "%d\n", data->l4_assoc); break; case NEED_L1D_CACHELINE: - fprintf(fout, "%d\n", data->l1_cacheline); + fprintf(fout, "%d\n", data->l1_data_cacheline); + break; + case NEED_L1I_CACHELINE: + fprintf(fout, "%d\n", data->l1_instruction_cacheline); break; case NEED_L2_CACHELINE: fprintf(fout, "%d\n", data->l2_cacheline); @@ -654,11 +664,13 @@ int main(int argc, char** argv) fprintf(fout, " L2 cache : %d KB\n", data.l2_cache); fprintf(fout, " L3 cache : %d KB\n", data.l3_cache); fprintf(fout, " L4 cache : %d KB\n", data.l4_cache); - fprintf(fout, " L1D assoc. : %d-way\n", data.l1_assoc); + fprintf(fout, " L1D assoc. : %d-way\n", data.l1_data_assoc); + fprintf(fout, " L1I assoc. : %d-way\n", data.l1_instruction_assoc); fprintf(fout, " L2 assoc. : %d-way\n", data.l2_assoc); fprintf(fout, " L3 assoc. : %d-way\n", data.l3_assoc); fprintf(fout, " L4 assoc. : %d-way\n", data.l4_assoc); - fprintf(fout, " L1D line sz: %d bytes\n", data.l1_cacheline); + fprintf(fout, " L1D line sz: %d bytes\n", data.l1_data_cacheline); + fprintf(fout, " L1I line sz: %d bytes\n", data.l1_instruction_cacheline); fprintf(fout, " L2 line sz : %d bytes\n", data.l2_cacheline); fprintf(fout, " L3 line sz : %d bytes\n", data.l3_cacheline); fprintf(fout, " L4 line sz : %d bytes\n", data.l4_cacheline); diff --git a/libcpuid/cpuid_main.c b/libcpuid/cpuid_main.c index aeb3d06..3551a17 100644 --- a/libcpuid/cpuid_main.c +++ b/libcpuid/cpuid_main.c @@ -55,8 +55,8 @@ static void cpu_id_t_constructor(struct cpu_id_t* id) { memset(id, 0, sizeof(struct cpu_id_t)); id->l1_data_cache = id->l1_instruction_cache = id->l2_cache = id->l3_cache = id->l4_cache = -1; - id->l1_assoc = id->l2_assoc = id->l3_assoc = id->l4_assoc = -1; - id->l1_cacheline = id->l2_cacheline = id->l3_cacheline = id->l4_cacheline = -1; + id->l1_assoc = id->l1_data_assoc = id->l1_instruction_assoc = id->l2_assoc = id->l3_assoc = id->l4_assoc = -1; + id->l1_cacheline = id->l1_data_cacheline = id->l1_instruction_cacheline = id->l2_cacheline = id->l3_cacheline = id->l4_cacheline = -1; id->sse_size = -1; } @@ -548,6 +548,10 @@ int cpu_ident_internal(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct default: break; } + /* Backward compatibility */ + /* - Deprecated since v0.5.0 */ + data->l1_assoc = data->l1_data_assoc; + data->l1_cacheline = data->l1_data_cacheline; return set_error(r); } diff --git a/libcpuid/libcpuid.h b/libcpuid/libcpuid.h index a76685c..bd94d0c 100644 --- a/libcpuid/libcpuid.h +++ b/libcpuid/libcpuid.h @@ -310,9 +310,17 @@ struct cpu_id_t { /** L4 cache size in KB. Zero on most systems */ int32_t l4_cache; - /** Cache associativity for the L1 data cache. -1 if undetermined */ + /** Cache associativity for the L1 data cache. -1 if undetermined + * @deprecated replaced by \ref cpu_id_t::l1_data_assoc + */ int32_t l1_assoc; + /** Cache associativity for the L1 data cache. -1 if undetermined */ + int32_t l1_data_assoc; + + /** Cache associativity for the L1 intruction cache. -1 if undetermined */ + int32_t l1_instruction_assoc; + /** Cache associativity for the L2 cache. -1 if undetermined */ int32_t l2_assoc; @@ -322,9 +330,17 @@ struct cpu_id_t { /** Cache associativity for the L4 cache. -1 if undetermined */ int32_t l4_assoc; - /** Cache-line size for L1 data cache. -1 if undetermined */ + /** Cache-line size for L1 data cache. -1 if undetermined + * @deprecated replaced by \ref cpu_id_t::l1_data_cacheline + */ int32_t l1_cacheline; + /** Cache-line size for L1 data cache. -1 if undetermined */ + int32_t l1_data_cacheline; + + /** Cache-line size for L1 intruction cache. -1 if undetermined */ + int32_t l1_instruction_cacheline; + /** Cache-line size for L2 cache. -1 if undetermined */ int32_t l2_cacheline; diff --git a/libcpuid/recog_amd.c b/libcpuid/recog_amd.c index 8c40cf1..ebe14f0 100644 --- a/libcpuid/recog_amd.c +++ b/libcpuid/recog_amd.c @@ -375,10 +375,15 @@ static void decode_amd_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* d unsigned n = raw->ext_cpuid[0][EAX]; if (n >= 0x80000005) { - data->l1_data_cache = (raw->ext_cpuid[5][ECX] >> 24) & 0xff; - data->l1_assoc = (raw->ext_cpuid[5][ECX] >> 16) & 0xff; - data->l1_cacheline = (raw->ext_cpuid[5][ECX]) & 0xff; - data->l1_instruction_cache = (raw->ext_cpuid[5][EDX] >> 24) & 0xff; + /* L1 Data Cache */ + data->l1_data_cache = EXTRACTS_BITS(raw->ext_cpuid[5][ECX], 31, 24); // L1DcSize + data->l1_data_assoc = EXTRACTS_BITS(raw->ext_cpuid[5][ECX], 23, 16); // L1DcAssoc + data->l1_data_cacheline = EXTRACTS_BITS(raw->ext_cpuid[5][ECX], 7, 0); // L1DcLineSize + + /* L1 Instruction Cache */ + data->l1_instruction_cache = EXTRACTS_BITS(raw->ext_cpuid[5][EDX], 31, 24); // L1IcSize + data->l1_instruction_assoc = EXTRACTS_BITS(raw->ext_cpuid[5][EDX], 23, 16); // L1IcAssoc + data->l1_instruction_cacheline = EXTRACTS_BITS(raw->ext_cpuid[5][EDX], 7, 0); // L1IcLineSize } if (n >= 0x80000006) { data->l2_cache = (raw->ext_cpuid[6][ECX] >> 16) & 0xffff; @@ -398,7 +403,7 @@ static void decode_amd_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* d Processor Programming Reference (PPR) for AMD Family 17h Model 71h, Revision B0 Processors: "There are insufficient available encodings to represent all possible L3 associativities. Please refer to Core::X86::Cpuid::CachePropEbx3[CacheNumWays]." - Note: we do not read CPUID_Fn80000001_ECX[22] (AKA TopologyExtensions) to allow retrocompatibility with existing tests */ + Note: we do not read CPUID_Fn80000001_ECX[22] (AKA TopologyExtensions) to allow backward compatibility with existing tests */ data->l3_assoc = EXTRACTS_BITS(raw->amd_fn8000001dh[0x3][EBX], 31, 22) + 1; // Cache number of ways is CacheNumWays + 1 data->l3_cacheline = EXTRACTS_BITS(raw->amd_fn8000001dh[0x3][EBX], 11, 0) + 1; // Cache line size in bytes is CacheLineSize + 1 } else { diff --git a/libcpuid/recog_intel.c b/libcpuid/recog_intel.c index 3f1a5a6..99252e1 100644 --- a/libcpuid/recog_intel.c +++ b/libcpuid/recog_intel.c @@ -463,11 +463,13 @@ static void check_case(uint8_t on, cache_type_t cache, int size, int assoc, int switch (cache) { case L1I: data->l1_instruction_cache = size; + data->l1_instruction_assoc = assoc; + data->l1_instruction_cacheline = linesize; break; case L1D: data->l1_data_cache = size; - data->l1_assoc = assoc; - data->l1_cacheline = linesize; + data->l1_data_assoc = assoc; + data->l1_data_cacheline = linesize; break; case L2: data->l2_cache = size;