diff options
Diffstat (limited to 'platform/linux-generic/source/odp_system_info.c')
-rw-r--r-- | platform/linux-generic/source/odp_system_info.c | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/platform/linux-generic/source/odp_system_info.c b/platform/linux-generic/source/odp_system_info.c new file mode 100644 index 000000000..1727f26e0 --- /dev/null +++ b/platform/linux-generic/source/odp_system_info.c @@ -0,0 +1,319 @@ +/* Copyright (c) 2013, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp_system_info.h> +#include <odp_internal.h> +#include <odp_debug.h> +#include <odp_align.h> +#include <string.h> + +/* sysconf */ +#include <unistd.h> +#include <sys/sysinfo.h> + +typedef struct { + uint64_t cpu_hz; + int cache_line_size; + int core_count; + char model_str[128]; + +} odp_system_info_t; + +typedef struct { + const char *cpu_arch_str; + int (*cpuinfo_parser)(FILE *file, odp_system_info_t *sysinfo); + +} odp_compiler_info_t; + +static odp_system_info_t odp_system_info; + + +#define CACHE_LNSZ_FILE \ + "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size" + + +/* + * Sysconf + */ +static int sysconf_core_count(void) +{ + long ret; + + ret = sysconf(_SC_NPROCESSORS_CONF); + + if (ret < 0) + return 0; + + return (int)ret; +} + + +#if defined __x86_64__ || defined __i386__ || defined __OCTEON__ +/* + * Analysis of /sys/devices/system/cpu/ files + */ +static int systemcpu_cache_line_size(void) +{ + FILE *file; + char str[128]; + int size = 0; + + file = fopen(CACHE_LNSZ_FILE, "rt"); + + if (file == NULL) { + /* File not found */ + return 0; + } + + if (fgets(str, sizeof(str), file) != NULL) { + /* Read cache line size */ + sscanf(str, "%i", &size); + } + + fclose(file); + + return size; +} + +#endif + + +/* + * HW specific /proc/cpuinfo file parsing + */ +#if defined __x86_64__ || defined __i386__ + +static int cpuinfo_x86(FILE *file, odp_system_info_t *sysinfo) +{ + char str[1024]; + char *pos; + double mhz = 0.0; + int model = 0; + int count = 2; + + while (fgets(str, sizeof(str), file) != NULL && count > 0) { + if (!mhz) { + pos = strstr(str, "cpu MHz"); + + if (pos) { + sscanf(pos, "cpu MHz : %lf", &mhz); + count--; + } + } + + if (!model) { + pos = strstr(str, "model name"); + + if (pos) { + int len; + pos = strchr(str, ':'); + strncpy(sysinfo->model_str, pos+2, + sizeof(sysinfo->model_str)); + len = strlen(sysinfo->model_str); + sysinfo->model_str[len - 1] = 0; + model = 1; + count--; + } + } + } + + sysinfo->cpu_hz = (uint64_t) (mhz * 1000000.0); + + return 0; +} + +#elif defined __arm__ + +static int cpuinfo_arm(FILE *file ODP_UNUSED, +odp_system_info_t *sysinfo ODP_UNUSED) +{ + return 0; +} + +#elif defined __OCTEON__ + +static int cpuinfo_octeon(FILE *file, odp_system_info_t *sysinfo) +{ + char str[1024]; + char *pos; + double mhz = 0.0; + int model = 0; + int count = 2; + + while (fgets(str, sizeof(str), file) != NULL && count > 0) { + if (!mhz) { + pos = strstr(str, "BogoMIPS"); + + if (pos) { + sscanf(pos, "BogoMIPS : %lf", &mhz); + count--; + } + } + + if (!model) { + pos = strstr(str, "cpu model"); + + if (pos) { + int len; + pos = strchr(str, ':'); + strncpy(sysinfo->model_str, pos+2, + sizeof(sysinfo->model_str)); + len = strlen(sysinfo->model_str); + sysinfo->model_str[len - 1] = 0; + model = 1; + count--; + } + } + } + + /* bogomips seems to be 2x freq */ + sysinfo->cpu_hz = (uint64_t) (mhz * 1000000.0 / 2.0); + + return 0; +} + +#else + #error GCC target not found +#endif + +static odp_compiler_info_t compiler_info = { + #if defined __x86_64__ || defined __i386__ + .cpu_arch_str = "x86", + .cpuinfo_parser = cpuinfo_x86 + + #elif defined __arm__ + .cpu_arch_str = "arm", + .cpuinfo_parser = cpuinfo_arm + + #elif defined __OCTEON__ + .cpu_arch_str = "octeon", + .cpuinfo_parser = cpuinfo_octeon + + #else + #error GCC target not found + #endif +}; + + +#if defined __x86_64__ || defined __i386__ || defined __OCTEON__ + +/* + * Analysis of /sys/devices/system/cpu/ files + */ +static int systemcpu(odp_system_info_t *sysinfo) +{ + int ret; + + ret = sysconf_core_count(); + + if (ret == 0) { + ODP_ERR("sysconf_core_count failed.\n"); + return -1; + } + + sysinfo->core_count = ret; + + + ret = systemcpu_cache_line_size(); + + if (ret == 0) { + ODP_ERR("systemcpu_cache_line_size failed.\n"); + return -1; + } + + sysinfo->cache_line_size = ret; + + if (ret != ODP_CACHE_LINE_SIZE) { + ODP_ERR("Cache line sizes definitions don't match.\n"); + return -1; + } + + return 0; +} + +#else + +/* + * Use sysconf and dummy values in generic case + */ + + +static int systemcpu(odp_system_info_t *sysinfo) +{ + int ret; + + ret = sysconf_core_count(); + + if (ret == 0) { + ODP_ERR("sysconf_core_count failed.\n"); + return -1; + } + + sysinfo->core_count = ret; + + /* Dummy values */ + sysinfo->cpu_hz = 1400000000; + sysinfo->cache_line_size = 64; + + strncpy(sysinfo->model_str, "UNKNOWN", sizeof(sysinfo->model_str)); + + return 0; +} + +#endif + +/* + * System info initialisation + */ +int odp_system_info_init(void) +{ + FILE *file; + + memset(&odp_system_info, 0, sizeof(odp_system_info_t)); + + file = fopen("/proc/cpuinfo", "rt"); + + if (file == NULL) { + ODP_ERR("Failed to open /proc/cpuinfo\n"); + return -1; + } + + compiler_info.cpuinfo_parser(file, &odp_system_info); + + fclose(file); + + if (systemcpu(&odp_system_info)) { + ODP_ERR("systemcpu failed\n"); + return -1; + } + + return 0; +} + +/* + ************************* + * Public access functions + ************************* + */ +uint64_t odp_sys_cpu_hz(void) +{ + return odp_system_info.cpu_hz; +} + +const char *odp_sys_cpu_model_str(void) +{ + return odp_system_info.model_str; +} + +int odp_sys_cache_line_size(void) +{ + return odp_system_info.cache_line_size; +} + +int odp_sys_core_count(void) +{ + return odp_system_info.core_count; +} |