703 lines
18 KiB
Diff
703 lines
18 KiB
Diff
|
From ca2e17833fa81026f0dfcf35b6b01a5f9f6c0806 Mon Sep 17 00:00:00 2001
|
||
|
Message-Id: <ca2e17833fa81026f0dfcf35b6b01a5f9f6c0806.1587532692.git.kamalesh@linux.vnet.ibm.com>
|
||
|
In-Reply-To: <cover.1587532692.git.kamalesh@linux.vnet.ibm.com>
|
||
|
References: <cover.1587532692.git.kamalesh@linux.vnet.ibm.com>
|
||
|
From: Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>
|
||
|
Date: Tue, 21 Apr 2020 07:05:00 -0500
|
||
|
Subject: [PATCH V4 01/14] common/cpu_info_helpers: library to capture CPU
|
||
|
information
|
||
|
To: powerpc-utils-devel@googlegroups.com
|
||
|
Cc: Tyrel Datwyler <tyreld@linux.ibm.com>,
|
||
|
Nathan Lynch <nathanl@linux.ibm.com>,
|
||
|
Naveen N . Rao <naveen.n.rao@linux.vnet.ibm.com>,
|
||
|
Gautham R . Shenoy <ego@linux.vnet.ibm.com>,
|
||
|
Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
|
||
|
|
||
|
ppc64_cpu tool does a lots of heavy lifting in finding the information
|
||
|
about the underlying CPU topology and various other details. These
|
||
|
details might be required by other tools, probing the underlying
|
||
|
platform for similar details. Moving such functions to a common
|
||
|
library, allows sharing across ppc64_cpu and others tools, instead of
|
||
|
multiple implementation of functions capturing same information.
|
||
|
|
||
|
Signed-off-by: Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>
|
||
|
---
|
||
|
Makefile.am | 4 +-
|
||
|
src/common/cpu_info_helpers.c | 290 ++++++++++++++++++++++++++++++++++
|
||
|
src/common/cpu_info_helpers.h | 46 ++++++
|
||
|
src/ppc64_cpu.c | 227 +-------------------------
|
||
|
4 files changed, 346 insertions(+), 221 deletions(-)
|
||
|
create mode 100644 src/common/cpu_info_helpers.c
|
||
|
create mode 100644 src/common/cpu_info_helpers.h
|
||
|
|
||
|
diff --git a/Makefile.am b/Makefile.am
|
||
|
index a272008..1f0b4f6 100644
|
||
|
--- a/Makefile.am
|
||
|
+++ b/Makefile.am
|
||
|
@@ -63,6 +63,8 @@ pseries_platform_SOURCES = src/common/pseries_platform.c src/common/pseries_plat
|
||
|
|
||
|
librtas_error_SOURCES = src/common/librtas_error.c src/common/librtas_error.h
|
||
|
|
||
|
+cpu_info_helpers_SOURCES = src/common/cpu_info_helpers.c src/common/cpu_info_helpers.h
|
||
|
+
|
||
|
src_nvram_SOURCES = src/nvram.c src/nvram.h $(pseries_platform_SOURCES)
|
||
|
src_nvram_LDADD = -lz @LIBDL@
|
||
|
|
||
|
@@ -70,7 +72,7 @@ src_lsprop_SOURCES = src/lsprop.c $(pseries_platform_SOURCES)
|
||
|
|
||
|
src_lparstat_SOURCES = src/lparstat.c src/lparstat.h $(pseries_platform_SOURCES)
|
||
|
|
||
|
-src_ppc64_cpu_SOURCES = src/ppc64_cpu.c $(pseries_platform_SOURCES)
|
||
|
+src_ppc64_cpu_SOURCES = src/ppc64_cpu.c $(pseries_platform_SOURCES) $(cpu_info_helpers_SOURCES)
|
||
|
src_ppc64_cpu_LDADD = -lpthread
|
||
|
|
||
|
|
||
|
diff --git a/src/common/cpu_info_helpers.c b/src/common/cpu_info_helpers.c
|
||
|
new file mode 100644
|
||
|
index 0000000..0bb1dfe
|
||
|
--- /dev/null
|
||
|
+++ b/src/common/cpu_info_helpers.c
|
||
|
@@ -0,0 +1,290 @@
|
||
|
+/**
|
||
|
+ * @file cpu_info_helpers.c
|
||
|
+ * @brief Common routines to capture cpu information
|
||
|
+ *
|
||
|
+ * Copyright (c) 2007, 2020 International Business Machines
|
||
|
+ *
|
||
|
+ * This program is free software; you can redistribute it and/or
|
||
|
+ * modify it under the terms of the GNU General Public License
|
||
|
+ * as published by the Free Software Foundation; either version 2
|
||
|
+ * of the License, or (at your option) any later version.
|
||
|
+ *
|
||
|
+ * This program is distributed in the hope that it will be useful,
|
||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * along with this program; if not, write to the Free Software
|
||
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
+ *
|
||
|
+ * @author Anton Blanchard <anton@au.ibm.com>
|
||
|
+ * @author Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>
|
||
|
+ */
|
||
|
+#define _GNU_SOURCE
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <string.h>
|
||
|
+#include <sched.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <stdbool.h>
|
||
|
+#include <dirent.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <sys/types.h>
|
||
|
+#include "cpu_info_helpers.h"
|
||
|
+
|
||
|
+int get_attribute(char *path, const char *fmt, int *value)
|
||
|
+{
|
||
|
+ FILE *fp;
|
||
|
+ int rc;
|
||
|
+
|
||
|
+ rc = access(path, F_OK);
|
||
|
+ if (rc)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ fp = fopen(path, "r");
|
||
|
+ if (!fp)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ rc = fscanf(fp, fmt, value);
|
||
|
+ fclose(fp);
|
||
|
+
|
||
|
+ if (rc == EOF)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int test_sysattr(char *attribute, int perms, int threads_in_system)
|
||
|
+{
|
||
|
+ char path[SYSFS_PATH_MAX];
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 0; i < threads_in_system; i++) {
|
||
|
+ sprintf(path, SYSFS_CPUDIR"/%s", i, attribute);
|
||
|
+ if (access(path, F_OK))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (access(path, perms))
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
+int __sysattr_is_readable(char *attribute, int threads_in_system)
|
||
|
+{
|
||
|
+ return test_sysattr(attribute, R_OK, threads_in_system);
|
||
|
+}
|
||
|
+
|
||
|
+int __sysattr_is_writeable(char *attribute, int threads_in_system)
|
||
|
+{
|
||
|
+ return test_sysattr(attribute, W_OK, threads_in_system);
|
||
|
+}
|
||
|
+
|
||
|
+int cpu_online(int thread)
|
||
|
+{
|
||
|
+ char path[SYSFS_PATH_MAX];
|
||
|
+ int rc, online;
|
||
|
+
|
||
|
+ sprintf(path, SYSFS_CPUDIR"/online", thread);
|
||
|
+ rc = get_attribute(path, "%d", &online);
|
||
|
+
|
||
|
+ /* This attribute does not exist in kernels without hotplug enabled */
|
||
|
+ if (rc && errno == ENOENT)
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ if (rc || !online)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
+int is_subcore_capable(void)
|
||
|
+{
|
||
|
+ return access(SYSFS_SUBCORES, F_OK) == 0;
|
||
|
+}
|
||
|
+
|
||
|
+int num_subcores(void)
|
||
|
+{
|
||
|
+ int rc, subcores;
|
||
|
+
|
||
|
+ rc = get_attribute(SYSFS_SUBCORES, "%d", &subcores);
|
||
|
+ if (rc)
|
||
|
+ return -1;
|
||
|
+ return subcores;
|
||
|
+}
|
||
|
+
|
||
|
+int get_cpu_info(int *_threads_per_cpu, int *_cpus_in_system,
|
||
|
+ int *_threads_in_system)
|
||
|
+{
|
||
|
+ DIR *d;
|
||
|
+ struct dirent *de;
|
||
|
+ int first_cpu = 1;
|
||
|
+ int rc;
|
||
|
+ int subcores;
|
||
|
+ int threads_in_system;
|
||
|
+ int threads_per_cpu = 0;
|
||
|
+ int cpus_in_system = 0;
|
||
|
+
|
||
|
+ d = opendir("/proc/device-tree/cpus");
|
||
|
+ if (!d)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ while ((de = readdir(d)) != NULL) {
|
||
|
+ if (!strncmp(de->d_name, "PowerPC", 7)) {
|
||
|
+ if (first_cpu) {
|
||
|
+ struct stat sbuf;
|
||
|
+ char path[128];
|
||
|
+
|
||
|
+ snprintf(path, sizeof(path), INTSERV_PATH, de->d_name);
|
||
|
+ rc = stat(path, &sbuf);
|
||
|
+ if (!rc)
|
||
|
+ threads_per_cpu = sbuf.st_size / 4;
|
||
|
+
|
||
|
+ first_cpu = 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ cpus_in_system++;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ closedir(d);
|
||
|
+ threads_in_system = cpus_in_system * threads_per_cpu;
|
||
|
+
|
||
|
+ subcores = num_subcores();
|
||
|
+ if (is_subcore_capable() && subcores > 0) {
|
||
|
+ threads_per_cpu /= subcores;
|
||
|
+ cpus_in_system *= subcores;
|
||
|
+ }
|
||
|
+
|
||
|
+ *_threads_per_cpu = threads_per_cpu;
|
||
|
+ *_threads_in_system = threads_in_system;
|
||
|
+ *_cpus_in_system = cpus_in_system;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+int __is_smt_capable(int threads_in_system)
|
||
|
+{
|
||
|
+ struct stat sb;
|
||
|
+ char path[SYSFS_PATH_MAX];
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 0; i < threads_in_system; i++) {
|
||
|
+ sprintf(path, SYSFS_CPUDIR"/smt_snooze_delay", i);
|
||
|
+ if (stat(path, &sb))
|
||
|
+ continue;
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+int __get_one_smt_state(int core, int threads_per_cpu)
|
||
|
+{
|
||
|
+ int primary_thread = core * threads_per_cpu;
|
||
|
+ int smt_state = 0;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ if (!__sysattr_is_readable("online", threads_per_cpu)) {
|
||
|
+ perror("Cannot retrieve smt state");
|
||
|
+ return -2;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; i < threads_per_cpu; i++) {
|
||
|
+ smt_state += cpu_online(primary_thread + i);
|
||
|
+ }
|
||
|
+
|
||
|
+ return smt_state;
|
||
|
+}
|
||
|
+
|
||
|
+static void print_cpu_list(const cpu_set_t *cpuset, int cpuset_size,
|
||
|
+ int cpus_in_system)
|
||
|
+{
|
||
|
+ int core;
|
||
|
+ const char *comma = "";
|
||
|
+
|
||
|
+ for (core = 0; core < cpus_in_system; core++) {
|
||
|
+ int begin = core;
|
||
|
+ if (CPU_ISSET_S(core, cpuset_size, cpuset)) {
|
||
|
+ while (CPU_ISSET_S(core+1, cpuset_size, cpuset))
|
||
|
+ core++;
|
||
|
+
|
||
|
+ if (core > begin)
|
||
|
+ printf("%s%d-%d", comma, begin, core);
|
||
|
+ else
|
||
|
+ printf("%s%d", comma, core);
|
||
|
+ comma = ",";
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+int __do_smt(bool numeric, int cpus_in_system, int threads_per_cpu,
|
||
|
+ bool print_smt_state)
|
||
|
+{
|
||
|
+ int thread, c, smt_state = 0;
|
||
|
+ cpu_set_t **cpu_states = NULL;
|
||
|
+ int cpu_state_size = CPU_ALLOC_SIZE(cpus_in_system);
|
||
|
+ int start_cpu = 0, stop_cpu = cpus_in_system;
|
||
|
+ int rc = 0;
|
||
|
+
|
||
|
+ cpu_states = (cpu_set_t **)calloc(threads_per_cpu, sizeof(cpu_set_t));
|
||
|
+ if (!cpu_states)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ for (thread = 0; thread < threads_per_cpu; thread++) {
|
||
|
+ cpu_states[thread] = CPU_ALLOC(cpus_in_system);
|
||
|
+ CPU_ZERO_S(cpu_state_size, cpu_states[thread]);
|
||
|
+ }
|
||
|
+
|
||
|
+ for (c = start_cpu; c < stop_cpu; c++) {
|
||
|
+ int threads_online = __get_one_smt_state(c, threads_per_cpu);
|
||
|
+
|
||
|
+ if (threads_online < 0) {
|
||
|
+ rc = threads_online;
|
||
|
+ goto cleanup_get_smt;
|
||
|
+ }
|
||
|
+ if (threads_online)
|
||
|
+ CPU_SET_S(c, cpu_state_size,
|
||
|
+ cpu_states[threads_online - 1]);
|
||
|
+ }
|
||
|
+
|
||
|
+ for (thread = 0; thread < threads_per_cpu; thread++) {
|
||
|
+ if (CPU_COUNT_S(cpu_state_size, cpu_states[thread])) {
|
||
|
+ if (smt_state == 0)
|
||
|
+ smt_state = thread + 1;
|
||
|
+ else if (smt_state > 0)
|
||
|
+ smt_state = -1; /* mix of SMT modes */
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!print_smt_state)
|
||
|
+ return smt_state;
|
||
|
+
|
||
|
+ if (smt_state == 1) {
|
||
|
+ if (numeric)
|
||
|
+ printf("SMT=1\n");
|
||
|
+ else
|
||
|
+ printf("SMT is off\n");
|
||
|
+ } else if (smt_state == -1) {
|
||
|
+ for (thread = 0; thread < threads_per_cpu; thread++) {
|
||
|
+ if (CPU_COUNT_S(cpu_state_size,
|
||
|
+ cpu_states[thread])) {
|
||
|
+ printf("SMT=%d: ", thread + 1);
|
||
|
+ print_cpu_list(cpu_states[thread],
|
||
|
+ cpu_state_size, cpus_in_system);
|
||
|
+ printf("\n");
|
||
|
+ }
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ printf("SMT=%d\n", smt_state);
|
||
|
+ }
|
||
|
+
|
||
|
+cleanup_get_smt:
|
||
|
+ for (thread = 0; thread < threads_per_cpu; thread++)
|
||
|
+ CPU_FREE(cpu_states[thread]);
|
||
|
+
|
||
|
+ return rc;
|
||
|
+}
|
||
|
diff --git a/src/common/cpu_info_helpers.h b/src/common/cpu_info_helpers.h
|
||
|
new file mode 100644
|
||
|
index 0000000..8f09d79
|
||
|
--- /dev/null
|
||
|
+++ b/src/common/cpu_info_helpers.h
|
||
|
@@ -0,0 +1,46 @@
|
||
|
+/**
|
||
|
+ * @file cpu_info_helpers.h
|
||
|
+ * @brief Header of common routines to capture cpu information
|
||
|
+ *
|
||
|
+ * Copyright (c) 2007, 2020 International Business Machines
|
||
|
+ *
|
||
|
+ * This program is free software; you can redistribute it and/or
|
||
|
+ * modify it under the terms of the GNU General Public License
|
||
|
+ * as published by the Free Software Foundation; either version 2
|
||
|
+ * of the License, or (at your option) any later version.
|
||
|
+ *
|
||
|
+ * This program is distributed in the hope that it will be useful,
|
||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * along with this program; if not, write to the Free Software
|
||
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
+ *
|
||
|
+ * @author Anton Blanchard <anton@au.ibm.com>
|
||
|
+ * @author Kamalesh Babulal <kamaleshb@linux.vnet.ibm.com>
|
||
|
+ */
|
||
|
+#ifndef _CPU_INFO_HELPERS_H
|
||
|
+#define _CPU_INFO_HELPERS_H
|
||
|
+
|
||
|
+#define SYSFS_CPUDIR "/sys/devices/system/cpu/cpu%d"
|
||
|
+#define SYSFS_SUBCORES "/sys/devices/system/cpu/subcores_per_core"
|
||
|
+#define INTSERV_PATH "/proc/device-tree/cpus/%s/ibm,ppc-interrupt-server#s"
|
||
|
+
|
||
|
+#define SYSFS_PATH_MAX 128
|
||
|
+
|
||
|
+extern int __sysattr_is_readable(char *attribute, int threads_in_system);
|
||
|
+extern int __sysattr_is_writeable(char *attribute, int threads_in_system);
|
||
|
+extern int cpu_online(int thread);
|
||
|
+extern int is_subcore_capable(void);
|
||
|
+extern int num_subcores(void);
|
||
|
+extern int get_attribute(char *path, const char *fmt, int *value);
|
||
|
+extern int get_cpu_info(int *threads_per_cpu, int *cpus_in_system,
|
||
|
+ int *threads_in_system);
|
||
|
+extern int __is_smt_capable(int threads_in_system);
|
||
|
+extern int __get_one_smt_state(int core, int threads_per_cpu);
|
||
|
+extern int __do_smt(bool numeric, int cpus_in_system, int threads_per_cpu,
|
||
|
+ bool print_smt_state);
|
||
|
+
|
||
|
+#endif /* CPU_INFO_H */
|
||
|
diff --git a/src/ppc64_cpu.c b/src/ppc64_cpu.c
|
||
|
index 6d02235..cacbf1a 100644
|
||
|
--- a/src/ppc64_cpu.c
|
||
|
+++ b/src/ppc64_cpu.c
|
||
|
@@ -47,15 +47,12 @@
|
||
|
#endif
|
||
|
|
||
|
#include <errno.h>
|
||
|
+#include "cpu_info_helpers.h"
|
||
|
|
||
|
#define PPC64_CPU_VERSION "1.2"
|
||
|
|
||
|
-#define SYSFS_CPUDIR "/sys/devices/system/cpu/cpu%d"
|
||
|
-#define SYSFS_SUBCORES "/sys/devices/system/cpu/subcores_per_core"
|
||
|
#define DSCR_DEFAULT_PATH "/sys/devices/system/cpu/dscr_default"
|
||
|
-#define INTSERV_PATH "/proc/device-tree/cpus/%s/ibm,ppc-interrupt-server#s"
|
||
|
|
||
|
-#define SYSFS_PATH_MAX 128
|
||
|
#define MAX_NR_CPUS 1024
|
||
|
#define DIAGNOSTICS_RUN_MODE 42
|
||
|
#define CPU_OFFLINE -1
|
||
|
@@ -80,54 +77,14 @@ static int threads_in_system = 0;
|
||
|
|
||
|
static int do_info(void);
|
||
|
|
||
|
-static int test_sysattr(char *attribute, int perms)
|
||
|
-{
|
||
|
- char path[SYSFS_PATH_MAX];
|
||
|
- int i;
|
||
|
-
|
||
|
- for (i = 0; i < threads_in_system; i++) {
|
||
|
- sprintf(path, SYSFS_CPUDIR"/%s", i, attribute);
|
||
|
- if (access(path, F_OK))
|
||
|
- continue;
|
||
|
-
|
||
|
- if (access(path, perms))
|
||
|
- return 0;
|
||
|
- }
|
||
|
-
|
||
|
- return 1;
|
||
|
-}
|
||
|
-
|
||
|
static int sysattr_is_readable(char *attribute)
|
||
|
{
|
||
|
- return test_sysattr(attribute, R_OK);
|
||
|
+ return __sysattr_is_readable(attribute, threads_in_system);
|
||
|
}
|
||
|
|
||
|
static int sysattr_is_writeable(char *attribute)
|
||
|
{
|
||
|
- return test_sysattr(attribute, W_OK);
|
||
|
-}
|
||
|
-
|
||
|
-static int get_attribute(char *path, const char *fmt, int *value)
|
||
|
-{
|
||
|
- FILE *fp;
|
||
|
- int rc;
|
||
|
-
|
||
|
- rc = access(path, F_OK);
|
||
|
- if (rc)
|
||
|
- return -1;
|
||
|
-
|
||
|
-
|
||
|
- fp = fopen(path, "r");
|
||
|
- if (!fp)
|
||
|
- return -1;
|
||
|
-
|
||
|
- rc = fscanf(fp, fmt, value);
|
||
|
- fclose(fp);
|
||
|
-
|
||
|
- if (rc == EOF)
|
||
|
- return -1;
|
||
|
-
|
||
|
- return 0;
|
||
|
+ return __sysattr_is_writeable(attribute, threads_in_system);
|
||
|
}
|
||
|
|
||
|
static int set_attribute(const char *path, const char *fmt, int value)
|
||
|
@@ -156,24 +113,6 @@ close:
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
-static int cpu_online(int thread)
|
||
|
-{
|
||
|
- char path[SYSFS_PATH_MAX];
|
||
|
- int rc, online;
|
||
|
-
|
||
|
- sprintf(path, SYSFS_CPUDIR"/online", thread);
|
||
|
- rc = get_attribute(path, "%d", &online);
|
||
|
-
|
||
|
- /* This attribute does not exist in kernels without hotplug enabled */
|
||
|
- if (rc && errno == ENOENT)
|
||
|
- return 1;
|
||
|
-
|
||
|
- if (rc || !online)
|
||
|
- return 0;
|
||
|
-
|
||
|
- return 1;
|
||
|
-}
|
||
|
-
|
||
|
static int get_system_attribute(char *attribute, const char *fmt, int *value,
|
||
|
int *inconsistent)
|
||
|
{
|
||
|
@@ -316,93 +255,14 @@ static int offline_thread(const char *path)
|
||
|
return set_attribute(path, "%d", 0);
|
||
|
}
|
||
|
|
||
|
-static int is_subcore_capable(void)
|
||
|
-{
|
||
|
- return access(SYSFS_SUBCORES, F_OK) == 0;
|
||
|
-}
|
||
|
-
|
||
|
-static int num_subcores(void)
|
||
|
-{
|
||
|
- int rc, subcores;
|
||
|
- rc = get_attribute(SYSFS_SUBCORES, "%d", &subcores);
|
||
|
- if (rc)
|
||
|
- return -1;
|
||
|
- return subcores;
|
||
|
-}
|
||
|
-
|
||
|
-static int get_cpu_info(void)
|
||
|
-{
|
||
|
- DIR *d;
|
||
|
- struct dirent *de;
|
||
|
- int first_cpu = 1;
|
||
|
- int rc;
|
||
|
- int subcores;
|
||
|
-
|
||
|
- d = opendir("/proc/device-tree/cpus");
|
||
|
- if (!d)
|
||
|
- return -1;
|
||
|
-
|
||
|
- while ((de = readdir(d)) != NULL) {
|
||
|
- if (!strncmp(de->d_name, "PowerPC", 7)) {
|
||
|
- if (first_cpu) {
|
||
|
- struct stat sbuf;
|
||
|
- char path[128];
|
||
|
-
|
||
|
- sprintf(path, INTSERV_PATH, de->d_name);
|
||
|
- rc = stat(path, &sbuf);
|
||
|
- if (!rc)
|
||
|
- threads_per_cpu = sbuf.st_size / 4;
|
||
|
-
|
||
|
- first_cpu = 0;
|
||
|
- }
|
||
|
-
|
||
|
- cpus_in_system++;
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- closedir(d);
|
||
|
- threads_in_system = cpus_in_system * threads_per_cpu;
|
||
|
-
|
||
|
- subcores = num_subcores();
|
||
|
- if (is_subcore_capable() && subcores > 0) {
|
||
|
- threads_per_cpu /= subcores;
|
||
|
- cpus_in_system *= subcores;
|
||
|
- }
|
||
|
- return 0;
|
||
|
-}
|
||
|
-
|
||
|
static int is_smt_capable(void)
|
||
|
{
|
||
|
- struct stat sb;
|
||
|
- char path[SYSFS_PATH_MAX];
|
||
|
- int i;
|
||
|
-
|
||
|
- for (i = 0; i < threads_in_system; i++) {
|
||
|
- sprintf(path, SYSFS_CPUDIR"/smt_snooze_delay", i);
|
||
|
- if (stat(path, &sb))
|
||
|
- continue;
|
||
|
- return 1;
|
||
|
- }
|
||
|
-
|
||
|
- return 0;
|
||
|
+ return __is_smt_capable(threads_in_system);
|
||
|
}
|
||
|
|
||
|
static int get_one_smt_state(int core)
|
||
|
{
|
||
|
- int primary_thread = core * threads_per_cpu;
|
||
|
- int smt_state = 0;
|
||
|
- int i;
|
||
|
-
|
||
|
- if (!sysattr_is_readable("online")) {
|
||
|
- perror("Cannot retrieve smt state");
|
||
|
- return -2;
|
||
|
- }
|
||
|
-
|
||
|
- for (i = 0; i < threads_per_cpu; i++) {
|
||
|
- smt_state += cpu_online(primary_thread + i);
|
||
|
- }
|
||
|
-
|
||
|
- return smt_state;
|
||
|
+ return __get_one_smt_state(core, threads_per_cpu);
|
||
|
}
|
||
|
|
||
|
static int get_smt_state(void)
|
||
|
@@ -513,26 +373,6 @@ static int is_dscr_capable(void)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-void print_cpu_list(const cpu_set_t *cpuset, int cpuset_size)
|
||
|
-{
|
||
|
- int core;
|
||
|
- const char *comma = "";
|
||
|
-
|
||
|
- for (core = 0; core < cpus_in_system; core++) {
|
||
|
- int begin = core;
|
||
|
- if (CPU_ISSET_S(core, cpuset_size, cpuset)) {
|
||
|
- while (CPU_ISSET_S(core+1, cpuset_size, cpuset))
|
||
|
- core++;
|
||
|
-
|
||
|
- if (core > begin)
|
||
|
- printf("%s%d-%d", comma, begin, core);
|
||
|
- else
|
||
|
- printf("%s%d", comma, core);
|
||
|
- comma = ",";
|
||
|
- }
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
static int do_smt(char *state, bool numeric)
|
||
|
{
|
||
|
int rc = 0;
|
||
|
@@ -547,60 +387,7 @@ static int do_smt(char *state, bool numeric)
|
||
|
}
|
||
|
|
||
|
if (!state) {
|
||
|
- int thread, c;
|
||
|
- cpu_set_t *cpu_states[threads_per_cpu];
|
||
|
- int cpu_state_size = CPU_ALLOC_SIZE(cpus_in_system);
|
||
|
- int start_cpu = 0, stop_cpu = cpus_in_system;
|
||
|
-
|
||
|
- for (thread = 0; thread < threads_per_cpu; thread++) {
|
||
|
- cpu_states[thread] = CPU_ALLOC(cpus_in_system);
|
||
|
- CPU_ZERO_S(cpu_state_size, cpu_states[thread]);
|
||
|
- }
|
||
|
-
|
||
|
- for (c = start_cpu; c < stop_cpu; c++) {
|
||
|
- int threads_online = get_one_smt_state(c);
|
||
|
-
|
||
|
- if (threads_online < 0) {
|
||
|
- rc = threads_online;
|
||
|
- goto cleanup_get_smt;
|
||
|
- }
|
||
|
- if (threads_online)
|
||
|
- CPU_SET_S(c, cpu_state_size,
|
||
|
- cpu_states[threads_online - 1]);
|
||
|
- }
|
||
|
-
|
||
|
- for (thread = 0; thread < threads_per_cpu; thread++) {
|
||
|
- if (CPU_COUNT_S(cpu_state_size, cpu_states[thread])) {
|
||
|
- if (smt_state == 0)
|
||
|
- smt_state = thread + 1;
|
||
|
- else if (smt_state > 0)
|
||
|
- smt_state = -1; /* mix of SMT modes */
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- if (smt_state == 1) {
|
||
|
- if (numeric)
|
||
|
- printf("SMT=1\n");
|
||
|
- else
|
||
|
- printf("SMT is off\n");
|
||
|
- } else if (smt_state == -1) {
|
||
|
- for (thread = 0; thread < threads_per_cpu; thread++) {
|
||
|
- if (CPU_COUNT_S(cpu_state_size,
|
||
|
- cpu_states[thread])) {
|
||
|
- printf("SMT=%d: ", thread + 1);
|
||
|
- print_cpu_list(cpu_states[thread],
|
||
|
- cpu_state_size);
|
||
|
- printf("\n");
|
||
|
- }
|
||
|
- }
|
||
|
- } else {
|
||
|
- printf("SMT=%d\n", smt_state);
|
||
|
- }
|
||
|
-
|
||
|
-cleanup_get_smt:
|
||
|
- for (thread = 0; thread < threads_per_cpu; thread++)
|
||
|
- CPU_FREE(cpu_states[thread]);
|
||
|
-
|
||
|
+ rc = __do_smt(numeric, cpus_in_system, threads_per_cpu, true);
|
||
|
} else {
|
||
|
if (!strcmp(state, "on"))
|
||
|
smt_state = threads_per_cpu;
|
||
|
@@ -1510,7 +1297,7 @@ int main(int argc, char *argv[])
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
- rc = get_cpu_info();
|
||
|
+ rc = get_cpu_info(&threads_per_cpu, &cpus_in_system, &threads_in_system);
|
||
|
if (rc) {
|
||
|
printf("Could not determine system cpu/thread information.\n");
|
||
|
return rc;
|
||
|
--
|
||
|
2.25.3
|
||
|
|