Skip to content

Commit

Permalink
Add initial support for powerpc64le initialization.
Browse files Browse the repository at this point in the history
    * Adds header definitions for PPC64le
    * Adds support to construct the processor, core, cluster, package
      and cache(L1i,L1d,L2 and L3) information reported by the system.

    Test: Build and ran cpu_info on PPC64le linux machine. confirmed
          that it properly reports the logical processors, cores, clusters,
          packages and cache information.
  • Loading branch information
BODAPATIMAHESH committed Nov 21, 2024
1 parent cebb093 commit 68fecdb
Show file tree
Hide file tree
Showing 19 changed files with 1,778 additions and 9 deletions.
18 changes: 17 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ IF(NOT CMAKE_SYSTEM_PROCESSOR)
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
ENDIF()
ELSEIF(NOT CPUINFO_TARGET_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?|armv[5-8].*|aarch64|arm64.*|ARM64.*|riscv(32|64))$")
ELSEIF(NOT CPUINFO_TARGET_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?|armv[5-8].*|aarch64|arm64.*|ARM64.*|riscv(32|64)|ppc64le)$")
MESSAGE(WARNING
"Target processor architecture \"${CPUINFO_TARGET_PROCESSOR}\" is not supported in cpuinfo. "
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
Expand Down Expand Up @@ -184,6 +184,14 @@ IF(CPUINFO_SUPPORTED_PLATFORM)
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
LIST(APPEND CPUINFO_SRCS src/x86/freebsd/init.c)
ENDIF()
ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ppc64le)$" )
LIST(APPEND CPUINFO_SRCS
src/powerpc/uarch.c
src/powerpc/cache.c
src/powerpc/linux/cpuinfo.c
src/powerpc/linux/ppc64-hw.c
src/powerpc/linux/init.c
src/powerpc/linux/ppc64-isa.c)
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "^Windows" AND CPUINFO_TARGET_PROCESSOR MATCHES "^(ARM64|arm64)$")
LIST(APPEND CPUINFO_SRCS
src/arm/windows/init-by-logical-sys-info.c
Expand Down Expand Up @@ -856,6 +864,14 @@ IF(CPUINFO_SUPPORTED_PLATFORM AND CPUINFO_BUILD_UNIT_TESTS)
TARGET_LINK_LIBRARIES(cache-test PRIVATE cpuinfo_internals gtest gtest_main)
ADD_TEST(NAME cache-test COMMAND cache-test)
ENDIF()

IF(CMAKE_SYSTEM_NAME STREQUAL "POWER" OR CMAKE_SYSTEM_PROCESSOR MATCHES "^(ppc64le)$")
ADD_EXECUTABLE(power-features-test test/name/power-features.cc)
CPUINFO_TARGET_ENABLE_CXX11(power-features-test)
CPUINFO_TARGET_RUNTIME_LIBRARY(power-features-test)
TARGET_LINK_LIBRARIES(power-features-test PRIVATE cpuinfo_internals gtest gtest_main)
ADD_TEST(NAME power-features-test COMMAND power-features-test)
ENDIF()
ENDIF()

# ---[ Helper and debug tools
Expand Down
12 changes: 12 additions & 0 deletions configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ def main(args):
if options.mock:
sources += ["linux/mockfile.c"]
build.static_library("cpuinfo", map(build.cc, sources))
if build.target.is_ppc64:
sources += [ "powerpc/uarch.c", "powerpc/cache.c"]
if build.target.is_linux:
sources += [
"powerpc/linux/cpuinfo.c"
"powerpc/linux/ppc64-hw.c",
"powerpc/linux/init.c",
"powerpc/linux/ppc64-isa.c",
]


with build.options(source_dir="tools", deps=[build, build.deps.clog]):
build.executable("cpu-info", build.cc("cpu-info.c"))
Expand All @@ -91,6 +101,8 @@ def main(args):
build.smoketest("get-current-test", build.cxx("get-current.cc"))
if build.target.is_x86_64:
build.smoketest("brand-string-test", build.cxx("name/brand-string.cc"))
if build.target.is_ppc64:
build.smoketest("power-features-test", build.cxx("name/power-features.cc"))
if options.mock:
with build.options(source_dir="test", include_dirs="test", macros="CPUINFO_MOCK", deps=[build, build.deps.googletest]):
if build.target.is_arm64 and build.target.is_linux:
Expand Down
60 changes: 60 additions & 0 deletions include/cpuinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,21 @@ enum cpuinfo_uarch {

/** HiSilicon TaiShan v110 (Huawei Kunpeng 920 series processors). */
cpuinfo_uarch_taishan_v110 = 0x00C00100,

/** IBM POWER 7. */
cpuinfo_uarch_power7 = 0x00D00100,
/** IBM POWER 7p. */
cpuinfo_uarch_power7p = 0x00D00101,
/** IBM POWER 8. */
cpuinfo_uarch_power8 = 0x00D00200,
/** IBM POWER8E. */
cpuinfo_uarch_power8e = 0x00D00201,
/** IBM POWER8NVL */
cpuinfo_uarch_power8nvl = 0x00D00202,
/** IBM POWER 9. */
cpuinfo_uarch_power9 = 0x00D00303,
/** IBM POWER 10. */
cpuinfo_uarch_power10 = 0x00D00400,
};

struct cpuinfo_processor {
Expand Down Expand Up @@ -671,9 +686,14 @@ struct cpuinfo_core {
#elif CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
/** Value of Main ID Register (MIDR) for this core */
uint32_t midr;
#elif CPUINFO_ARCH_PPC64
/** Value of Processor Version Register for this core */
uint32_t pvr;
#endif
/** Clock rate (non-Turbo) of the core, in Hz */
uint64_t frequency;

bool disabled;
};

struct cpuinfo_cluster {
Expand All @@ -699,6 +719,9 @@ struct cpuinfo_cluster {
#elif CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
/** Value of Main ID Register (MIDR) of the cores in the cluster */
uint32_t midr;
#elif CPUINFO_ARCH_PPC64
/** Value of Processor Version Register in this cluster */
uint32_t pvr;
#endif
/** Clock rate (non-Turbo) of the cores in the cluster, in Hz */
uint64_t frequency;
Expand Down Expand Up @@ -732,6 +755,9 @@ struct cpuinfo_uarch_info {
#elif CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
/** Value of Main ID Register (MIDR) for the microarchitecture */
uint32_t midr;
#elif CPUINFO_ARCH_PPC64
/** Value of Processor Version Register for this core */
uint32_t pvr;
#endif
/** Number of logical processors with the microarchitecture */
uint32_t processor_count;
Expand Down Expand Up @@ -2218,6 +2244,40 @@ static inline bool cpuinfo_has_riscv_v(void) {
#endif
}

#if CPUINFO_ARCH_PPC64
struct cpuinfo_powerpc_isa {
bool vsx;
bool htm;
bool mma;
};

extern struct cpuinfo_powerpc_isa cpuinfo_isa;
#endif

static inline bool cpuinfo_has_powerpc_vsx(void) {
#if CPUINFO_ARCH_PPC64
return cpuinfo_isa.vsx;
#else
return false;
#endif
}

static inline bool cpuinfo_has_powerpc_htm(void) {
#if CPUINFO_ARCH_PPC64
return cpuinfo_isa.htm;
#else
return false;
#endif
}

static inline bool cpuinfo_has_powerpc_mma(void) {
#if CPUINFO_ARCH_PPC64
return cpuinfo_isa.mma;
#else
return false;
#endif
}

const struct cpuinfo_processor* CPUINFO_ABI cpuinfo_get_processors(void);
const struct cpuinfo_core* CPUINFO_ABI cpuinfo_get_cores(void);
const struct cpuinfo_cluster* CPUINFO_ABI cpuinfo_get_clusters(void);
Expand Down
14 changes: 7 additions & 7 deletions src/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ uint32_t cpuinfo_packages_count = 0;
uint32_t cpuinfo_cache_count[cpuinfo_cache_level_max] = {0};
uint32_t cpuinfo_max_cache_size = 0;

#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 || CPUINFO_ARCH_PPC64
struct cpuinfo_uarch_info* cpuinfo_uarchs = NULL;
uint32_t cpuinfo_uarchs_count = 0;
#else
Expand All @@ -41,7 +41,7 @@ struct cpuinfo_uarch_info cpuinfo_global_uarch = {cpuinfo_uarch_unknown};
uint32_t cpuinfo_linux_cpu_max = 0;
const struct cpuinfo_processor** cpuinfo_linux_cpu_to_processor_map = NULL;
const struct cpuinfo_core** cpuinfo_linux_cpu_to_core_map = NULL;
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 || CPUINFO_ARCH_PPC64
const uint32_t* cpuinfo_linux_cpu_to_uarch_index_map = NULL;
#endif
#endif
Expand Down Expand Up @@ -78,7 +78,7 @@ const struct cpuinfo_uarch_info* cpuinfo_get_uarchs() {
if (!cpuinfo_is_initialized) {
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarchs");
}
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 || CPUINFO_ARCH_PPC64
return cpuinfo_uarchs;
#else
return &cpuinfo_global_uarch;
Expand Down Expand Up @@ -129,7 +129,7 @@ const struct cpuinfo_uarch_info* cpuinfo_get_uarch(uint32_t index) {
if (!cpuinfo_is_initialized) {
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarch");
}
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 || CPUINFO_ARCH_PPC64
if CPUINFO_UNLIKELY (index >= cpuinfo_uarchs_count) {
return NULL;
}
Expand Down Expand Up @@ -174,7 +174,7 @@ uint32_t cpuinfo_get_uarchs_count(void) {
if (!cpuinfo_is_initialized) {
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarchs_count");
}
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 || CPUINFO_ARCH_PPC64
return cpuinfo_uarchs_count;
#else
return 1;
Expand Down Expand Up @@ -350,7 +350,7 @@ uint32_t CPUINFO_ABI cpuinfo_get_current_uarch_index(void) {
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_uarch_index");
}
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 || CPUINFO_ARCH_PPC64
#ifdef __linux__
if (cpuinfo_linux_cpu_to_uarch_index_map == NULL) {
/* Special case: avoid syscall on systems with only a single
Expand Down Expand Up @@ -385,7 +385,7 @@ uint32_t CPUINFO_ABI cpuinfo_get_current_uarch_index_with_default(uint32_t defau
cpuinfo_log_fatal(
"cpuinfo_get_%s called before cpuinfo is initialized", "current_uarch_index_with_default");
}
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 || CPUINFO_ARCH_PPC64
#ifdef __linux__
if (cpuinfo_linux_cpu_to_uarch_index_map == NULL) {
/* Special case: avoid syscall on systems with only a single
Expand Down
3 changes: 2 additions & 1 deletion src/cpuinfo/internal-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ extern CPUINFO_INTERNAL uint32_t cpuinfo_packages_count;
extern CPUINFO_INTERNAL uint32_t cpuinfo_cache_count[cpuinfo_cache_level_max];
extern CPUINFO_INTERNAL uint32_t cpuinfo_max_cache_size;

#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 || CPUINFO_ARCH_PPC64
extern CPUINFO_INTERNAL struct cpuinfo_uarch_info* cpuinfo_uarchs;
extern CPUINFO_INTERNAL uint32_t cpuinfo_uarchs_count;
#else
Expand All @@ -61,6 +61,7 @@ CPUINFO_PRIVATE void cpuinfo_arm_mach_init(void);
CPUINFO_PRIVATE void cpuinfo_arm_linux_init(void);
CPUINFO_PRIVATE void cpuinfo_riscv_linux_init(void);
CPUINFO_PRIVATE void cpuinfo_emscripten_init(void);
CPUINFO_PRIVATE void cpuinfo_powerpc_linux_init(void);

CPUINFO_PRIVATE uint32_t cpuinfo_compute_max_cache_size(const struct cpuinfo_processor* processor);

Expand Down
6 changes: 6 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ bool CPUINFO_ABI cpuinfo_initialize(void) {
#else
cpuinfo_log_error("operating system is not supported in cpuinfo");
#endif
#elif CPUINFO_ARCH_PPC64
#if defined(__linux__)
pthread_once(&init_guard, &cpuinfo_powerpc_linux_init);
#else
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);
Expand Down
1 change: 1 addition & 0 deletions src/linux/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ CPUINFO_INTERNAL bool cpuinfo_linux_get_processor_package_id(
uint32_t processor,
uint32_t package_id[restrict static 1]);
CPUINFO_INTERNAL bool cpuinfo_linux_get_processor_core_id(uint32_t processor, uint32_t core_id[restrict static 1]);
CPUINFO_INTERNAL bool cpuinfo_linux_get_processor_online_status(uint32_t processor, uint32_t* online_status);

CPUINFO_INTERNAL bool cpuinfo_linux_detect_possible_processors(
uint32_t max_processors_count,
Expand Down
28 changes: 28 additions & 0 deletions src/linux/processors.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
#define CORE_ID_FILENAME_FORMAT "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/core_id"
#define CORE_ID_FILESIZE 32

#define PROCESSOR_ONLINE_FILENAME_SIZE (sizeof("/sys/devices/system/cpu/cpu" STRINGIFY(UINT32_MAX) "/online"))
#define PROCESSOR_ONLINE_FILENAME_FORMAT "/sys/devices/system/cpu/cpu%" PRIu32 "/online"
#define PROCESSOR_ONLINE_FILESIZE 32
#define CORE_CPUS_FILENAME_SIZE (sizeof("/sys/devices/system/cpu/cpu" STRINGIFY(UINT32_MAX) "/topology/core_cpus_list"))
#define CORE_CPUS_FILENAME_FORMAT "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/core_cpus_list"
#define CORE_SIBLINGS_FILENAME_SIZE \
Expand Down Expand Up @@ -280,6 +283,31 @@ bool cpuinfo_linux_get_processor_package_id(uint32_t processor, uint32_t package
}
}

bool cpuinfo_linux_get_processor_online_status(uint32_t processor, uint32_t* online_status_ptr) {
char processor_online_filename[PROCESSOR_ONLINE_FILENAME_SIZE];
const int chars_formatted =
snprintf(processor_online_filename, PROCESSOR_ONLINE_FILENAME_SIZE, PROCESSOR_ONLINE_FILENAME_FORMAT, processor);
if ((unsigned int)chars_formatted >= PROCESSOR_ONLINE_FILENAME_SIZE) {
cpuinfo_log_warning("failed to format filename for online status of processor %" PRIu32, processor);
return 0;
}
uint32_t online_status;
if (cpuinfo_linux_parse_small_file(processor_online_filename, PROCESSOR_ONLINE_FILESIZE, uint32_parser, &online_status)) {
cpuinfo_log_debug(
"parsed online status value of %" PRIu32 " for logical processor %" PRIu32 " from %s",
online_status,
processor,
processor_online_filename);
*online_status_ptr = online_status;
return true;
} else {
cpuinfo_log_info(
"failed to parse online status for processor %" PRIu32 " from %s", processor, processor_online_filename);
return false;
}
}


static bool max_processor_number_parser(uint32_t processor_list_start, uint32_t processor_list_end, void* context) {
uint32_t* processor_number_ptr = (uint32_t*)context;
const uint32_t processor_list_last = processor_list_end - 1;
Expand Down
21 changes: 21 additions & 0 deletions src/powerpc/api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <stdbool.h>
#include <stdint.h>

#include <cpuinfo.h>

enum cpuinfo_powerpc_chipset_vendor {
cpuinfo_powerpc_chipset_vendor_unknown = 0,
cpuinfo_powerpc_chipset_vendor_ibm
};
void cpuinfo_powerpc_decode_vendor_uarch(
uint32_t vendor_id,
enum cpuinfo_vendor vendor[restrict static 1],
enum cpuinfo_uarch uarch[restrict static 1]);

void cpuinfo_powerpc_decode_cache(
struct cpuinfo_cache l1i[restrict static 1],
struct cpuinfo_cache l1d[restrict static 1],
struct cpuinfo_cache l2[restrict static 1],
struct cpuinfo_cache l3[restrict static 1]);
Loading

0 comments on commit 68fecdb

Please sign in to comment.