aboutsummaryrefslogtreecommitdiff
path: root/src/arm/windows/init-by-logical-sys-info.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arm/windows/init-by-logical-sys-info.c')
-rw-r--r--src/arm/windows/init-by-logical-sys-info.c885
1 files changed, 885 insertions, 0 deletions
diff --git a/src/arm/windows/init-by-logical-sys-info.c b/src/arm/windows/init-by-logical-sys-info.c
new file mode 100644
index 0000000..f088011
--- /dev/null
+++ b/src/arm/windows/init-by-logical-sys-info.c
@@ -0,0 +1,885 @@
+#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)
+
+/* Call chain:
+ * cpu_info_init_by_logical_sys_info
+ * read_packages_for_processors
+ * read_cores_for_processors
+ * read_caches_for_processors
+ * read_all_logical_processor_info_of_relation
+ * parse_relation_processor_info
+ * store_package_info_per_processor
+ * store_core_info_per_processor
+ * parse_relation_cache_info
+ * store_cache_info_per_processor
+ */
+
+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();
+
+ /* 1. Count available logical processor groups and processors */
+ const uint32_t max_group_count = (uint32_t) GetMaximumProcessorGroupCount();
+ cpuinfo_log_debug("detected %"PRIu32" processor group(s)", max_group_count);
+ /* We need to store the absolute processor ID offsets for every groups, because
+ * 1. We can't assume every processor groups include the same number of
+ * logical processors.
+ * 2. Every processor groups know its group number and processor IDs within
+ * the group, but not the global processor IDs.
+ * 3. We need to list every logical processors by global IDs.
+ */
+ 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;
+ }
+
+ /* 2. Read topology information via MSDN API: packages, cores and caches*/
+ 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);
+
+ /* We need the EfficiencyClass to parse uarch from the core information,
+ * but we need to iterate first to count cores and allocate memory then
+ * we will iterate again to read and store data to cpuinfo_core structures.
+ */
+ 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);
+
+ /* There is no API to read number of caches, so we need to iterate twice on caches:
+ 1. Count all type of caches -> allocate memory
+ 2. Read out cache data and store to allocated memory
+ */
+ 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);
+
+ /* 3. Allocate memory for package, cluster, core and cache structures */
+ 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;
+ }
+
+ /* We don't have cluster information so we explicitly set clusters to equal to cores. */
+ 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;
+ }
+
+ /* We allocate one contiguous cache array for all caches, then use offsets per cache type. */
+ 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;
+ }
+
+ /* 4.Read missing topology information that can't be saved without counted
+ * allocate structures in the first round.
+ */
+ 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;
+ }
+
+ /* 5. Now that we read out everything from the system we can, fill the package, cluster
+ * and core structures respectively.
+ */
+ 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;
+ }
+
+ /* 6. Count and store uarchs of cores, assuming same uarchs are neighbors */
+ 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;
+ }
+ }
+
+ /* 7. Commit changes */
+ 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:
+ /* The propagated pointers, shouldn't be freed, only in case of error
+ * and unfinished init.
+ */
+ 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);
+ }
+
+ /* Free the locally used temporary pointers */
+ 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)
+{
+ /* Reset processor start indexes */
+ 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();
+
+ /* 1. Query the size of the information structure first */
+ 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;
+ }
+ }
+ /* 2. Allocate memory for the information structure */
+ 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;
+ }
+ /* 3. Read the information structure */
+ 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;
+ }
+
+ /* 4. Parse the structure and store relevant data */
+ 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:
+ /* 5. Release dynamically allocated info structure. */
+ 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;
+ /* Bitmask representing processors in this group belonging to this package */
+ 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;
+ }
+ /* Clear the bits in affinity mask, lower the least set bit. */
+ 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;
+
+ /* Count cache types for allocation at first. */
+ 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;
+ /* We don't have partition and set information of caches on Windows,
+ * so we set partitions to 1 and calculate the expected sets.
+ */
+ 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++) {
+ /* Zero GroupCount is valid, GroupMask still can store bits set. */
+ const uint32_t group_id = info->Cache.GroupMasks[i].Group;
+ /* Bitmask representing processors in this group belonging to this package */
+ 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);
+
+ /* Clear the bits in affinity mask, lower the least set bit. */
+ 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;
+
+ /* As we're counting the number of packages now, we haven't allocated memory for
+ * cpuinfo_packages yet, so we only set the package pointer's offset now.
+ */
+ 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));
+
+ /* We don't have cluster information, so we handle it as
+ * fixed 1 to (cluster / cores).
+ * Set the cluster offset ID now, as soon as we have the
+ * cluster base address, we'll set the absolute address.
+ */
+ 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)
+{
+ /* Adjust core and package pointers for all logical processors. */
+ 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;
+
+ /* We stored the offset of pointers when we haven't allocated memory
+ * for packages and clusters, so now add offsets to base addresses.
+ */
+ 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) {
+ strncpy_s(package->name, CPUINFO_PACKAGE_NAME_MAX, chip_info->chip_name_string,
+ strnlen(chip_info->chip_name_string, CPUINFO_PACKAGE_NAME_MAX));
+ }
+
+ /* Set start indexes and counts per packages / clusters / cores - going backwards */
+
+ /* This can be overwritten by lower-index processors on the same package. */
+ package->processor_start = processor_id;
+ package->processor_count++;
+
+ /* This can be overwritten by lower-index processors on the same cluster. */
+ cluster->processor_start = processor_id;
+ cluster->processor_count++;
+
+ /* This can be overwritten by lower-index processors on the same core. */
+ core->processor_start = processor_id;
+ core->processor_count++;
+ }
+ /* Fill cores */
+ 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;
+
+ /* This can be overwritten by lower-index cores on the same cluster/package. */
+ 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;
+}