Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ jobs:
- name: Configure and build
run: scripts/local-build.sh
working-directory: ${{ github.workspace }}
- name: Run tests
run: ctest --test-dir build/local --output-on-failure
cmake-darwin:
runs-on: macos-latest
timeout-minutes: 40
Expand All @@ -34,6 +36,8 @@ jobs:
- name: Configure and build
run: scripts/local-build.sh
working-directory: ${{ github.workspace }}
- name: Run tests
run: ctest --test-dir build/local --output-on-failure
cmake-windows:
runs-on: windows-latest
timeout-minutes: 40
Expand All @@ -45,6 +49,8 @@ jobs:
run: scripts/local-build.sh
shell: bash # Specify bash so we can reuse the build script on Windows (runs on Git bash)
working-directory: ${{ github.workspace }}
- name: Run tests
run: ctest --test-dir build/local --output-on-failure
cmake-uwp:
runs-on: windows-latest
timeout-minutes: 40
Expand Down
40 changes: 40 additions & 0 deletions src/arm/linux/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -1001,3 +1001,43 @@ void cpuinfo_arm_linux_init(void) {
free(linux_cpu_to_core_map);
free(linux_cpu_to_uarch_index_map);
}

void cpuinfo_arm_linux_deinit(void) {
free(cpuinfo_processors);
cpuinfo_processors = NULL;
cpuinfo_processors_count = 0;

free(cpuinfo_cores);
cpuinfo_cores = NULL;
cpuinfo_cores_count = 0;

free(cpuinfo_clusters);
cpuinfo_clusters = NULL;
cpuinfo_clusters_count = 0;

/* cpuinfo_packages points to static storage (&package) — do not free */
cpuinfo_packages = NULL;
cpuinfo_packages_count = 0;

free(cpuinfo_uarchs);
cpuinfo_uarchs = NULL;
cpuinfo_uarchs_count = 0;

for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) {
free(cpuinfo_cache[lvl]);
cpuinfo_cache[lvl] = NULL;
cpuinfo_cache_count[lvl] = 0;
}
cpuinfo_max_cache_size = 0;

free(cpuinfo_linux_cpu_to_processor_map);
cpuinfo_linux_cpu_to_processor_map = NULL;

free(cpuinfo_linux_cpu_to_core_map);
cpuinfo_linux_cpu_to_core_map = NULL;

free((void*)cpuinfo_linux_cpu_to_uarch_index_map);
cpuinfo_linux_cpu_to_uarch_index_map = NULL;

cpuinfo_linux_cpu_max = 0;
}
29 changes: 29 additions & 0 deletions src/arm/mach/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -873,3 +873,32 @@ void cpuinfo_arm_mach_init(void) {
free(l2);
free(l3);
}

void cpuinfo_arm_mach_deinit(void) {
free(cpuinfo_processors);
cpuinfo_processors = NULL;
cpuinfo_processors_count = 0;

free(cpuinfo_cores);
cpuinfo_cores = NULL;
cpuinfo_cores_count = 0;

free(cpuinfo_clusters);
cpuinfo_clusters = NULL;
cpuinfo_clusters_count = 0;

free(cpuinfo_packages);
cpuinfo_packages = NULL;
cpuinfo_packages_count = 0;

free(cpuinfo_uarchs);
cpuinfo_uarchs = NULL;
cpuinfo_uarchs_count = 0;

for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) {
free(cpuinfo_cache[lvl]);
cpuinfo_cache[lvl] = NULL;
cpuinfo_cache_count[lvl] = 0;
}
cpuinfo_max_cache_size = 0;
}
34 changes: 34 additions & 0 deletions src/arm/windows/init-by-logical-sys-info.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,40 @@ bool cpu_info_init_by_logical_sys_info(const struct woa_chip_info* chip_info, co
return result;
}

