|
#include <stdio.h> |
|
#include <stdint.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <malloc.h> |
|
#include <errno.h> |
|
#include <sys/types.h> |
|
|
|
#include <cpuinfo.h> |
|
#include <cpuinfo/internal-api.h> |
|
#include <cpuinfo/log.h> |
|
|
|
#include "windows-arm-init.h" |
|
|
|
#define MAX_NR_OF_CACHES (cpuinfo_cache_level_max - 1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t count_logical_processors( |
|
const uint32_t max_group_count, |
|
uint32_t* global_proc_index_per_group); |
|
|
|
static uint32_t read_packages_for_processors( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t number_of_processors, |
|
const uint32_t* global_proc_index_per_group, |
|
const struct woa_chip_info *chip_info); |
|
|
|
static uint32_t read_cores_for_processors( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t number_of_processors, |
|
const uint32_t* global_proc_index_per_group, |
|
struct cpuinfo_core* cores, |
|
const struct woa_chip_info *chip_info); |
|
|
|
static uint32_t read_caches_for_processors( |
|
struct cpuinfo_processor *processors, |
|
const uint32_t number_of_processors, |
|
struct cpuinfo_cache *caches, |
|
uint32_t* numbers_of_caches, |
|
const uint32_t* global_proc_index_per_group, |
|
const struct woa_chip_info *chip_info); |
|
|
|
static uint32_t read_all_logical_processor_info_of_relation( |
|
LOGICAL_PROCESSOR_RELATIONSHIP info_type, |
|
struct cpuinfo_processor* processors, |
|
const uint32_t number_of_processors, |
|
struct cpuinfo_cache* caches, |
|
uint32_t* numbers_of_caches, |
|
struct cpuinfo_core* cores, |
|
const uint32_t* global_proc_index_per_group, |
|
const struct woa_chip_info *chip_info); |
|
|
|
static bool parse_relation_processor_info( |
|
struct cpuinfo_processor* processors, |
|
uint32_t nr_of_processors, |
|
const uint32_t* global_proc_index_per_group, |
|
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info, |
|
const uint32_t info_id, |
|
struct cpuinfo_core* cores, |
|
const struct woa_chip_info *chip_info); |
|
|
|
static bool parse_relation_cache_info( |
|
struct cpuinfo_processor* processors, |
|
struct cpuinfo_cache* caches, |
|
uint32_t* numbers_of_caches, |
|
const uint32_t* global_proc_index_per_group, |
|
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info); |
|
|
|
static void store_package_info_per_processor( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t processor_global_index, |
|
const uint32_t package_id, |
|
const uint32_t group_id, |
|
const uint32_t processor_id_in_group); |
|
|
|
static void store_core_info_per_processor( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t processor_global_index, |
|
const uint32_t core_id, |
|
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX core_info, |
|
struct cpuinfo_core* cores, |
|
const struct woa_chip_info *chip_info); |
|
|
|
static void store_cache_info_per_processor( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t processor_global_index, |
|
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info, |
|
struct cpuinfo_cache* current_cache); |
|
|
|
static bool connect_packages_cores_clusters_by_processors( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t nr_of_processors, |
|
struct cpuinfo_package* packages, |
|
const uint32_t nr_of_packages, |
|
struct cpuinfo_cluster* clusters, |
|
struct cpuinfo_core* cores, |
|
const uint32_t nr_of_cores, |
|
const struct woa_chip_info* chip_info, |
|
enum cpuinfo_vendor vendor); |
|
|
|
static inline uint32_t low_index_from_kaffinity(KAFFINITY kaffinity); |
|
|
|
|
|
bool cpu_info_init_by_logical_sys_info( |
|
const struct woa_chip_info *chip_info, |
|
const enum cpuinfo_vendor vendor) |
|
{ |
|
struct cpuinfo_processor* processors = NULL; |
|
struct cpuinfo_package* packages = NULL; |
|
struct cpuinfo_cluster* clusters = NULL; |
|
struct cpuinfo_core* cores = NULL; |
|
struct cpuinfo_cache* caches = NULL; |
|
struct cpuinfo_uarch_info* uarchs = NULL; |
|
|
|
uint32_t nr_of_packages = 0; |
|
uint32_t nr_of_cores = 0; |
|
uint32_t nr_of_all_caches = 0; |
|
uint32_t numbers_of_caches[MAX_NR_OF_CACHES] = {0}; |
|
|
|
uint32_t nr_of_uarchs = 0; |
|
bool result = false; |
|
|
|
HANDLE heap = GetProcessHeap(); |
|
|
|
|
|
const uint32_t max_group_count = (uint32_t) GetMaximumProcessorGroupCount(); |
|
cpuinfo_log_debug("detected %"PRIu32" processor group(s)", max_group_count); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t* global_proc_index_per_group = |
|
(uint32_t*) HeapAlloc(heap, 0, max_group_count * sizeof(uint32_t)); |
|
if (global_proc_index_per_group == NULL) { |
|
cpuinfo_log_error( |
|
"failed to allocate %zu bytes for descriptions of %"PRIu32" processor groups", |
|
max_group_count * sizeof(struct cpuinfo_processor), max_group_count); |
|
goto clean_up; |
|
} |
|
|
|
uint32_t nr_of_processors = |
|
count_logical_processors(max_group_count, global_proc_index_per_group); |
|
processors = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_processors * sizeof(struct cpuinfo_processor)); |
|
if (processors == NULL) { |
|
cpuinfo_log_error( |
|
"failed to allocate %zu bytes for descriptions of %"PRIu32" logical processors", |
|
nr_of_processors * sizeof(struct cpuinfo_processor), nr_of_processors); |
|
goto clean_up; |
|
} |
|
|
|
|
|
nr_of_packages = read_packages_for_processors( |
|
processors, nr_of_processors, |
|
global_proc_index_per_group, |
|
chip_info); |
|
if (!nr_of_packages) { |
|
cpuinfo_log_error("error in reading package information"); |
|
goto clean_up; |
|
} |
|
cpuinfo_log_debug("detected %"PRIu32" processor package(s)", nr_of_packages); |
|
|
|
|
|
|
|
|
|
|
|
nr_of_cores = read_cores_for_processors( |
|
processors, nr_of_processors, |
|
global_proc_index_per_group, NULL, |
|
chip_info); |
|
if (!nr_of_cores) { |
|
cpuinfo_log_error("error in reading core information"); |
|
goto clean_up; |
|
} |
|
cpuinfo_log_debug("detected %"PRIu32" processor core(s)", nr_of_cores); |
|
|
|
|
|
|
|
|
|
|
|
nr_of_all_caches = read_caches_for_processors( |
|
processors, nr_of_processors, |
|
caches, numbers_of_caches, |
|
global_proc_index_per_group, chip_info); |
|
if (!nr_of_all_caches) { |
|
cpuinfo_log_error("error in reading cache information"); |
|
goto clean_up; |
|
} |
|
cpuinfo_log_debug("detected %"PRIu32" processor cache(s)", nr_of_all_caches); |
|
|
|
|
|
packages = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_packages * sizeof(struct cpuinfo_package)); |
|
if (packages == NULL) { |
|
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" physical packages", |
|
nr_of_packages * sizeof(struct cpuinfo_package), nr_of_packages); |
|
goto clean_up; |
|
} |
|
|
|
|
|
clusters = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_cores * sizeof(struct cpuinfo_cluster)); |
|
if (clusters == NULL) { |
|
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" core clusters", |
|
nr_of_cores * sizeof(struct cpuinfo_cluster), nr_of_cores); |
|
goto clean_up; |
|
} |
|
|
|
cores = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_cores * sizeof(struct cpuinfo_core)); |
|
if (cores == NULL) { |
|
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" cores", |
|
nr_of_cores * sizeof(struct cpuinfo_core), nr_of_cores); |
|
goto clean_up; |
|
} |
|
|
|
|
|
caches = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_all_caches * sizeof(struct cpuinfo_cache)); |
|
if (caches == NULL) { |
|
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" caches", |
|
nr_of_all_caches * sizeof(struct cpuinfo_cache), nr_of_all_caches); |
|
goto clean_up; |
|
} |
|
|
|
|
|
|
|
|
|
nr_of_all_caches = read_caches_for_processors( |
|
processors, nr_of_processors, |
|
caches, numbers_of_caches, global_proc_index_per_group, chip_info); |
|
if (!nr_of_all_caches) { |
|
cpuinfo_log_error("error in reading cache information"); |
|
goto clean_up; |
|
} |
|
|
|
nr_of_cores = read_cores_for_processors( |
|
processors, nr_of_processors, |
|
global_proc_index_per_group, cores, |
|
chip_info); |
|
if (!nr_of_cores) { |
|
cpuinfo_log_error("error in reading core information"); |
|
goto clean_up; |
|
} |
|
|
|
|
|
|
|
|
|
result = connect_packages_cores_clusters_by_processors( |
|
processors, nr_of_processors, |
|
packages, nr_of_packages, |
|
clusters, |
|
cores, nr_of_cores, |
|
chip_info, |
|
vendor); |
|
if(!result) { |
|
cpuinfo_log_error("error in connecting information"); |
|
goto clean_up; |
|
} |
|
|
|
|
|
enum cpuinfo_uarch prev_uarch = cpuinfo_uarch_unknown; |
|
for (uint32_t i = 0; i < nr_of_cores; i++) { |
|
if (prev_uarch != cores[i].uarch) { |
|
nr_of_uarchs++; |
|
prev_uarch = cores[i].uarch; |
|
} |
|
} |
|
uarchs = HeapAlloc(heap, HEAP_ZERO_MEMORY, nr_of_uarchs * sizeof(struct cpuinfo_uarch_info)); |
|
if (uarchs == NULL) { |
|
cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" uarchs", |
|
nr_of_uarchs * sizeof(struct cpuinfo_uarch_info), nr_of_uarchs); |
|
goto clean_up; |
|
} |
|
prev_uarch = cpuinfo_uarch_unknown; |
|
for (uint32_t i = 0, uarch_counter = 0; i < nr_of_cores; i++) { |
|
if (prev_uarch != cores[i].uarch) { |
|
prev_uarch = cores[i].uarch; |
|
uarchs[uarch_counter].uarch = cores[i].uarch; |
|
uarchs[uarch_counter].core_count = 1; |
|
uarchs[uarch_counter].processor_count = cores[i].processor_count; |
|
uarch_counter++; |
|
} else if (prev_uarch != cpuinfo_uarch_unknown) { |
|
uarchs[uarch_counter].core_count++; |
|
uarchs[uarch_counter].processor_count += cores[i].processor_count; |
|
} |
|
} |
|
|
|
|
|
cpuinfo_processors = processors; |
|
cpuinfo_packages = packages; |
|
cpuinfo_clusters = clusters; |
|
cpuinfo_cores = cores; |
|
cpuinfo_uarchs = uarchs; |
|
|
|
cpuinfo_processors_count = nr_of_processors; |
|
cpuinfo_packages_count = nr_of_packages; |
|
cpuinfo_clusters_count = nr_of_cores; |
|
cpuinfo_cores_count = nr_of_cores; |
|
cpuinfo_uarchs_count = nr_of_uarchs; |
|
|
|
for (uint32_t i = 0; i < MAX_NR_OF_CACHES; i++) { |
|
cpuinfo_cache_count[i] = numbers_of_caches[i]; |
|
} |
|
cpuinfo_cache[cpuinfo_cache_level_1i] = caches; |
|
cpuinfo_cache[cpuinfo_cache_level_1d] = cpuinfo_cache[cpuinfo_cache_level_1i] + cpuinfo_cache_count[cpuinfo_cache_level_1i]; |
|
cpuinfo_cache[cpuinfo_cache_level_2] = cpuinfo_cache[cpuinfo_cache_level_1d] + cpuinfo_cache_count[cpuinfo_cache_level_1d]; |
|
cpuinfo_cache[cpuinfo_cache_level_3] = cpuinfo_cache[cpuinfo_cache_level_2] + cpuinfo_cache_count[cpuinfo_cache_level_2]; |
|
cpuinfo_cache[cpuinfo_cache_level_4] = cpuinfo_cache[cpuinfo_cache_level_3] + cpuinfo_cache_count[cpuinfo_cache_level_3]; |
|
cpuinfo_max_cache_size = cpuinfo_compute_max_cache_size(&processors[0]); |
|
|
|
result = true; |
|
MemoryBarrier(); |
|
|
|
processors = NULL; |
|
packages = NULL; |
|
clusters = NULL; |
|
cores = NULL; |
|
caches = NULL; |
|
uarchs = NULL; |
|
|
|
clean_up: |
|
|
|
|
|
|
|
if (processors != NULL) { |
|
HeapFree(heap, 0, processors); |
|
} |
|
if (packages != NULL) { |
|
HeapFree(heap, 0, packages); |
|
} |
|
if (clusters != NULL) { |
|
HeapFree(heap, 0, clusters); |
|
} |
|
if (cores != NULL) { |
|
HeapFree(heap, 0, cores); |
|
} |
|
if (caches != NULL) { |
|
HeapFree(heap, 0, caches); |
|
} |
|
if (uarchs != NULL) { |
|
HeapFree(heap, 0, uarchs); |
|
} |
|
|
|
|
|
HeapFree(heap, 0, global_proc_index_per_group); |
|
global_proc_index_per_group = NULL; |
|
return result; |
|
} |
|
|
|
static uint32_t count_logical_processors( |
|
const uint32_t max_group_count, |
|
uint32_t* global_proc_index_per_group) |
|
{ |
|
uint32_t nr_of_processors = 0; |
|
|
|
for (uint32_t i = 0; i < max_group_count; i++) { |
|
uint32_t nr_of_processors_per_group = GetMaximumProcessorCount((WORD) i); |
|
cpuinfo_log_debug("detected %"PRIu32" processor(s) in group %"PRIu32"", |
|
nr_of_processors_per_group, i); |
|
global_proc_index_per_group[i] = nr_of_processors; |
|
nr_of_processors += nr_of_processors_per_group; |
|
} |
|
return nr_of_processors; |
|
} |
|
|
|
static uint32_t read_packages_for_processors( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t number_of_processors, |
|
const uint32_t* global_proc_index_per_group, |
|
const struct woa_chip_info *chip_info) |
|
{ |
|
return read_all_logical_processor_info_of_relation( |
|
RelationProcessorPackage, |
|
processors, |
|
number_of_processors, |
|
NULL, |
|
NULL, |
|
NULL, |
|
global_proc_index_per_group, |
|
chip_info); |
|
} |
|
|
|
uint32_t read_cores_for_processors( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t number_of_processors, |
|
const uint32_t* global_proc_index_per_group, |
|
struct cpuinfo_core* cores, |
|
const struct woa_chip_info *chip_info) |
|
{ |
|
return read_all_logical_processor_info_of_relation( |
|
RelationProcessorCore, |
|
processors, |
|
number_of_processors, |
|
NULL, |
|
NULL, |
|
cores, |
|
global_proc_index_per_group, |
|
chip_info); |
|
} |
|
|
|
static uint32_t read_caches_for_processors( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t number_of_processors, |
|
struct cpuinfo_cache* caches, |
|
uint32_t* numbers_of_caches, |
|
const uint32_t* global_proc_index_per_group, |
|
const struct woa_chip_info *chip_info) |
|
{ |
|
|
|
if (caches) { |
|
uint32_t cache_offset = 0; |
|
for (uint32_t i = 0; i < MAX_NR_OF_CACHES; i++) { |
|
for (uint32_t j = 0; j < numbers_of_caches[i]; j++) { |
|
caches[cache_offset + j].processor_start = UINT32_MAX; |
|
} |
|
cache_offset += numbers_of_caches[i]; |
|
} |
|
} |
|
|
|
return read_all_logical_processor_info_of_relation( |
|
RelationCache, |
|
processors, |
|
number_of_processors, |
|
caches, |
|
numbers_of_caches, |
|
NULL, |
|
global_proc_index_per_group, |
|
chip_info); |
|
} |
|
|
|
static uint32_t read_all_logical_processor_info_of_relation( |
|
LOGICAL_PROCESSOR_RELATIONSHIP info_type, |
|
struct cpuinfo_processor* processors, |
|
const uint32_t number_of_processors, |
|
struct cpuinfo_cache* caches, |
|
uint32_t* numbers_of_caches, |
|
struct cpuinfo_core* cores, |
|
const uint32_t* global_proc_index_per_group, |
|
const struct woa_chip_info* chip_info) |
|
{ |
|
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX infos = NULL; |
|
uint32_t nr_of_structs = 0; |
|
DWORD info_size = 0; |
|
bool result = false; |
|
HANDLE heap = GetProcessHeap(); |
|
|
|
|
|
if (GetLogicalProcessorInformationEx(info_type, NULL, &info_size) == FALSE) { |
|
const DWORD last_error = GetLastError(); |
|
if (last_error != ERROR_INSUFFICIENT_BUFFER) { |
|
cpuinfo_log_error( |
|
"failed to query size of processor %"PRIu32" information information: error %"PRIu32"", |
|
(uint32_t)info_type, (uint32_t) last_error); |
|
goto clean_up; |
|
} |
|
} |
|
|
|
infos = HeapAlloc(heap, 0, info_size); |
|
if (infos == NULL) { |
|
cpuinfo_log_error("failed to allocate %"PRIu32" bytes for logical processor information", |
|
(uint32_t) info_size); |
|
goto clean_up; |
|
} |
|
|
|
if (GetLogicalProcessorInformationEx(info_type, infos, &info_size) == FALSE) { |
|
cpuinfo_log_error("failed to query processor %"PRIu32" information: error %"PRIu32"", |
|
(uint32_t)info_type, (uint32_t) GetLastError()); |
|
goto clean_up; |
|
} |
|
|
|
|
|
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info_end = |
|
(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) ((uintptr_t) infos + info_size); |
|
for (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info = infos; |
|
info < info_end; |
|
info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) ((uintptr_t) info + info->Size)) |
|
{ |
|
if (info->Relationship != info_type) { |
|
cpuinfo_log_warning( |
|
"unexpected processor info type (%"PRIu32") for processor information", |
|
(uint32_t) info->Relationship); |
|
continue; |
|
} |
|
|
|
const uint32_t info_id = nr_of_structs++; |
|
|
|
switch(info_type) { |
|
case RelationProcessorPackage: |
|
result = parse_relation_processor_info( |
|
processors, |
|
number_of_processors, |
|
global_proc_index_per_group, |
|
info, |
|
info_id, |
|
cores, |
|
chip_info); |
|
break; |
|
case RelationProcessorCore: |
|
result = parse_relation_processor_info( |
|
processors, |
|
number_of_processors, |
|
global_proc_index_per_group, |
|
info, |
|
info_id, |
|
cores, |
|
chip_info); |
|
break; |
|
case RelationCache: |
|
result = parse_relation_cache_info( |
|
processors, |
|
caches, |
|
numbers_of_caches, |
|
global_proc_index_per_group, |
|
info); |
|
break; |
|
default: |
|
cpuinfo_log_error( |
|
"unexpected processor info type (%"PRIu32") for processor information", |
|
(uint32_t) info->Relationship); |
|
result = false; |
|
break; |
|
} |
|
if (!result) { |
|
nr_of_structs = 0; |
|
goto clean_up; |
|
} |
|
} |
|
clean_up: |
|
|
|
HeapFree(heap, 0, infos); |
|
infos = NULL; |
|
return nr_of_structs; |
|
} |
|
|
|
static bool parse_relation_processor_info( |
|
struct cpuinfo_processor* processors, |
|
uint32_t nr_of_processors, |
|
const uint32_t* global_proc_index_per_group, |
|
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info, |
|
const uint32_t info_id, |
|
struct cpuinfo_core* cores, |
|
const struct woa_chip_info *chip_info) |
|
{ |
|
for (uint32_t i = 0; i < info->Processor.GroupCount; i++) { |
|
const uint32_t group_id = info->Processor.GroupMask[i].Group; |
|
|
|
KAFFINITY group_processors_mask = info->Processor.GroupMask[i].Mask; |
|
while (group_processors_mask != 0) { |
|
const uint32_t processor_id_in_group = |
|
low_index_from_kaffinity(group_processors_mask); |
|
const uint32_t processor_global_index = |
|
global_proc_index_per_group[group_id] + processor_id_in_group; |
|
|
|
if(processor_global_index >= nr_of_processors) { |
|
cpuinfo_log_error("unexpected processor index %"PRIu32"", |
|
processor_global_index); |
|
return false; |
|
} |
|
|
|
switch(info->Relationship) { |
|
case RelationProcessorPackage: |
|
store_package_info_per_processor( |
|
processors, processor_global_index, info_id, |
|
group_id, processor_id_in_group); |
|
break; |
|
case RelationProcessorCore: |
|
store_core_info_per_processor( |
|
processors, processor_global_index, |
|
info_id, info, |
|
cores, chip_info); |
|
break; |
|
default: |
|
cpuinfo_log_error( |
|
"unexpected processor info type (%"PRIu32") for processor information", |
|
(uint32_t) info->Relationship); |
|
break; |
|
} |
|
|
|
group_processors_mask &= (group_processors_mask - 1); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
static bool parse_relation_cache_info( |
|
struct cpuinfo_processor* processors, |
|
struct cpuinfo_cache* caches, |
|
uint32_t* numbers_of_caches, |
|
const uint32_t* global_proc_index_per_group, |
|
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info) |
|
{ |
|
static uint32_t l1i_counter = 0; |
|
static uint32_t l1d_counter = 0; |
|
static uint32_t l2_counter = 0; |
|
static uint32_t l3_counter = 0; |
|
|
|
|
|
if (caches == NULL) { |
|
switch(info->Cache.Level) { |
|
case 1: |
|
switch (info->Cache.Type) { |
|
case CacheInstruction: |
|
numbers_of_caches[cpuinfo_cache_level_1i]++; |
|
break; |
|
case CacheData: |
|
numbers_of_caches[cpuinfo_cache_level_1d]++; |
|
break; |
|
case CacheUnified: |
|
break; |
|
case CacheTrace: |
|
break; |
|
default: |
|
break; |
|
} |
|
break; |
|
case 2: |
|
numbers_of_caches[cpuinfo_cache_level_2]++; |
|
break; |
|
case 3: |
|
numbers_of_caches[cpuinfo_cache_level_3]++; |
|
break; |
|
} |
|
return true; |
|
} |
|
struct cpuinfo_cache* l1i_base = caches; |
|
struct cpuinfo_cache* l1d_base = l1i_base + numbers_of_caches[cpuinfo_cache_level_1i]; |
|
struct cpuinfo_cache* l2_base = l1d_base + numbers_of_caches[cpuinfo_cache_level_1d]; |
|
struct cpuinfo_cache* l3_base = l2_base + numbers_of_caches[cpuinfo_cache_level_2]; |
|
|
|
cpuinfo_log_debug( |
|
"info->Cache.GroupCount:%"PRIu32", info->Cache.GroupMask:%"PRIu32"," |
|
"info->Cache.Level:%"PRIu32", info->Cache.Associativity:%"PRIu32"," |
|
"info->Cache.LineSize:%"PRIu32"," |
|
"info->Cache.CacheSize:%"PRIu32", info->Cache.Type:%"PRIu32"", |
|
info->Cache.GroupCount, (unsigned int)info->Cache.GroupMask.Mask, |
|
info->Cache.Level, info->Cache.Associativity, info->Cache.LineSize, |
|
info->Cache.CacheSize, info->Cache.Type); |
|
|
|
struct cpuinfo_cache* current_cache = NULL; |
|
switch (info->Cache.Level) { |
|
case 1: |
|
switch (info->Cache.Type) { |
|
case CacheInstruction: |
|
current_cache = l1i_base + l1i_counter; |
|
l1i_counter++; |
|
break; |
|
case CacheData: |
|
current_cache = l1d_base + l1d_counter; |
|
l1d_counter++; |
|
break; |
|
case CacheUnified: |
|
break; |
|
case CacheTrace: |
|
break; |
|
default: |
|
break; |
|
} |
|
break; |
|
case 2: |
|
current_cache = l2_base + l2_counter; |
|
l2_counter++; |
|
break; |
|
case 3: |
|
current_cache = l3_base + l3_counter; |
|
l3_counter++; |
|
break; |
|
} |
|
current_cache->size = info->Cache.CacheSize; |
|
current_cache->line_size = info->Cache.LineSize; |
|
current_cache->associativity = info->Cache.Associativity; |
|
|
|
|
|
|
|
current_cache->partitions = 1; |
|
current_cache->sets = |
|
current_cache->size / current_cache->line_size / current_cache->associativity; |
|
if (info->Cache.Type == CacheUnified) { |
|
current_cache->flags = CPUINFO_CACHE_UNIFIED; |
|
} |
|
|
|
for (uint32_t i = 0; i < info->Cache.GroupCount; i++) { |
|
|
|
const uint32_t group_id = info->Cache.GroupMasks[i].Group; |
|
|
|
KAFFINITY group_processors_mask = info->Cache.GroupMasks[i].Mask; |
|
while (group_processors_mask != 0) { |
|
const uint32_t processor_id_in_group = |
|
low_index_from_kaffinity(group_processors_mask); |
|
const uint32_t processor_global_index = |
|
global_proc_index_per_group[group_id] + processor_id_in_group; |
|
|
|
store_cache_info_per_processor( |
|
processors, processor_global_index, |
|
info, current_cache); |
|
|
|
|
|
group_processors_mask &= (group_processors_mask - 1); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
static void store_package_info_per_processor( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t processor_global_index, |
|
const uint32_t package_id, |
|
const uint32_t group_id, |
|
const uint32_t processor_id_in_group) |
|
{ |
|
processors[processor_global_index].windows_group_id = |
|
(uint16_t) group_id; |
|
processors[processor_global_index].windows_processor_id = |
|
(uint16_t) processor_id_in_group; |
|
|
|
|
|
|
|
|
|
processors[processor_global_index].package = |
|
(const struct cpuinfo_package*) NULL + package_id; |
|
} |
|
|
|
void store_core_info_per_processor( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t processor_global_index, |
|
const uint32_t core_id, |
|
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX core_info, |
|
struct cpuinfo_core* cores, |
|
const struct woa_chip_info *chip_info) |
|
{ |
|
if (cores) { |
|
processors[processor_global_index].core = cores + core_id; |
|
cores[core_id].core_id = core_id; |
|
get_core_uarch_for_efficiency( |
|
chip_info->chip_name, core_info->Processor.EfficiencyClass, |
|
&(cores[core_id].uarch), &(cores[core_id].frequency)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
processors[processor_global_index].cluster = |
|
(const struct cpuinfo_cluster*) NULL + core_id; |
|
} |
|
} |
|
|
|
static void store_cache_info_per_processor( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t processor_global_index, |
|
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info, |
|
struct cpuinfo_cache* current_cache) |
|
{ |
|
if (current_cache->processor_start > processor_global_index) { |
|
current_cache->processor_start = processor_global_index; |
|
} |
|
current_cache->processor_count++; |
|
|
|
switch(info->Cache.Level) { |
|
case 1: |
|
switch (info->Cache.Type) { |
|
case CacheInstruction: |
|
processors[processor_global_index].cache.l1i = current_cache; |
|
break; |
|
case CacheData: |
|
processors[processor_global_index].cache.l1d = current_cache; |
|
break; |
|
case CacheUnified: |
|
break; |
|
case CacheTrace: |
|
break; |
|
default: |
|
break; |
|
} |
|
break; |
|
case 2: |
|
processors[processor_global_index].cache.l2 = current_cache; |
|
break; |
|
case 3: |
|
processors[processor_global_index].cache.l3 = current_cache; |
|
break; |
|
} |
|
} |
|
|
|
static bool connect_packages_cores_clusters_by_processors( |
|
struct cpuinfo_processor* processors, |
|
const uint32_t nr_of_processors, |
|
struct cpuinfo_package* packages, |
|
const uint32_t nr_of_packages, |
|
struct cpuinfo_cluster* clusters, |
|
struct cpuinfo_core* cores, |
|
const uint32_t nr_of_cores, |
|
const struct woa_chip_info* chip_info, |
|
enum cpuinfo_vendor vendor) |
|
{ |
|
|
|
for (uint32_t i = nr_of_processors; i != 0; i--) { |
|
const uint32_t processor_id = i - 1; |
|
struct cpuinfo_processor* processor = processors + processor_id; |
|
|
|
struct cpuinfo_core* core = (struct cpuinfo_core*)processor->core; |
|
|
|
|
|
|
|
|
|
struct cpuinfo_package* package = |
|
(struct cpuinfo_package*) ((uintptr_t) packages + (uintptr_t) processor->package); |
|
if (package < packages || |
|
package >= (packages + nr_of_packages)) { |
|
cpuinfo_log_error("invalid package indexing"); |
|
return false; |
|
} |
|
processor->package = package; |
|
|
|
struct cpuinfo_cluster* cluster = |
|
(struct cpuinfo_cluster*) ((uintptr_t) clusters + (uintptr_t) processor->cluster); |
|
if (cluster < clusters || |
|
cluster >= (clusters + nr_of_cores)) { |
|
cpuinfo_log_error("invalid cluster indexing"); |
|
return false; |
|
} |
|
processor->cluster = cluster; |
|
|
|
if (chip_info) { |
|
size_t converted_chars = 0; |
|
if (!WideCharToMultiByte( |
|
CP_UTF8, |
|
WC_ERR_INVALID_CHARS, |
|
chip_info->chip_name_string, |
|
-1, |
|
package->name, |
|
CPUINFO_PACKAGE_NAME_MAX, |
|
NULL, |
|
NULL)) { |
|
cpuinfo_log_error("cpu name character conversion error"); |
|
return false; |
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
package->processor_start = processor_id; |
|
package->processor_count++; |
|
|
|
|
|
cluster->processor_start = processor_id; |
|
cluster->processor_count++; |
|
|
|
|
|
core->processor_start = processor_id; |
|
core->processor_count++; |
|
} |
|
|
|
for (uint32_t i = nr_of_cores; i != 0; i--) { |
|
const uint32_t global_core_id = i - 1; |
|
struct cpuinfo_core* core = cores + global_core_id; |
|
const struct cpuinfo_processor* processor = processors + core->processor_start; |
|
struct cpuinfo_package* package = (struct cpuinfo_package*) processor->package; |
|
struct cpuinfo_cluster* cluster = (struct cpuinfo_cluster*) processor->cluster; |
|
|
|
core->package = package; |
|
core->cluster = cluster; |
|
core->vendor = vendor; |
|
|
|
|
|
cluster->core_start = global_core_id; |
|
cluster->core_count++; |
|
package->core_start = global_core_id; |
|
package->core_count++; |
|
package->cluster_start = global_core_id; |
|
package->cluster_count = package->core_count; |
|
|
|
cluster->package = package; |
|
cluster->vendor = cores[cluster->core_start].vendor; |
|
cluster->uarch = cores[cluster->core_start].uarch; |
|
cluster->frequency = cores[cluster->core_start].frequency; |
|
} |
|
return true; |
|
} |
|
|
|
static inline uint32_t low_index_from_kaffinity(KAFFINITY kaffinity) { |
|
unsigned long index; |
|
_BitScanForward64(&index, (unsigned __int64) kaffinity); |
|
return (uint32_t) index; |
|
} |
|
|