BOOL CALLBACK cpuinfo_arm_windows_deinit(PINIT_ONCE init_once, PVOID parameter, PVOID* context) {
HANDLE heap = GetProcessHeap();

HeapFree(heap, 0, cpuinfo_processors);
cpuinfo_processors = NULL;
cpuinfo_processors_count = 0;

HeapFree(heap, 0, cpuinfo_packages);
cpuinfo_packages = NULL;
cpuinfo_packages_count = 0;

HeapFree(heap, 0, cpuinfo_clusters);
cpuinfo_clusters = NULL;
cpuinfo_clusters_count = 0;

HeapFree(heap, 0, cpuinfo_cores);
cpuinfo_cores = NULL;
cpuinfo_cores_count = 0;

HeapFree(heap, 0, cpuinfo_uarchs);
cpuinfo_uarchs = NULL;
cpuinfo_uarchs_count = 0;

/* Caches are allocated as a single contiguous block starting at l1i */
HeapFree(heap, 0, cpuinfo_cache[cpuinfo_cache_level_1i]);
for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) {
cpuinfo_cache[lvl] = NULL;
cpuinfo_cache_count[lvl] = 0;
}
cpuinfo_max_cache_size = 0;

return TRUE;
}

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;

Expand Down
10 changes: 10 additions & 0 deletions src/arm/windows/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@ BOOL CALLBACK cpuinfo_arm_windows_init(PINIT_ONCE init_once, PVOID parameter, PV
set_cpuinfo_isa_fields();

chip_info = get_system_info_from_registry();
const bool chip_info_from_registry = chip_info != NULL;
if (chip_info == NULL) {
chip_info = &woa_chip_unknown;
}

cpuinfo_is_initialized = cpu_info_init_by_logical_sys_info(chip_info, chip_info->uarchs[0].vendor);

if (chip_info_from_registry) {
HeapFree(GetProcessHeap(), 0, chip_info->chip_name_string);
HeapFree(GetProcessHeap(), 0, chip_info);
}

return true;
}

Expand Down Expand Up @@ -177,6 +183,7 @@ static struct woa_chip_info* get_system_info_from_registry(void) {
uint64_t midr_qword = (uint32_t)read_registry_qword(cpu0_subkey, chip_midr_value);
if (midr_qword == 0) {
cpuinfo_log_error("Registry read error for MIDR value");
HeapFree(GetProcessHeap(), 0, text_buffer);
return NULL;
}
// MIDR is only 32 bits, so we need to cast it to uint32_t
Expand All @@ -187,6 +194,7 @@ static struct woa_chip_info* get_system_info_from_registry(void) {
uint64_t frequency_mhz = read_registry_dword(cpu0_subkey, chip_mhz_value);
if (frequency_mhz == 0) {
cpuinfo_log_error("Registry read error for frequency value");
HeapFree(GetProcessHeap(), 0, text_buffer);
return NULL;
}
// Convert MHz to Hz
Expand All @@ -196,11 +204,13 @@ static struct woa_chip_info* get_system_info_from_registry(void) {
chip_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct woa_chip_info));
if (chip_info == NULL) {
cpuinfo_log_error("Heap allocation error for chip_info");
HeapFree(GetProcessHeap(), 0, text_buffer);
return NULL;
}

// set chip_info fields
chip_info->chip_name_string = wcsndup(text_buffer, CPUINFO_PACKAGE_NAME_MAX - 1);
HeapFree(GetProcessHeap(), 0, text_buffer);
chip_info->uarchs[0] = get_core_info_from_midr(midr_value, frequency_hz);

cpuinfo_log_debug("detected chip model name: %ls", chip_info->chip_name_string);
Expand Down
20 changes: 20 additions & 0 deletions src/cpuinfo/internal-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ extern CPUINFO_INTERNAL struct cpuinfo_uarch_info cpuinfo_global_uarch;
extern CPUINFO_INTERNAL uint32_t cpuinfo_linux_cpu_max;
extern CPUINFO_INTERNAL const struct cpuinfo_processor** cpuinfo_linux_cpu_to_processor_map;
extern CPUINFO_INTERNAL const struct cpuinfo_core** cpuinfo_linux_cpu_to_core_map;
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
extern CPUINFO_INTERNAL const uint32_t* cpuinfo_linux_cpu_to_uarch_index_map;
#endif
#endif

CPUINFO_PRIVATE void cpuinfo_x86_mach_init(void);
Expand All @@ -62,6 +65,23 @@ CPUINFO_PRIVATE void cpuinfo_arm_linux_init(void);
CPUINFO_PRIVATE void cpuinfo_riscv_linux_init(void);
CPUINFO_PRIVATE void cpuinfo_emscripten_init(void);

/* Platform-specific deinitialization functions.
* Each frees the globals allocated by its corresponding init function. */
CPUINFO_PRIVATE void cpuinfo_x86_mach_deinit(void);
CPUINFO_PRIVATE void cpuinfo_x86_linux_deinit(void);
CPUINFO_PRIVATE void cpuinfo_x86_freebsd_deinit(void);
#if defined(_WIN32) || defined(__CYGWIN__)
#if CPUINFO_ARCH_ARM64
CPUINFO_PRIVATE BOOL CALLBACK cpuinfo_arm_windows_deinit(PINIT_ONCE init_once, PVOID parameter, PVOID* context);
#else
CPUINFO_PRIVATE BOOL CALLBACK cpuinfo_x86_windows_deinit(PINIT_ONCE init_once, PVOID parameter, PVOID* context);
#endif
#endif
CPUINFO_PRIVATE void cpuinfo_arm_mach_deinit(void);
CPUINFO_PRIVATE void cpuinfo_arm_linux_deinit(void);
CPUINFO_PRIVATE void cpuinfo_riscv_linux_deinit(void);
CPUINFO_PRIVATE void cpuinfo_emscripten_deinit(void);

CPUINFO_PRIVATE uint32_t cpuinfo_compute_max_cache_size(const struct cpuinfo_processor* processor);

typedef void (*cpuinfo_processor_callback)(uint32_t);
32 changes: 32 additions & 0 deletions src/emscripten/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,35 @@ void cpuinfo_emscripten_init(void) {
free(l1d);
free(l2);
}

void cpuinfo_emscripten_deinit(void) {
free(cpuinfo_processors);
cpuinfo_processors = NULL;
cpuinfo_processors_count = 0;

free(cpuinfo_cores);
cpuinfo_cores = NULL;
cpuinfo_cores_count = 0;

free(cpuinfo_clusters);
cpuinfo_clusters = NULL;
cpuinfo_clusters_count = 0;

/* cpuinfo_packages points to static storage (&static_package) — do not free */
cpuinfo_packages = NULL;
cpuinfo_packages_count = 0;

/* L1i, L1d, L2 are dynamically allocated; L3 may point to static
* storage (&static_x86_l3) so only free levels that were calloc'd */
free(cpuinfo_cache[cpuinfo_cache_level_1i]);
free(cpuinfo_cache[cpuinfo_cache_level_1d]);
free(cpuinfo_cache[cpuinfo_cache_level_2]);
/* cpuinfo_cache[cpuinfo_cache_level_3] may be &static_x86_l3 — do not free */
for (int lvl = 0; lvl < cpuinfo_cache_level_max; ++lvl) {
cpuinfo_cache[lvl] = NULL;
cpuinfo_cache_count[lvl] = 0;
}
cpuinfo_max_cache_size = 0;

cpuinfo_global_uarch = (struct cpuinfo_uarch_info){0};
}
91 changes: 67 additions & 24 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,98 @@
#endif

#if defined(_WIN32) || defined(__CYGWIN__)
static INIT_ONCE init_guard = INIT_ONCE_STATIC_INIT;
static SRWLOCK cpuinfo_lifecycle_lock = SRWLOCK_INIT;
#define CPUINFO_LIFECYCLE_LOCK() AcquireSRWLockExclusive(&cpuinfo_lifecycle_lock)
#define CPUINFO_LIFECYCLE_UNLOCK() ReleaseSRWLockExclusive(&cpuinfo_lifecycle_lock)
#elif !defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__)
static pthread_once_t init_guard = PTHREAD_ONCE_INIT;
static pthread_mutex_t cpuinfo_lifecycle_lock = PTHREAD_MUTEX_INITIALIZER;
#define CPUINFO_LIFECYCLE_LOCK() pthread_mutex_lock(&cpuinfo_lifecycle_lock)
#define CPUINFO_LIFECYCLE_UNLOCK() pthread_mutex_unlock(&cpuinfo_lifecycle_lock)
#else
static bool init_guard = false;
/* Single-threaded build (e.g. Emscripten without pthreads): no lock needed. */
#define CPUINFO_LIFECYCLE_LOCK() \
do { \
} while (0)
#define CPUINFO_LIFECYCLE_UNLOCK() \
do { \
} while (0)
#endif
static unsigned int cpuinfo_init_refcount = 0;

bool CPUINFO_ABI cpuinfo_initialize(void) {
CPUINFO_LIFECYCLE_LOCK();
if (cpuinfo_init_refcount == 0) {
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
#if defined(__MACH__) && defined(__APPLE__)
pthread_once(&init_guard, &cpuinfo_x86_mach_init);
cpuinfo_x86_mach_init();
#elif defined(__FreeBSD__)
pthread_once(&init_guard, &cpuinfo_x86_freebsd_init);
cpuinfo_x86_freebsd_init();
#elif defined(__linux__)
pthread_once(&init_guard, &cpuinfo_x86_linux_init);
cpuinfo_x86_linux_init();
#elif defined(_WIN32) || defined(__CYGWIN__)
InitOnceExecuteOnce(&init_guard, &cpuinfo_x86_windows_init, NULL, NULL);
cpuinfo_x86_windows_init(NULL, NULL, NULL);
#else
cpuinfo_log_error("operating system is not supported in cpuinfo");
cpuinfo_log_error("operating system is not supported in cpuinfo");
#endif
#elif CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
#if defined(__linux__)
pthread_once(&init_guard, &cpuinfo_arm_linux_init);
cpuinfo_arm_linux_init();
#elif defined(__MACH__) && defined(__APPLE__)
pthread_once(&init_guard, &cpuinfo_arm_mach_init);
cpuinfo_arm_mach_init();
#elif defined(_WIN32)
InitOnceExecuteOnce(&init_guard, &cpuinfo_arm_windows_init, NULL, NULL);
cpuinfo_arm_windows_init(NULL, NULL, NULL);
#else
cpuinfo_log_error("operating system is not supported in cpuinfo");
cpuinfo_log_error("operating system is not supported in cpuinfo");
#endif
#elif CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#if defined(__linux__)
pthread_once(&init_guard, &cpuinfo_riscv_linux_init);
cpuinfo_riscv_linux_init();
#else
cpuinfo_log_error("operating system is not supported in cpuinfo");
cpuinfo_log_error("operating system is not supported in cpuinfo");
#endif
#elif CPUINFO_ARCH_ASMJS || CPUINFO_ARCH_WASM || CPUINFO_ARCH_WASMSIMD
#if defined(__EMSCRIPTEN_PTHREADS__)
pthread_once(&init_guard, &cpuinfo_emscripten_init);
#else
if (!init_guard) {
cpuinfo_emscripten_init();
}
init_guard = true;
#endif
#else
cpuinfo_log_error("processor architecture is not supported in cpuinfo");
cpuinfo_log_error("processor architecture is not supported in cpuinfo");
#endif
return cpuinfo_is_initialized;
}
if (cpuinfo_is_initialized) {
cpuinfo_init_refcount++;
}
const bool initialized = cpuinfo_is_initialized;
CPUINFO_LIFECYCLE_UNLOCK();
return initialized;
}

void CPUINFO_ABI cpuinfo_deinitialize(void) {}
void CPUINFO_ABI cpuinfo_deinitialize(void) {
CPUINFO_LIFECYCLE_LOCK();
if (cpuinfo_init_refcount != 0 && --cpuinfo_init_refcount == 0) {
cpuinfo_is_initialized = false;
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
#if defined(__MACH__) && defined(__APPLE__)
cpuinfo_x86_mach_deinit();
#elif defined(__FreeBSD__)
cpuinfo_x86_freebsd_deinit();
#elif defined(__linux__)
cpuinfo_x86_linux_deinit();
#elif defined(_WIN32) || defined(__CYGWIN__)
cpuinfo_x86_windows_deinit(NULL, NULL, NULL);
#endif
#elif CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
#if defined(__linux__)
cpuinfo_arm_linux_deinit();
#elif defined(__MACH__) && defined(__APPLE__)
cpuinfo_arm_mach_deinit();
#elif defined(_WIN32)
cpuinfo_arm_windows_deinit(NULL, NULL, NULL);
#endif
#elif CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#if defined(__linux__)
cpuinfo_riscv_linux_deinit();
#endif
#elif CPUINFO_ARCH_ASMJS || CPUINFO_ARCH_WASM || CPUINFO_ARCH_WASMSIMD
cpuinfo_emscripten_deinit();
#endif
}
CPUINFO_LIFECYCLE_UNLOCK();
}
Loading