diff --git a/0001-common-cpu_info_helpers-library-to-capture-CPU-infor.patch b/0001-common-cpu_info_helpers-library-to-capture-CPU-infor.patch new file mode 100644 index 0000000..e1e22dd --- /dev/null +++ b/0001-common-cpu_info_helpers-library-to-capture-CPU-infor.patch @@ -0,0 +1,702 @@ +From ca2e17833fa81026f0dfcf35b6b01a5f9f6c0806 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: +References: +From: Kamalesh Babulal +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 , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +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 +--- + 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 ++ * @author Kamalesh Babulal ++ */ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 ++ * @author Kamalesh Babulal ++ */ ++#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 ++#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 + diff --git a/0001-powerpc-utils-Suppress-errors-reading-kern.v2.patch b/0001-powerpc-utils-Suppress-errors-reading-kern.v2.patch new file mode 100644 index 0000000..f99cde6 --- /dev/null +++ b/0001-powerpc-utils-Suppress-errors-reading-kern.v2.patch @@ -0,0 +1,85 @@ +From 4fe0e76e1d02787b4cf60eafd2fb3667897becf4 Mon Sep 17 00:00:00 2001 +From: Michael Bringmann +Date: Tue, 23 Jul 2019 15:58:21 -0500 +Subject: [PATCH 1/1] powerpc-utils: Suppress errors reading kernel + files + +A problem was observed with the evaluation of the '${devspec}' +by the script 'ofpathname'. This patch provided improved +handling of errors within that script, and by some of the +follow-on uses of the tool by the 'bootlist' script. + +* Deal with error messages returned sometimes by evaluation + of ${devspec} in 'ofpathname'. +* Strip embedded nulls from values provided by kernel files, + especially, /proc/device-tree${devspec}/namespace/name, + in 'ofpathname'. +* Redirect more error messages to /dev/null + +Signed-off-by: Michael Bringmann +--- + scripts/bootlist | 8 ++++---- + scripts/ofpathname | 4 ++-- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/scripts/bootlist b/scripts/bootlist +index 65926d7..5ce20cf 100755 +--- a/scripts/bootlist ++++ b/scripts/bootlist +@@ -169,7 +169,7 @@ get_logical_device_name() + local devname=$1 + local logical_name + +- logical_name=`$OFPATHNAME -l $devname 2>/dev/null` ++ logical_name=`$OFPATHNAME -l $devname 2>/dev/null | tr -d '\000'` + if [[ $? -ne 0 ]]; then + echo "" + else +@@ -207,11 +207,11 @@ show_bootlist() + local devlist=$1 + local i + +- for i in `$NVRAM --print-config=${devlist} | sed 's/ /\n/g'`; do ++ for i in `$NVRAM --print-config=${devlist} 2> /dev/null | sed 's/ /\n/g'`; do + if [[ $TRANSLATE_NAMES = "yes" ]]; then + name=`get_logical_device_name $i` + if [[ -z $name ]]; then +- echo "Could not translate $i to logical device name" ++ echo "Could not translate $i to logical device name" 2>&1 + else + case $name in + eth*) parse_eth_info $name $i ;; +@@ -230,7 +230,7 @@ show_bootlist() + + . $PSERIES_PLATFORM + if [[ $platform != $PLATFORM_PSERIES_LPAR ]]; then +- echo "bootlist: is not supported on the $platform_name platform" ++ echo "bootlist: is not supported on the $platform_name platform" 2>&1 + exit 1 + fi + +diff --git a/scripts/ofpathname b/scripts/ofpathname +index c37c6bd..09c0209 100755 +--- a/scripts/ofpathname ++++ b/scripts/ofpathname +@@ -656,7 +656,7 @@ l2of_nvme() + + goto_dir $PWD "device/devspec" + +- devspec=`$CAT $PWD/device/devspec` ++ devspec=`$CAT $PWD/device/devspec | tr -d '\000'` + if [[ -n $devspec ]]; then + found=1 + break +@@ -681,7 +681,7 @@ l2of_nvme() + + # Device type is usually 'namespace'. + # Get it from device-tree just in case. +- devtype=`$CAT /proc/device-tree${devspec}/namespace/name` ++ devtype=`$CAT /proc/device-tree${devspec}/namespace/name | tr -d '\000'` 2> /dev/null + if [[ -z $devtype ]]; then + err $ERR_NO_OFPATH + fi +-- +1.8.3.1 + diff --git a/0002-lparstat-Remove-ppc64_cpu-tool-dependency.patch b/0002-lparstat-Remove-ppc64_cpu-tool-dependency.patch new file mode 100644 index 0000000..4a55f99 --- /dev/null +++ b/0002-lparstat-Remove-ppc64_cpu-tool-dependency.patch @@ -0,0 +1,165 @@ +From 5cd8f63b62394840de818328d275d7f20efe79a7 Mon Sep 17 00:00:00 2001 +Message-Id: <5cd8f63b62394840de818328d275d7f20efe79a7.1587532692.git.kamalesh@linux.vnet.ibm.com> +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 07:10:54 -0500 +Subject: [PATCH V4 02/14] lparstat: Remove ppc64_cpu tool dependency +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +get_smt_mode(), calls ppc64_cpu tool to get the current SMT mode, this +method of probing has its disadvantages like tightly coupling lparstat +with ppc64_cpu to mention one. Use, the internal library to fetch this +information. + +Signed-off-by: Kamalesh Babulal +--- + Makefile.am | 3 ++- + src/lparstat.c | 54 ++++++++++++++++++++++++++++++++++---------------- + src/lparstat.h | 2 +- + 3 files changed, 40 insertions(+), 19 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 1f0b4f6..15f8bcc 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -70,7 +70,8 @@ src_nvram_LDADD = -lz @LIBDL@ + + src_lsprop_SOURCES = src/lsprop.c $(pseries_platform_SOURCES) + +-src_lparstat_SOURCES = src/lparstat.c src/lparstat.h $(pseries_platform_SOURCES) ++src_lparstat_SOURCES = src/lparstat.c src/lparstat.h $(pseries_platform_SOURCES) \ ++ $(cpu_info_helpers_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/lparstat.c b/src/lparstat.c +index ffb2cfa..b7cb2d2 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -31,6 +31,7 @@ + #include + #include "lparstat.h" + #include "pseries_platform.h" ++#include "cpu_info_helpers.h" + + #define LPARCFG_FILE "/proc/ppc64/lparcfg" + #define SE_NOT_FOUND "???" +@@ -38,6 +39,10 @@ + + static bool o_legacy = false; + ++static int threads_per_cpu; ++static int cpus_in_system; ++static int threads_in_system; ++ + struct sysentry *get_sysentry(char *name) + { + struct sysentry *se = &system_data[0]; +@@ -73,6 +78,16 @@ void get_sysdata(char *name, char **descr, char *value) + *descr = se->descr; + } + ++static int is_smt_capable(void) ++{ ++ return __is_smt_capable(threads_in_system); ++} ++ ++static int parse_smt_state(void) ++{ ++ return __do_smt(false, cpus_in_system, threads_per_cpu, false); ++} ++ + void get_time() + { + struct timeval t; +@@ -522,32 +537,23 @@ void get_mem_total(struct sysentry *se, char *buf) + + void get_smt_mode(struct sysentry *se, char *buf) + { +- FILE *f; +- char line[128]; +- char *cmd = "/usr/sbin/ppc64_cpu --smt"; +- char *first_line; ++ int smt_state = 0; + +- f = popen(cmd, "r"); +- if (!f) { +- fprintf(stderr, "Failed to execute %s\n", cmd); ++ if (!is_smt_capable()) { ++ sprintf(buf, "1"); + return; + } + +- first_line = fgets(line, 128, f); +- pclose(f); +- +- if (!first_line) { +- fprintf(stderr, "Could not read output of %s\n", cmd); ++ smt_state = parse_smt_state(); ++ if (smt_state < 0) { ++ fprintf(stderr, "Failed to get smt state\n"); + return; + } + +- /* The output is either "SMT=x" or "SMT is off", we can cheat +- * by looking at line[8] for an 'f'. +- */ +- if (line[8] == 'f') ++ if (smt_state == 1) + sprintf(buf, "Off"); + else +- sprintf(buf, "%c", line[4]); ++ sprintf(buf, "%d", smt_state); + } + + long long get_cpu_time_diff() +@@ -574,6 +580,19 @@ void get_cpu_stat(struct sysentry *se, char *buf) + sprintf(buf, "%.2f", percent); + } + ++void init_sysinfo(void) ++{ ++ int rc = 0; ++ ++ /* probe one time system cpu information */ ++ rc = get_cpu_info(&threads_per_cpu, &cpus_in_system, ++ &threads_in_system); ++ if (rc) { ++ fprintf(stderr, "Failed to capture system CPUs information\n"); ++ exit(rc); ++ } ++} ++ + void init_sysdata(void) + { + get_time(); +@@ -746,6 +765,7 @@ int main(int argc, char *argv[]) + if (optind < argc) + count = atoi(argv[optind++]); + ++ init_sysinfo(); + init_sysdata(); + + if (i_option) +diff --git a/src/lparstat.h b/src/lparstat.h +index 3aee192..ae84caf 100644 +--- a/src/lparstat.h ++++ b/src/lparstat.h +@@ -184,7 +184,7 @@ struct sysentry system_data[] = { + .descr = "Online Memory", + .get = &get_mem_total}, + +- /* ppc64_cpu --smt */ ++ /* smt mode, cpu_info_helpers::__do_smt() */ + {.name = "smt_state", + .descr = "SMT", + .get = &get_smt_mode}, +-- +2.25.3 + diff --git a/0003-lparstat-Read-the-online-cores.patch b/0003-lparstat-Read-the-online-cores.patch new file mode 100644 index 0000000..2fac495 --- /dev/null +++ b/0003-lparstat-Read-the-online-cores.patch @@ -0,0 +1,99 @@ +From 9263de80d08451beacc29e4eb83492234d648796 Mon Sep 17 00:00:00 2001 +Message-Id: <9263de80d08451beacc29e4eb83492234d648796.1587532692.git.kamalesh@linux.vnet.ibm.com> +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 07:54:01 -0500 +Subject: [PATCH V4 03/14] lparstat: Read the online cores +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +The accumulation of PURR/SPURR values are total of all online CPU in +the system, hence the timebase also needs to be scaled to the number +of cores. Add a helper to read the online cores. + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 32 ++++++++++++++++++++++++++++++++ + src/lparstat.h | 4 ++++ + 2 files changed, 36 insertions(+) + +diff --git a/src/lparstat.c b/src/lparstat.c +index b7cb2d2..1d0b3a7 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -88,6 +88,11 @@ static int parse_smt_state(void) + return __do_smt(false, cpus_in_system, threads_per_cpu, false); + } + ++static int get_one_smt_state(int core) ++{ ++ return __get_one_smt_state(core, threads_per_cpu); ++} ++ + void get_time() + { + struct timeval t; +@@ -556,6 +561,31 @@ void get_smt_mode(struct sysentry *se, char *buf) + sprintf(buf, "%d", smt_state); + } + ++void get_online_cores(void) ++{ ++ struct sysentry *se; ++ int *core_state; ++ int online_cores = 0; ++ int i; ++ ++ core_state = calloc(cpus_in_system, sizeof(int)); ++ if (!core_state) { ++ fprintf(stderr, "Failed to read online cores\n"); ++ return; ++ } ++ ++ for (i = 0; i < cpus_in_system; i++) { ++ core_state[i] = (get_one_smt_state(i) > 0); ++ if (core_state[i]) ++ online_cores++; ++ } ++ ++ se = get_sysentry("online_cores"); ++ sprintf(se->value, "%d", online_cores); ++ ++ free(core_state); ++} ++ + long long get_cpu_time_diff() + { + long long old_total = 0, new_total = 0; +@@ -591,6 +621,8 @@ void init_sysinfo(void) + fprintf(stderr, "Failed to capture system CPUs information\n"); + exit(rc); + } ++ ++ get_online_cores(); + } + + void init_sysdata(void) +diff --git a/src/lparstat.h b/src/lparstat.h +index ae84caf..6b65b48 100644 +--- a/src/lparstat.h ++++ b/src/lparstat.h +@@ -189,6 +189,10 @@ struct sysentry system_data[] = { + .descr = "SMT", + .get = &get_smt_mode}, + ++ /* online cores, cpu_info_helpers::get_one_smt_state() */ ++ {.name = "online_cores", ++ .descr = "Online Cores"}, ++ + /* /proc/stat */ + {.name = "cpu_total", + .descr = "CPU Total Time"}, +-- +2.25.3 + diff --git a/0004-lparstat-Capture-nominal-frequency.patch b/0004-lparstat-Capture-nominal-frequency.patch new file mode 100644 index 0000000..f655a34 --- /dev/null +++ b/0004-lparstat-Capture-nominal-frequency.patch @@ -0,0 +1,94 @@ +From e8f0f534bab72cecdaf6b5822324d71884cb9133 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 07:55:28 -0500 +Subject: [PATCH V4 04/14] lparstat: Capture nominal frequency +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +Capture the nominal frequency/clock from the /proc/cpuinfo. This value +will be used later to calculate the effective/current frequency at which +the processor is running. + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 36 ++++++++++++++++++++++++++++++++++++ + src/lparstat.h | 2 ++ + 2 files changed, 38 insertions(+) + +diff --git a/src/lparstat.c b/src/lparstat.c +index 1d0b3a7..24c48ad 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -171,6 +171,38 @@ void get_sys_uptime(struct sysentry *unused_se, char *uptime) + fclose(f); + } + ++int get_nominal_frequency(void) ++{ ++ FILE *f; ++ char buf[80]; ++ struct sysentry *se; ++ char *nfreq = NULL; ++ ++ f = fopen("/proc/cpuinfo", "r"); ++ if (!f) { ++ fprintf(stderr, "Could not open /proc/cpuinfo\n"); ++ return -1; ++ } ++ ++ while ((fgets(buf, 80, f)) != NULL) { ++ if (!strncmp(buf, "clock", 5)) { ++ nfreq = strchr(buf, ':') + 2; ++ break; ++ } ++ } ++ ++ fclose(f); ++ ++ if (!nfreq) { ++ fprintf(stderr, "Failed to read Nominal frequency\n"); ++ return -1; ++ } ++ ++ se = get_sysentry("nominal_freq"); ++ snprintf(se->value, sizeof(se->value), "%s", nfreq); ++ ++ return 0; ++} + + void get_cpu_physc(struct sysentry *unused_se, char *buf) + { +@@ -623,6 +655,10 @@ void init_sysinfo(void) + } + + get_online_cores(); ++ ++ rc = get_nominal_frequency(); ++ if (rc) ++ exit(rc); + } + + void init_sysdata(void) +diff --git a/src/lparstat.h b/src/lparstat.h +index 6b65b48..c1bac28 100644 +--- a/src/lparstat.h ++++ b/src/lparstat.h +@@ -242,6 +242,8 @@ struct sysentry system_data[] = { + /* /proc/cpuinfo */ + {.name = "timebase", + .descr = "Timebase"}, ++ {.name = "nominal_freq", ++ .descr = "Nominal Frequency"}, + + /* /proc/interrupts */ + {.name = "phint", +-- +2.25.3 + diff --git a/0005-lparstat-Assign-file-descriptors-to-speed-up-read.patch b/0005-lparstat-Assign-file-descriptors-to-speed-up-read.patch new file mode 100644 index 0000000..35ee8e6 --- /dev/null +++ b/0005-lparstat-Assign-file-descriptors-to-speed-up-read.patch @@ -0,0 +1,215 @@ +From 8f0bf6a9dd14c16ee95092f43c45ee256f10637b Mon Sep 17 00:00:00 2001 +Message-Id: <8f0bf6a9dd14c16ee95092f43c45ee256f10637b.1587532692.git.kamalesh@linux.vnet.ibm.com> +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 07:58:19 -0500 +Subject: [PATCH V4 05/14] lparstat: Assign file descriptors to speed up read +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +For every sampling interval, three per-cpu sysfs files is read to +capture spurr, idle_purr and idle_spurr values. Every read takes +three file operation such as open, read, close, future this scales +with number of CPUs in the system. To reduce the latency involved +in open and close, assign a permanent file descriptors per online cpu. + +without caching file descriptors +--------------------------------- + +System Configuration +type=Dedicated mode=Capped smt=8 lcpu=4 mem=8302464 kB cpus=0 ent=4.00 + +---Actual--- -Normalized- +%busy %idle Frequency %busy %idle +------ ------ ------------- ------ ------ + 0.04 99.95 3.16GHz[100%] 0.04 99.95 1.1003219 + 0.15 99.85 3.16GHz[100%] 0.15 99.85 1.1003222 + 0.04 99.96 3.16GHz[100%] 0.04 99.96 1.1003179 + 0.03 99.97 3.16GHz[100%] 0.03 99.97 1.1003183 + 0.03 99.97 3.16GHz[100%] 0.03 99.97 1.1003166 + +with caching file descriptors +------------------------------ + +System Configuration +type=Dedicated mode=Capped smt=8 lcpu=4 mem=8302464 kB cpus=0 ent=4.00 + +---Actual--- -Normalized- +%busy %idle Frequency %busy %idle +------ ------ ------------- ------ ------ + 0.03 99.96 3.16GHz[100%] 0.03 99.97 1.1001793 + 0.03 99.97 3.16GHz[100%] 0.03 99.97 1.1001775 + 0.03 99.97 3.16GHz[100%] 0.03 99.97 1.1001775 + 0.02 99.98 3.16GHz[100%] 0.02 99.98 1.1001766 + 0.02 99.98 3.16GHz[100%] 0.02 99.98 1.1001762 + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ + src/lparstat.h | 12 +++++++ + 2 files changed, 100 insertions(+) + +diff --git a/src/lparstat.c b/src/lparstat.c +index 24c48ad..f5c0ce5 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -27,6 +27,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include "lparstat.h" +@@ -43,6 +45,8 @@ static int threads_per_cpu; + static int cpus_in_system; + static int threads_in_system; + ++static cpu_sysfs_fd *cpu_sysfs_fds; ++ + struct sysentry *get_sysentry(char *name) + { + struct sysentry *se = &system_data[0]; +@@ -93,6 +97,80 @@ static int get_one_smt_state(int core) + return __get_one_smt_state(core, threads_per_cpu); + } + ++static int assign_read_fd(const char *path) ++{ ++ int rc = 0; ++ ++ rc = access(path, R_OK); ++ if (rc) ++ return -1; ++ ++ rc = open(path, O_RDONLY); ++ return rc; ++} ++ ++static void close_cpu_sysfs_fds(int threads_in_system) ++{ ++ int i; ++ ++ for (i = 0; i < threads_in_system && cpu_sysfs_fds[i].spurr; i++) { ++ close(cpu_sysfs_fds[i].spurr); ++ close(cpu_sysfs_fds[i].idle_purr); ++ close(cpu_sysfs_fds[i].idle_spurr); ++ } ++ ++ free(cpu_sysfs_fds); ++} ++ ++static int assign_cpu_sysfs_fds(int threads_in_system) ++{ ++ int cpu_idx, i; ++ char sysfs_file_path[SYSFS_PATH_MAX]; ++ ++ cpu_sysfs_fds = ++ (cpu_sysfs_fd*)calloc(sizeof(cpu_sysfs_fd), threads_in_system); ++ if (!cpu_sysfs_fds) { ++ fprintf(stderr, "Failed to allocate memory for sysfs file descriptors\n"); ++ return -1; ++ } ++ ++ for (cpu_idx = 0, i = 0; i < threads_in_system; i++) { ++ if (!cpu_online(i)) ++ continue; ++ ++ cpu_sysfs_fds[cpu_idx].cpu = i; ++ ++ snprintf(sysfs_file_path, SYSFS_PATH_MAX, SYSFS_PERCPU_SPURR, i); ++ cpu_sysfs_fds[cpu_idx].spurr = assign_read_fd(sysfs_file_path); ++ if (cpu_sysfs_fds[cpu_idx].spurr == -1) ++ goto error; ++ ++ snprintf(sysfs_file_path, SYSFS_PATH_MAX, SYSFS_PERCPU_IDLE_PURR, i); ++ cpu_sysfs_fds[cpu_idx].idle_purr = assign_read_fd(sysfs_file_path); ++ if (cpu_sysfs_fds[cpu_idx].idle_purr == -1) ++ goto error; ++ ++ snprintf(sysfs_file_path, SYSFS_PATH_MAX, SYSFS_PERCPU_IDLE_SPURR, i); ++ cpu_sysfs_fds[cpu_idx].idle_spurr = assign_read_fd(sysfs_file_path); ++ if (cpu_sysfs_fds[cpu_idx].idle_spurr == -1) ++ goto error; ++ ++ cpu_idx++; ++ } ++ ++ return 0; ++error: ++ fprintf(stderr, "Failed to open %s\n", sysfs_file_path); ++ close_cpu_sysfs_fds(threads_in_system); ++ return -1; ++} ++ ++static void sig_int_handler(int signal) ++{ ++ close_cpu_sysfs_fds(threads_in_system); ++ exit(1); ++} ++ + void get_time() + { + struct timeval t; +@@ -659,6 +737,15 @@ void init_sysinfo(void) + rc = get_nominal_frequency(); + if (rc) + exit(rc); ++ ++ if (signal(SIGINT, sig_int_handler) == SIG_ERR) { ++ fprintf(stderr, "Failed to add signal handler\n"); ++ exit(-1); ++ } ++ ++ rc = assign_cpu_sysfs_fds(threads_in_system); ++ if (rc) ++ exit(rc); + } + + void init_sysdata(void) +@@ -841,5 +928,6 @@ int main(int argc, char *argv[]) + else + print_default_output(interval, count); + ++ close_cpu_sysfs_fds(threads_in_system); + return 0; + } +diff --git a/src/lparstat.h b/src/lparstat.h +index c1bac28..617737b 100644 +--- a/src/lparstat.h ++++ b/src/lparstat.h +@@ -25,6 +25,10 @@ + #define SYSDATA_NAME_SZ 64 + #define SYSDATA_DESCR_SZ 128 + ++#define SYSFS_PERCPU_SPURR "/sys/devices/system/cpu/cpu%d/spurr" ++#define SYSFS_PERCPU_IDLE_PURR "/sys/devices/system/cpu/cpu%d/idle_purr" ++#define SYSFS_PERCPU_IDLE_SPURR "/sys/devices/system/cpu/cpu%d/idle_spurr" ++ + struct sysentry { + char value[SYSDATA_VALUE_SZ]; /* value from file */ + char old_value[SYSDATA_VALUE_SZ]; /* previous value from file */ +@@ -33,6 +37,14 @@ struct sysentry { + void (*get)(struct sysentry *, char *); + }; + ++struct cpu_sysfs_file_desc { ++ int cpu; /* cpu number */ ++ int spurr; /* per-cpu /sys/devices/system/cpu/cpuX/spurr file descriptor */ ++ int idle_purr; /* per-cpu /sys/devices/system/cpu/cpuX/idle_purr file descriptor */ ++ int idle_spurr; /* per-cpu /sys/devices/system/cpu/cpuX/idle_spurr file descriptor */ ++}; ++typedef struct cpu_sysfs_file_desc cpu_sysfs_fd; ++ + extern void get_smt_state(struct sysentry *, char *); + extern void get_capped_mode(struct sysentry *, char *); + extern void get_memory_mode(struct sysentry *, char *); +-- +2.25.3 + diff --git a/0006-lparstat-Read-SPURR-Idle_-PURR-SPURR-values.patch b/0006-lparstat-Read-SPURR-Idle_-PURR-SPURR-values.patch new file mode 100644 index 0000000..7bee99f --- /dev/null +++ b/0006-lparstat-Read-SPURR-Idle_-PURR-SPURR-values.patch @@ -0,0 +1,134 @@ +From 6bc0d4f1e181c2254b7e35f9b3f77128f663a525 Mon Sep 17 00:00:00 2001 +Message-Id: <6bc0d4f1e181c2254b7e35f9b3f77128f663a525.1587532692.git.kamalesh@linux.vnet.ibm.com> +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 08:00:49 -0500 +Subject: [PATCH V4 06/14] lparstat: Read SPURR, Idle_{PURR, SPURR} values +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +Parse per-cpu +/sys/devices/system/cpu/cpu/{spurr, idle_purr, idle_spurr} files to +accumulate system wide SPURR, Idle PURR, Idle SPURR values like +PURR value captured in /proc/powerpc/lparcfg. Calculating scaled +utilization metrics, need them. + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ + src/lparstat.h | 11 +++++++++ + 2 files changed, 71 insertions(+) + +diff --git a/src/lparstat.c b/src/lparstat.c +index f5c0ce5..7c55a8c 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -165,6 +165,61 @@ error: + return -1; + } + ++int parse_sysfs_values(void) ++{ ++ unsigned long long spurr, idle_spurr, idle_purr, value; ++ char line[SYSDATA_VALUE_SZ]; ++ struct sysentry *se; ++ int i, rc; ++ ++ spurr = idle_spurr = idle_purr = 0UL; ++ ++ for (i = 0; cpu_sysfs_fds[i].spurr > 0; i++) { ++ rc = pread(cpu_sysfs_fds[i].spurr, (void *)line, sizeof(line), 0); ++ if (rc == -1) { ++ fprintf(stderr, "Failed to /sys/devices/system/cpu/cpu%d/spurr\n", ++ cpu_sysfs_fds[i].cpu); ++ goto error; ++ } ++ ++ value = strtoll(line, NULL, 16); ++ spurr += value; ++ ++ rc = pread(cpu_sysfs_fds[i].idle_purr, (void *)line, sizeof(line), 0); ++ if (rc == -1) { ++ fprintf(stderr, "Failed to /sys/devices/system/cpu/cpu%d/idle_purr\n", ++ cpu_sysfs_fds[i].cpu); ++ goto error; ++ } ++ ++ value = strtoll(line, NULL, 16); ++ idle_purr += value; ++ ++ rc = pread(cpu_sysfs_fds[i].idle_spurr, (void *)line, sizeof(line), 0); ++ if (rc == -1) { ++ fprintf(stderr, "Failed to /sys/devices/system/cpu/cpu%d/idle_spurr\n", ++ cpu_sysfs_fds[i].cpu); ++ goto error; ++ } ++ ++ value = strtoll(line, NULL, 16); ++ idle_spurr += value; ++ } ++ ++ se = get_sysentry("spurr"); ++ sprintf(se->value, "%llu", spurr); ++ se = get_sysentry("idle_purr"); ++ sprintf(se->value, "%llu", idle_purr); ++ se = get_sysentry("idle_spurr"); ++ sprintf(se->value, "%llu", idle_spurr); ++ ++ return 0; ++ ++error: ++ close_cpu_sysfs_fds(threads_in_system); ++ return -1; ++} ++ + static void sig_int_handler(int signal) + { + close_cpu_sysfs_fds(threads_in_system); +@@ -750,11 +805,16 @@ void init_sysinfo(void) + + void init_sysdata(void) + { ++ int rc = 0; ++ + get_time(); + parse_lparcfg(); + parse_proc_stat(); + parse_proc_ints(); + get_time_base(); ++ rc = parse_sysfs_values(); ++ if (rc) ++ exit(rc); + } + + void update_sysdata(void) +diff --git a/src/lparstat.h b/src/lparstat.h +index 617737b..eec59d6 100644 +--- a/src/lparstat.h ++++ b/src/lparstat.h +@@ -266,6 +266,17 @@ struct sysentry system_data[] = { + .descr = "System Uptime", + .get = &get_sys_uptime}, + ++ /* /sys/devices/system/cpu/cpu/ */ ++ /* Sum of per CPU SPURR registers */ ++ {.name = "spurr", ++ .descr = "Scaled Processor Utilization Resource Register"}, ++ /* Sum of per CPU Idle PURR Values */ ++ {.name = "idle_purr", ++ .descr = "Processor Utilization Resource Idle Values"}, ++ /* Sum of per CPU Idle SPURR Values */ ++ {.name = "idle_spurr", ++ .descr = "Scaled Processor Utilization Resource Idle Values"}, ++ + {.name[0] = '\0'}, + }; + +-- +2.25.3 + diff --git a/0007-lparstat-Add-helper-function-to-calculate-delta.patch b/0007-lparstat-Add-helper-function-to-calculate-delta.patch new file mode 100644 index 0000000..e6c57de --- /dev/null +++ b/0007-lparstat-Add-helper-function-to-calculate-delta.patch @@ -0,0 +1,51 @@ +From b79f34df37d605954beaa381e6309d50386434b2 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 08:02:51 -0500 +Subject: [PATCH V4 07/14] lparstat: Add helper function to calculate delta +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +Add a helper function for one of the most often used arithmetics of +calculating delta of a sysentry. + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/src/lparstat.c b/src/lparstat.c +index 7c55a8c..152e5fa 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -226,6 +226,21 @@ static void sig_int_handler(int signal) + exit(1); + } + ++long long get_delta_value(char *se_name) ++{ ++ long long value, old_value; ++ struct sysentry *se; ++ ++ se = get_sysentry(se_name); ++ if (se->value[0] == '\0') ++ return 0LL; ++ ++ value = strtoll(se->value, NULL, 0); ++ old_value = strtoll(se->old_value, NULL, 0); ++ ++ return (value - old_value); ++} ++ + void get_time() + { + struct timeval t; +-- +2.25.3 + diff --git a/0008-lparstat-Derive-effective-frequency.patch b/0008-lparstat-Derive-effective-frequency.patch new file mode 100644 index 0000000..ac9bbd8 --- /dev/null +++ b/0008-lparstat-Derive-effective-frequency.patch @@ -0,0 +1,89 @@ +From 9f4055e95380a19a824f13cd3e629d2e73be075f Mon Sep 17 00:00:00 2001 +Message-Id: <9f4055e95380a19a824f13cd3e629d2e73be075f.1587532692.git.kamalesh@linux.vnet.ibm.com> +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 08:05:45 -0500 +Subject: [PATCH V4 08/14] lparstat: Derive effective frequency +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +Effective/current operating frequency is derived by following: + +Effective frequency = (delta SPURR / delta PURR) * nominal frequency + +it required to calculate the scaled variants using SPURR, whereas +the currently computed values based on the PURR. +performed. + +Effective frequency is derived from PURR/SPURR values, hence call +get_frequency() after function updating sysfs values. + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 23 +++++++++++++++++++++++ + src/lparstat.h | 3 +++ + 2 files changed, 26 insertions(+) + +diff --git a/src/lparstat.c b/src/lparstat.c +index 152e5fa..0f9dffc 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -352,6 +352,28 @@ int get_nominal_frequency(void) + return 0; + } + ++void get_effective_frequency() ++{ ++ struct sysentry *se; ++ double delta_purr, delta_spurr; ++ double nominal_freq, effective_freq; ++ ++ se = get_sysentry("nominal_freq"); ++ nominal_freq = strtol(se->value, NULL, 10); ++ ++ /* ++ * Calculate the Effective Frequency (EF) ++ * EF = (delta SPURR / delta PURR) * nominal frequency ++ */ ++ delta_purr = get_delta_value("purr"); ++ delta_spurr = get_delta_value("spurr"); ++ ++ effective_freq = (delta_spurr / delta_purr) * nominal_freq; ++ ++ se = get_sysentry("effective_freq"); ++ sprintf(se->value, "%f", effective_freq); ++} ++ + void get_cpu_physc(struct sysentry *unused_se, char *buf) + { + struct sysentry *se; +@@ -830,6 +852,7 @@ void init_sysdata(void) + rc = parse_sysfs_values(); + if (rc) + exit(rc); ++ get_effective_frequency(); + } + + void update_sysdata(void) +diff --git a/src/lparstat.h b/src/lparstat.h +index eec59d6..5e91d67 100644 +--- a/src/lparstat.h ++++ b/src/lparstat.h +@@ -256,6 +256,9 @@ struct sysentry system_data[] = { + .descr = "Timebase"}, + {.name = "nominal_freq", + .descr = "Nominal Frequency"}, ++ /* derived from nominal freq */ ++ {.name = "effective_freq", ++ .descr = "Effective Frequency"}, + + /* /proc/interrupts */ + {.name = "phint", +-- +2.25.3 + diff --git a/0009-lparstat-Add-helper-to-calculate-scaled-timebase.patch b/0009-lparstat-Add-helper-to-calculate-scaled-timebase.patch new file mode 100644 index 0000000..e4fbe5e --- /dev/null +++ b/0009-lparstat-Add-helper-to-calculate-scaled-timebase.patch @@ -0,0 +1,57 @@ +From 39cb3fba241a3fa77be3b3065e638aa4d807dae7 Mon Sep 17 00:00:00 2001 +Message-Id: <39cb3fba241a3fa77be3b3065e638aa4d807dae7.1587532692.git.kamalesh@linux.vnet.ibm.com> +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 08:06:40 -0500 +Subject: [PATCH V4 09/14] lparstat: Add helper to calculate scaled timebase +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +Timebase is used to derive system wide CPU utilization, scale it to +the number of online cores too like the PURR/SPURR registers values +accumulated across all online CPU cores. This helper also scales the +timebase register value to the interval passed. + +Timebase = (Timebase * Elapsed Time) * online cores + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/src/lparstat.c b/src/lparstat.c +index 0f9dffc..7628afa 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -294,6 +294,23 @@ int get_time_base() + return 0; + } + ++double get_scaled_tb(void) ++{ ++ double elapsed, timebase; ++ struct sysentry *se; ++ int online_cores; ++ ++ se = get_sysentry("online_cores"); ++ online_cores = atoi(se->value); ++ ++ elapsed = elapsed_time() / 1000000.0; ++ ++ se = get_sysentry("timebase"); ++ timebase = atoi(se->value); ++ ++ return (timebase * elapsed) * online_cores; ++} ++ + void get_sys_uptime(struct sysentry *unused_se, char *uptime) + { + FILE *f; +-- +2.25.3 + diff --git a/0010-lparstat-Add-helpers-to-derive-PURR-SPURR-values.patch b/0010-lparstat-Add-helpers-to-derive-PURR-SPURR-values.patch new file mode 100644 index 0000000..651d00f --- /dev/null +++ b/0010-lparstat-Add-helpers-to-derive-PURR-SPURR-values.patch @@ -0,0 +1,164 @@ +From ec05852c7d2e10c924e9521c32fe002e0f8cde71 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 08:08:12 -0500 +Subject: [PATCH V4 10/14] lparstat: Add helpers to derive PURR/SPURR values +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +For every interval specified by the user, the PURR/SPURR delta values +are needed to be calculated. Add helpers to derive them. + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++ + src/lparstat.h | 22 +++++++++++++ + 2 files changed, 109 insertions(+) + +diff --git a/src/lparstat.c b/src/lparstat.c +index 7628afa..84a6544 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -471,6 +471,93 @@ void get_cpu_app(struct sysentry *unused_se, char *buf) + sprintf(buf, "%.2f", app); + } + ++static double round_off_freq(void) ++{ ++ double effective_freq, nominal_freq, freq; ++ struct sysentry *se; ++ ++ se = get_sysentry("effective_freq"); ++ effective_freq = strtod(se->value, NULL); ++ ++ se = get_sysentry("nominal_freq"); ++ nominal_freq = strtod(se->value, NULL); ++ ++ freq = ((int)((effective_freq/nominal_freq * 100)+ 0.44) - ++ (effective_freq/nominal_freq * 100)) / ++ (effective_freq/nominal_freq * 100) * 100; ++ ++ return freq; ++} ++ ++void get_cpu_util_purr(struct sysentry *unused_se, char *buf) ++{ ++ double delta_tb, delta_purr, delta_idle_purr; ++ double physc; ++ ++ delta_tb = get_scaled_tb(); ++ delta_purr = get_delta_value("purr"); ++ delta_idle_purr = get_delta_value("idle_purr"); ++ ++ physc = (delta_purr - delta_idle_purr) / delta_tb; ++ physc *= 100.00; ++ ++ sprintf(buf, "%.2f", physc); ++} ++ ++void get_cpu_idle_purr(struct sysentry *unused_se, char *buf) ++{ ++ double delta_tb, delta_purr, delta_idle_purr; ++ double physc, idle; ++ ++ delta_tb = get_scaled_tb(); ++ delta_purr = get_delta_value("purr"); ++ delta_idle_purr = get_delta_value("idle_purr"); ++ ++ physc = (delta_purr - delta_idle_purr) / delta_tb; ++ idle = (delta_purr / delta_tb) - physc; ++ idle *= 100.00; ++ ++ sprintf(buf, "%.2f", idle); ++} ++ ++void get_cpu_util_spurr(struct sysentry *unused_se, char *buf) ++{ ++ double delta_tb, delta_spurr, delta_idle_spurr; ++ double physc, rfreq; ++ ++ delta_tb = get_scaled_tb(); ++ delta_spurr = get_delta_value("spurr"); ++ delta_idle_spurr = get_delta_value("idle_spurr"); ++ ++ physc = (delta_spurr - delta_idle_spurr) / delta_tb; ++ physc *= 100.00; ++ ++ rfreq = round_off_freq(); ++ physc += ((physc * rfreq) / 100); ++ ++ sprintf(buf, "%.2f", physc); ++} ++ ++void get_cpu_idle_spurr(struct sysentry *unused_se, char *buf) ++{ ++ double delta_tb, delta_spurr, delta_idle_spurr; ++ double physc, idle; ++ double rfreq; ++ ++ delta_tb = get_scaled_tb(); ++ delta_spurr = get_delta_value("spurr"); ++ delta_idle_spurr = get_delta_value("idle_spurr"); ++ ++ physc = (delta_spurr - delta_idle_spurr) / delta_tb; ++ idle = (delta_spurr / delta_tb) - physc; ++ idle *= 100.00; ++ ++ rfreq = round_off_freq(); ++ idle += ((idle * rfreq) / 100); ++ ++ sprintf(buf, "%.2f", idle); ++} ++ + int parse_lparcfg() + { + FILE *f; +diff --git a/src/lparstat.h b/src/lparstat.h +index 5e91d67..9b7117f 100644 +--- a/src/lparstat.h ++++ b/src/lparstat.h +@@ -60,6 +60,10 @@ extern void get_cpu_physc(struct sysentry *, char *); + extern void get_per_entc(struct sysentry *, char *); + extern void get_cpu_app(struct sysentry *, char *); + extern void get_sys_uptime(struct sysentry *, char *); ++extern void get_cpu_util_purr(struct sysentry *unused_se, char *buf); ++extern void get_cpu_idle_purr(struct sysentry *unused_se, char *buf); ++extern void get_cpu_util_spurr(struct sysentry *unused_se, char *buf); ++extern void get_cpu_idle_spurr(struct sysentry *uunused_se, char *buf); + + struct sysentry system_data[] = { + /* System Names */ +@@ -280,6 +284,24 @@ struct sysentry system_data[] = { + {.name = "idle_spurr", + .descr = "Scaled Processor Utilization Resource Idle Values"}, + ++ /* Dervied from above sysfs values */ ++ /* PURR Utilization */ ++ {.name = "purr_cpu_util", ++ .descr = "Physical CPU consumed - PURR", ++ .get = &get_cpu_util_purr}, ++ /* PURR Idle time */ ++ {.name = "purr_cpu_idle", ++ .descr = "Idle CPU value - PURR", ++ .get = &get_cpu_idle_purr}, ++ /* SPURR Utilization */ ++ {.name = "spurr_cpu_util", ++ .descr = "Physical CPU consumed - SPURR", ++ .get = &get_cpu_util_spurr}, ++ /* SPURR Idle time */ ++ {.name = "spurr_cpu_idle", ++ .descr = "Idle CPU value - SPURR", ++ .get = &get_cpu_idle_spurr}, ++ + {.name[0] = '\0'}, + }; + +-- +2.25.3 + diff --git a/0011-lparstat-Move-displaying-system-configuration-detail.patch b/0011-lparstat-Move-displaying-system-configuration-detail.patch new file mode 100644 index 0000000..0c20ba2 --- /dev/null +++ b/0011-lparstat-Move-displaying-system-configuration-detail.patch @@ -0,0 +1,66 @@ +From 1b176657dea3da2fc8b2c00bf6f0d8b25c92ee74 Mon Sep 17 00:00:00 2001 +Message-Id: <1b176657dea3da2fc8b2c00bf6f0d8b25c92ee74.1587532692.git.kamalesh@linux.vnet.ibm.com> +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 08:09:12 -0500 +Subject: [PATCH V4 11/14] lparstat: Move displaying system configuration + details to new func +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +System configuration details is required while displaying the +scaled metrics too. Move it to a new function, to be called by both +default, scaled metrics too. + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/src/lparstat.c b/src/lparstat.c +index 84a6544..3768b79 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -989,16 +989,13 @@ int print_iflag_data() + return 0; + } + +-void print_default_output(int interval, int count) ++void print_system_configuration(void) + { +- char *fmt = "%5s %5s %5s %8s %8s %5s %5s %5s %5s %5s\n"; + char *descr; + char buf[128]; + int offset, smt, active_proc; + char type[32]; + char value[32]; +- char user[32], sys[32], wait[32], idle[32], physc[32], entc[32]; +- char lbusy[32], app[32], vcsw[32], phint[32]; + + memset(buf, 0, 128); + get_sysdata("shared_processor_mode", &descr, value); +@@ -1031,6 +1028,16 @@ void print_default_output(int interval, int count) + offset += sprintf(buf + offset, "ent=%s ", value); + + fprintf(stdout, "\nSystem Configuration\n%s\n\n", buf); ++} ++ ++void print_default_output(int interval, int count) ++{ ++ char *fmt = "%5s %5s %5s %8s %8s %5s %5s %5s %5s %5s\n"; ++ char *descr; ++ char user[32], sys[32], wait[32], idle[32], physc[32], entc[32]; ++ char lbusy[32], app[32], vcsw[32], phint[32]; ++ ++ print_system_configuration(); + + fprintf(stdout, fmt, "\%user", "\%sys", "\%wait", "\%idle", "physc", + "\%entc", "lbusy", "app", "vcsw", "phint"); +-- +2.25.3 + diff --git a/0012-lparstat-Add-switch-to-print-Scaled-metrics.patch b/0012-lparstat-Add-switch-to-print-Scaled-metrics.patch new file mode 100644 index 0000000..5a8baf0 --- /dev/null +++ b/0012-lparstat-Add-switch-to-print-Scaled-metrics.patch @@ -0,0 +1,161 @@ +From 9ffdec9aca02761034cd5e87d8f6da0b54a4f770 Mon Sep 17 00:00:00 2001 +Message-Id: <9ffdec9aca02761034cd5e87d8f6da0b54a4f770.1587532692.git.kamalesh@linux.vnet.ibm.com> +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 08:15:25 -0500 +Subject: [PATCH V4 12/14] lparstat: Add switch to print Scaled metrics +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +Add '-E' command line switch to print scaled version of meterics, this +switch prints CPU utilization/Idle based on Actual (PURR) and Scaled +(SPURR) values along with the current effective frequency of the system. + +output: + +~ # lparstat -E 1 3 + +System Configuration +type=Dedicated mode=Capped smt=8 lcpu=2 mem=4324928 kB cpus=0 ent=2.00 + +---Actual--- -Normalized- +%busy %idle Frequency %busy %idle +------ ------ ------------- ------ ------ + 0.10 99.90 2.13GHz[ 70%] 0.10 69.91 + 0.07 99.92 2.10GHz[ 69%] 0.05 68.95 + 0.08 99.92 2.10GHz[ 69%] 0.05 68.95 + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 57 insertions(+), 4 deletions(-) + +diff --git a/src/lparstat.c b/src/lparstat.c +index 3768b79..5390b9f 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -40,6 +40,7 @@ + #define SE_NOT_VALID "-" + + static bool o_legacy = false; ++static bool o_scaled = false; + + static int threads_per_cpu; + static int cpus_in_system; +@@ -928,6 +929,10 @@ void init_sysinfo(void) + exit(rc); + } + ++ /* refer to init_sysdata for explanation */ ++ if (!o_scaled) ++ return; ++ + get_online_cores(); + + rc = get_nominal_frequency(); +@@ -953,6 +958,12 @@ void init_sysdata(void) + parse_proc_stat(); + parse_proc_ints(); + get_time_base(); ++ ++ /* Skip reading spurr, purr, idle_{purr,spurr} and calculating ++ * effective frequency for default option */ ++ if (!o_scaled) ++ return; ++ + rc = parse_sysfs_values(); + if (rc) + exit(rc); +@@ -1067,6 +1078,42 @@ void print_default_output(int interval, int count) + } while (--count > 0); + } + ++void print_scaled_output(int interval, int count) ++{ ++ char purr[32], purr_idle[32], spurr[32], spurr_idle[32]; ++ char nominal_f[32], effective_f[32]; ++ double nominal_freq, effective_freq; ++ char *descr; ++ ++ print_system_configuration(); ++ ++ fprintf(stdout, "---Actual--- -Normalized-\n"); ++ fprintf(stdout, "%%busy %%idle Frequency %%busy %%idle\n"); ++ fprintf(stdout, "------ ------ ------------- ------ ------\n"); ++ do { ++ if (interval) { ++ sleep(interval); ++ update_sysdata(); ++ } ++ ++ get_sysdata("purr_cpu_util", &descr, purr); ++ get_sysdata("purr_cpu_idle", &descr, purr_idle); ++ get_sysdata("spurr_cpu_util", &descr, spurr); ++ get_sysdata("spurr_cpu_idle", &descr, spurr_idle); ++ get_sysdata("nominal_freq", &descr, nominal_f); ++ get_sysdata("effective_freq", &descr, effective_f); ++ nominal_freq = strtod(nominal_f, NULL); ++ effective_freq = strtod(effective_f, NULL); ++ ++ fprintf(stdout, "%6s %6s %5.2fGHz[%3d%%] %6s %6s\n", ++ purr, purr_idle, ++ effective_freq/1000, ++ (int)((effective_freq/nominal_freq * 100)+ 0.44 ), ++ spurr, spurr_idle ); ++ fflush(stdout); ++ } while (--count > 0); ++} ++ + static void usage(void) + { + printf("Usage: lparstat [ options ]\n\tlparstat [ count ]\n\n" +@@ -1074,6 +1121,7 @@ static void usage(void) + "\t-h, --help Show this message and exit.\n" + "\t-V, --version \tDisplay lparstat version information.\n" + "\t-i Lists details on the LPAR configuration.\n" ++ "\t-E Print SPURR metrics.\n" + "\t-l, --legacy Print the report in legacy format.\n" + "interval The interval parameter specifies the amount of time between each report.\n" + "count The count parameter specifies how many reports will be displayed.\n"); +@@ -1098,7 +1146,7 @@ int main(int argc, char *argv[]) + exit(1); + } + +- while ((c = getopt_long(argc, argv, "iVhl", ++ while ((c = getopt_long(argc, argv, "iEVhl", + long_opts, &opt_index)) != -1) { + switch(c) { + case 'i': +@@ -1107,6 +1155,9 @@ int main(int argc, char *argv[]) + case 'l': + o_legacy = true; + break; ++ case 'E': ++ o_scaled = true; ++ break; + case 'V': + printf("lparstat - %s\n", VERSION); + return 0; +@@ -1134,9 +1185,11 @@ int main(int argc, char *argv[]) + + if (i_option) + print_iflag_data(); +- else ++ else if (o_scaled) { ++ print_scaled_output(interval, count); ++ close_cpu_sysfs_fds(threads_in_system); ++ } else { + print_default_output(interval, count); +- +- close_cpu_sysfs_fds(threads_in_system); ++ } + return 0; + } +-- +2.25.3 + diff --git a/0013-lparstat-Add-support-for-cpu-hotplug.patch b/0013-lparstat-Add-support-for-cpu-hotplug.patch new file mode 100644 index 0000000..d8b3ebf --- /dev/null +++ b/0013-lparstat-Add-support-for-cpu-hotplug.patch @@ -0,0 +1,177 @@ +From 179d461b79387bd3877cd239da933a8dfceae05c Mon Sep 17 00:00:00 2001 +Message-Id: <179d461b79387bd3877cd239da933a8dfceae05c.1587532692.git.kamalesh@linux.vnet.ibm.com> +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 08:23:24 -0500 +Subject: [PATCH V4 13/14] lparstat: Add support for cpu-hotplug +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +For optimizing the read of sysfs file, the file descriptors are +assigned at the beginning of the run but they do not change dynamically +in event of a cpu hotplug, resulting under-estimated load average in +case of new cpus onlined or error in case of cpu removed. This can be +solved by checking for the online cpus every interval and re-assign +the file descriptors again with new set of cpu on hotplug event. + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 78 +++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 71 insertions(+), 7 deletions(-) + +diff --git a/src/lparstat.c b/src/lparstat.c +index 5390b9f..51caa3d 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -21,6 +21,7 @@ + * @author Nathan Fontenot + */ + ++#define _GNU_SOURCE + #include + #include + #include +@@ -28,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -47,6 +49,7 @@ static int cpus_in_system; + static int threads_in_system; + + static cpu_sysfs_fd *cpu_sysfs_fds; ++static cpu_set_t *online_cpus; + + struct sysentry *get_sysentry(char *name) + { +@@ -180,7 +183,7 @@ int parse_sysfs_values(void) + if (rc == -1) { + fprintf(stderr, "Failed to /sys/devices/system/cpu/cpu%d/spurr\n", + cpu_sysfs_fds[i].cpu); +- goto error; ++ goto check_cpu_hotplug; + } + + value = strtoll(line, NULL, 16); +@@ -190,7 +193,7 @@ int parse_sysfs_values(void) + if (rc == -1) { + fprintf(stderr, "Failed to /sys/devices/system/cpu/cpu%d/idle_purr\n", + cpu_sysfs_fds[i].cpu); +- goto error; ++ goto check_cpu_hotplug; + } + + value = strtoll(line, NULL, 16); +@@ -200,7 +203,7 @@ int parse_sysfs_values(void) + if (rc == -1) { + fprintf(stderr, "Failed to /sys/devices/system/cpu/cpu%d/idle_spurr\n", + cpu_sysfs_fds[i].cpu); +- goto error; ++ goto check_cpu_hotplug; + } + + value = strtoll(line, NULL, 16); +@@ -216,9 +219,11 @@ int parse_sysfs_values(void) + + return 0; + +-error: +- close_cpu_sysfs_fds(threads_in_system); +- return -1; ++check_cpu_hotplug: ++ if(!cpu_online(cpu_sysfs_fds[i].cpu)) ++ return 1; ++ ++ return rc; + } + + static void sig_int_handler(int signal) +@@ -917,6 +922,52 @@ void get_cpu_stat(struct sysentry *se, char *buf) + sprintf(buf, "%.2f", percent); + } + ++int has_cpu_topology_changed(void) ++{ ++ int i, changed = 1; ++ cpu_set_t *tmp_cpuset; ++ size_t online_cpus_size = CPU_ALLOC_SIZE(threads_in_system); ++ ++ if (!online_cpus) { ++ online_cpus = CPU_ALLOC(threads_in_system); ++ if (!online_cpus) { ++ fprintf(stderr, "Failed to allocate memory for cpu_set\n"); ++ return -1; ++ } ++ ++ CPU_ZERO_S(online_cpus_size, online_cpus); ++ ++ for (i = 0; i < threads_in_system; i++) { ++ if (!cpu_online(i)) ++ continue; ++ CPU_SET_S(i, online_cpus_size, online_cpus); ++ } ++ ++ return changed; ++ } ++ ++ tmp_cpuset = CPU_ALLOC(threads_in_system); ++ if (!tmp_cpuset) { ++ fprintf(stderr, "Failed to allocate memory for cpu_set\n"); ++ return -1; ++ } ++ ++ CPU_ZERO_S(online_cpus_size, tmp_cpuset); ++ ++ for (i = 0; i < threads_in_system; i++) { ++ if (!cpu_online(i)) ++ continue; ++ CPU_SET_S(i, online_cpus_size, tmp_cpuset); ++ } ++ ++ changed = CPU_EQUAL_S(online_cpus_size, online_cpus, tmp_cpuset); ++ ++ CPU_FREE(online_cpus); ++ online_cpus = tmp_cpuset; ++ ++ return changed; ++} ++ + void init_sysinfo(void) + { + int rc = 0; +@@ -964,10 +1015,23 @@ void init_sysdata(void) + if (!o_scaled) + return; + ++ rc = has_cpu_topology_changed(); ++ if (!rc) ++ goto cpu_hotplug_restart; ++ + rc = parse_sysfs_values(); +- if (rc) ++ if (rc == -1) + exit(rc); ++ else if (rc) ++ goto cpu_hotplug_restart; ++ + get_effective_frequency(); ++ ++ return; ++ ++cpu_hotplug_restart: ++ close_cpu_sysfs_fds(threads_in_system); ++ init_sysinfo(); + } + + void update_sysdata(void) +-- +2.25.3 + diff --git a/0014-lparstat-Use-get_delta_value-helper.patch b/0014-lparstat-Use-get_delta_value-helper.patch new file mode 100644 index 0000000..a3e0982 --- /dev/null +++ b/0014-lparstat-Use-get_delta_value-helper.patch @@ -0,0 +1,148 @@ +From 1ee9fc2d08a1a4aa34e17fce2234ba5abec9b4ae Mon Sep 17 00:00:00 2001 +Message-Id: <1ee9fc2d08a1a4aa34e17fce2234ba5abec9b4ae.1587532692.git.kamalesh@linux.vnet.ibm.com> +In-Reply-To: +References: +From: Kamalesh Babulal +Date: Tue, 21 Apr 2020 08:24:43 -0500 +Subject: [PATCH V4 14/14] lparstat: Use get_delta_value() helper +To: powerpc-utils-devel@googlegroups.com +Cc: Tyrel Datwyler , + Nathan Lynch , + Naveen N . Rao , + Gautham R . Shenoy , + Vasant Hegde + +Use get_delta_value(), helper, to calculate the delta of interested +values instead of duplicating it in various functions. This reduces +the amount of duplication and makes code more readable. + +Signed-off-by: Kamalesh Babulal +--- + src/lparstat.c | 61 ++++++++++++++------------------------------------ + 1 file changed, 17 insertions(+), 44 deletions(-) + +diff --git a/src/lparstat.c b/src/lparstat.c +index 51caa3d..29e6365 100644 +--- a/src/lparstat.c ++++ b/src/lparstat.c +@@ -259,18 +259,6 @@ void get_time() + (long long)t.tv_sec * 1000000LL + (long long)t.tv_usec); + } + +-long long elapsed_time() +-{ +- long long newtime, oldtime = 0; +- struct sysentry *se; +- +- se = get_sysentry("time"); +- newtime = strtoll(se->value, NULL, 0); +- oldtime = strtoll(se->old_value, NULL, 0); +- +- return newtime - oldtime; +-} +- + int get_time_base() + { + FILE *f; +@@ -309,7 +297,8 @@ double get_scaled_tb(void) + se = get_sysentry("online_cores"); + online_cores = atoi(se->value); + +- elapsed = elapsed_time() / 1000000.0; ++ elapsed = get_delta_value("time"); ++ elapsed = elapsed / 1000000.0; + + se = get_sysentry("timebase"); + timebase = atoi(se->value); +@@ -401,27 +390,25 @@ void get_cpu_physc(struct sysentry *unused_se, char *buf) + { + struct sysentry *se; + float elapsed; +- float new_purr, old_purr; ++ float delta_purr; + float timebase, physc; +- float new_tb, old_tb; ++ float delta_tb; + +- se = get_sysentry("purr"); +- new_purr = strtoll(se->value, NULL, 0); +- old_purr = strtoll(se->old_value, NULL, 0); ++ delta_purr = get_delta_value("purr"); + + se = get_sysentry("tbr"); + if (se->value[0] != '\0') { +- new_tb = strtoll(se->value, NULL, 0); +- old_tb = strtoll(se->old_value, NULL, 0); ++ delta_tb = get_delta_value("tbr"); + +- physc = (new_purr - old_purr) / (new_tb - old_tb); ++ physc = delta_purr / delta_tb; + } else { +- elapsed = elapsed_time() / 1000000.0; ++ elapsed = get_delta_value("time"); ++ elapsed = elapsed / 1000000.0; + + se = get_sysentry("timebase"); + timebase = atoi(se->value); + +- physc = (new_purr - old_purr)/timebase/elapsed; ++ physc = delta_purr/timebase/elapsed; + } + + sprintf(buf, "%.2f", physc); +@@ -443,7 +430,7 @@ void get_cpu_app(struct sysentry *unused_se, char *buf) + { + struct sysentry *se; + float timebase, app, elapsed_time; +- long long new_app, old_app, newtime, oldtime; ++ long long new_app, old_app, delta_time; + char *descr, uptime[32]; + + se = get_sysentry("time"); +@@ -457,9 +444,8 @@ void get_cpu_app(struct sysentry *unused_se, char *buf) + } + elapsed_time = atof(uptime); + } else { +- newtime = strtoll(se->value, NULL, 0); +- oldtime = strtoll(se->old_value, NULL, 0); +- elapsed_time = (newtime - oldtime) / 1000000.0; ++ delta_time = get_delta_value("time"); ++ elapsed_time = delta_time / 1000000.0; + } + + se = get_sysentry("timebase"); +@@ -898,27 +884,14 @@ void get_online_cores(void) + free(core_state); + } + +-long long get_cpu_time_diff() +-{ +- long long old_total = 0, new_total = 0; +- struct sysentry *se; +- +- se = get_sysentry("cpu_total"); +- new_total = strtoll(se->value, NULL, 0); +- old_total = strtoll(se->old_value, NULL, 0); +- +- return new_total - old_total; +-} +- + void get_cpu_stat(struct sysentry *se, char *buf) + { + float percent; +- long long total, old_val, new_val; ++ long long total, delta_val; + +- total = get_cpu_time_diff(); +- new_val = atoll(se->value); +- old_val = atoll(se->old_value); +- percent = ((new_val - old_val)/(long double)total) * 100; ++ total = get_delta_value("cpu_total"); ++ delta_val = get_delta_value(se->name); ++ percent = (delta_val/(long double)total) * 100; + sprintf(buf, "%.2f", percent); + } + +-- +2.25.3 + diff --git a/powerpc-utils-1.3.6-bz#1847604.patch b/powerpc-utils-1.3.6-bz#1847604.patch new file mode 100644 index 0000000..cde21d7 --- /dev/null +++ b/powerpc-utils-1.3.6-bz#1847604.patch @@ -0,0 +1,12 @@ +diff -up powerpc-utils-1.3.6/scripts/ofpathname.me powerpc-utils-1.3.6/scripts/ofpathname +--- powerpc-utils-1.3.6/scripts/ofpathname.me 2020-06-24 09:53:03.145041606 +0200 ++++ powerpc-utils-1.3.6/scripts/ofpathname 2020-06-24 09:55:11.040981495 +0200 +@@ -286,7 +286,7 @@ get_usb_storage_no() + # $3 on_exit behavior on error + goto_dir() + { +- local start_dir=$1 ++ local start_dir=$(readlink -f $1) + local fname=$2 + local found=0 + local on_exit=1 diff --git a/powerpc-utils-b0586b5938e9d371e55671422b2f0a5d2cd10c54.patch b/powerpc-utils-b0586b5938e9d371e55671422b2f0a5d2cd10c54.patch new file mode 100644 index 0000000..f82a251 --- /dev/null +++ b/powerpc-utils-b0586b5938e9d371e55671422b2f0a5d2cd10c54.patch @@ -0,0 +1,272 @@ +commit b0586b5938e9d371e55671422b2f0a5d2cd10c54 +Author: Michael Bringmann +Date: Wed Oct 2 16:54:52 2019 -0500 + + powerpc-utils/devtree: Parse 'ibm,drc-info' property + + Parse new DRC Info: Define data structures to support parsing + the new "ibm,drc-info" device tree property. Integrate the new + property information into the existing search mechanisms of the + userspace 'drmgr' driver. + + Signed-off-by: Michael Bringmann + Signed-off-by: Tyrel Datwyler + +diff --git a/src/drmgr/common_ofdt.c b/src/drmgr/common_ofdt.c +index 8c9e224..c110bc0 100644 +--- a/src/drmgr/common_ofdt.c ++++ b/src/drmgr/common_ofdt.c +@@ -41,6 +41,16 @@ struct drc_prop_grp { + struct of_list_prop drc_domains; + }; + ++struct drc_info { ++ char *drc_type; ++ char *drc_name_prefix; ++ int drc_index_start; ++ int drc_name_suffix_start; ++ int n_seq_elems; ++ int seq_inc; ++ int drc_power_domain; ++}; ++ + struct dr_connector *all_drc_lists = NULL; + + /** +@@ -186,6 +196,169 @@ build_connectors_list(struct drc_prop_grp *group, int n_entries, + return 0; + } + ++/** ++ * drc_info_connectors_v1 ++ * ++ * @param full_path ++ * @param ofdt_path ++ * @param list ++ * @returns 0 on success, !0 otherwise ++ */ ++static int drc_info_connectors_v1(char *full_path, char *ofdt_path, ++ struct dr_connector **list) ++{ ++ struct dr_connector *out_list = NULL; ++ struct drc_prop_grp prop_grp; ++ struct of_list_prop *drc_names; ++ int n_drcs; ++ int rc = 0; ++ ++ rc = get_drc_prop_grp(full_path, &prop_grp); ++ if (rc) { ++ say(DEBUG, ++ "Could not find DRC property group in path: %s.\n", ++ full_path); ++ goto done; ++ } ++ ++ drc_names = &prop_grp.drc_names; ++ n_drcs = drc_names->n_entries; ++ ++ out_list = zalloc(n_drcs * sizeof(struct dr_connector)); ++ if (out_list == NULL) ++ goto done; ++ ++ build_connectors_list(&prop_grp, n_drcs, out_list); ++ ++done: ++ if (rc) { ++ free_drc_props(&prop_grp); ++ free(out_list); ++ } else { ++ snprintf(out_list->ofdt_path, DR_PATH_MAX, "%s", ofdt_path); ++ *list = out_list; ++ } ++ ++ return rc; ++} ++ ++/** ++ * drc_info_connectors_v2 ++ * ++ * @param full_path ++ * @param ofdt_path ++ * @param list ++ * @returns 0 on success, !0 otherwise ++ */ ++static int drc_info_connectors_v2(char *full_path, char *ofdt_path, ++ struct dr_connector **list) ++{ ++ struct dr_connector *out_list = NULL; ++ struct drc_info info; ++ char *prop_name = "ibm,drc-info"; ++ char *prop_data, *data_ptr; ++ int i, j, n_entries, size, connector_size, ics, rc; ++ ++ size = get_property_size(full_path, prop_name); ++ prop_data = zalloc(size); ++ if (prop_data == NULL) ++ return -1; ++ rc = get_property(full_path, prop_name, prop_data, size); ++ if (rc) { ++ free(prop_data); ++ return -1; ++ } ++ ++ /* Num of DRC-info sets */ ++ data_ptr = prop_data; ++ n_entries = be32toh(*(uint *)data_ptr); ++ data_ptr += 4; ++ ++ /* Extract drc-info data */ ++ for (j = 0, connector_size = 0; j < n_entries; j++) { ++ info.drc_type = data_ptr; ++ data_ptr += strlen(info.drc_type)+1; ++ info.drc_name_prefix = data_ptr; ++ data_ptr += strlen(info.drc_name_prefix)+1; ++ data_ptr += 4; /* Skip drc-index-start */ ++ data_ptr += 4; /* Skip drc-name-suffix-start */ ++ info.n_seq_elems = be32toh(*(uint *)data_ptr); ++ data_ptr += 4; /* Advance over n-seq-elems */ ++ data_ptr += 4; /* Skip sequential-increment */ ++ data_ptr += 4; /* Skip drc-power-domain */ ++ if (info.n_seq_elems <= 0) ++ continue; ++ connector_size += info.n_seq_elems; ++ } ++ ++ /* Allocate list entry */ ++ out_list = zalloc(connector_size * sizeof(struct dr_connector)); ++ if (out_list == NULL) { ++ rc = -1; ++ goto done; ++ } ++ ++ /* Extract drc-info data */ ++ data_ptr = prop_data; ++ data_ptr += 4; ++ for (j = 0, ics = 0; j < n_entries; j++) { ++ info.drc_type = data_ptr; ++ data_ptr += strlen(info.drc_type)+1; ++ info.drc_name_prefix = data_ptr; ++ data_ptr += strlen(info.drc_name_prefix)+1; ++ ++ info.drc_index_start = be32toh(*(uint *)data_ptr); ++ data_ptr += 4; ++ ++ info.drc_name_suffix_start = be32toh(*(uint *)data_ptr); ++ data_ptr += 4; ++ ++ info.n_seq_elems = be32toh(*(uint *)data_ptr); ++ data_ptr += 4; ++ ++ info.seq_inc = be32toh(*(uint *)data_ptr); ++ data_ptr += 4; ++ ++ info.drc_power_domain = be32toh(*(uint *)data_ptr); ++ data_ptr += 4; ++ ++ /* Build connector list */ ++ if (info.n_seq_elems <= 0) ++ continue; ++ ++ for (i = 0; i < info.n_seq_elems; i++, ics++) { ++ out_list[ics].index = info.drc_index_start+ ++ (i*info.seq_inc); ++ out_list[ics].powerdomain = info.drc_power_domain; ++ ++ sprintf(out_list[ics].name, "%s%d", ++ info.drc_name_prefix, ++ info.drc_name_suffix_start+(i*info.seq_inc)); ++ ++ strncpy(out_list[ics].type, info.drc_type, DRC_STR_MAX); ++ ++ out_list[ics].next = &out_list[ics+1]; ++ } ++ } ++ if (ics > 0) ++ out_list[ics-1].next = NULL; ++ ++done: ++ if (prop_data) ++ free(prop_data); ++ ++ if (rc) { ++ free(out_list); ++ *list = NULL; ++ } else { ++ snprintf(out_list->ofdt_path, DR_PATH_MAX, "%s", ofdt_path); ++ *list = out_list; ++ } ++ ++ return rc; ++} ++ ++ + /** + * of_to_full_path + * +@@ -232,11 +405,12 @@ of_to_full_path(const char *of_path) + struct dr_connector * + get_drc_info(const char *of_path) + { +- struct dr_connector *list = NULL; +- struct of_list_prop *drc_names; +- struct drc_prop_grp prop_grp; ++ struct stat sbuf; ++ char fname[DR_PATH_MAX]; ++ char ofdt_path[DR_PATH_MAX]; + char *full_path = NULL; +- int rc, n_drcs; ++ struct dr_connector *list = NULL; ++ int rc; + + for (list = all_drc_lists; list; list = list->all_next) { + if (! strcmp(list->ofdt_path, of_path)) +@@ -246,33 +420,24 @@ get_drc_info(const char *of_path) + full_path = of_to_full_path(of_path); + if (full_path == NULL) + return NULL; +- +- rc = get_drc_prop_grp(full_path, &prop_grp); +- if (rc) { +- say(DEBUG, "Could not find DRC property group in path: %s.\n", +- full_path); +- goto done; +- } + +- drc_names = &prop_grp.drc_names; +- n_drcs = drc_names->n_entries; +- +- list = zalloc(n_drcs * sizeof(struct dr_connector)); +- if (list == NULL) +- goto done; +- +- /* XXX Unchecked rc */ +- rc = build_connectors_list(&prop_grp, n_drcs, list); +- +- snprintf(list->ofdt_path, DR_PATH_MAX, "%s", of_path); +- +- list->all_next = all_drc_lists; +- all_drc_lists = list; ++ /* ibm,drc-info vs the old implementation */ ++ sprintf(fname, "%s/%s", full_path, "ibm,drc-info"); ++ snprintf(ofdt_path, DR_PATH_MAX, "%s", of_path); ++ rc = stat(fname, &sbuf); ++ if (rc) ++ rc = drc_info_connectors_v1(full_path, ofdt_path, &list); ++ else ++ rc = drc_info_connectors_v2(full_path, ofdt_path, &list); + +-done: +- free_drc_props(&prop_grp); +- if (full_path) +- free(full_path); ++ if (rc == 0) { ++ list->all_next = all_drc_lists; ++ all_drc_lists = list; ++ } else { ++ if (full_path) ++ free(full_path); ++ list = NULL; ++ } + + return list; + } diff --git a/powerpc-utils-ea4db66e941720313af2c6b1afb32a74f3e360f4.patch b/powerpc-utils-ea4db66e941720313af2c6b1afb32a74f3e360f4.patch new file mode 100644 index 0000000..f43e8b2 --- /dev/null +++ b/powerpc-utils-ea4db66e941720313af2c6b1afb32a74f3e360f4.patch @@ -0,0 +1,64 @@ +commit ea4db66e941720313af2c6b1afb32a74f3e360f4 +Author: Michael Bringmann +Date: Tue Sep 10 14:31:42 2019 -0500 + + Safe bootlist update + + This patch is intended to prevent problems with identifying or parsing + the bootlist devices from propagating into the system NVRAM configuration. + A number of such problems have been observed when processing USB devices. + + * If 'bootlist' encounters an invalid OF_DEVPATH entry, it will print + an notice, but still continue on to write invalid data to nvram. + + Changed to abort the script before writing bad data to nvram. + + * When 'ofpathname' encounters an invalid 'devspec' file or invalid + value in a 'devspec' file, while trying to find the logical pathname + for a scsi device, it may continue to return the invalid 'devspec' + value to the caller/invoking script. + + Changed to abort with an error message instead of returning that + invalid value to a caller like 'bootlist'. + + Example: + # bootlist -m normal sdb + # bootlist -m normal -o + Could not translate (null)/scsi@0/sd@0,0 to logical device name + + Signed-off-by: Tyrel Datwyler + +diff --git a/scripts/bootlist b/scripts/bootlist +index 65926d7..acdaf89 100755 +--- a/scripts/bootlist ++++ b/scripts/bootlist +@@ -459,6 +459,7 @@ if [[ ${#LOGICAL_NAMES[*]} -ne 0 ]]; then + + if [[ -z ${OF_DEVPATH[$ctr]} ]]; then + echo "Device ${LOGICAL_NAMES[$ctr]} does not appear to be valid." >&2 ++ exit 1 + else + # See if this is an ethernet adapter. If so, the next entries + # may be parameters for the bootlist entry. +diff --git a/scripts/ofpathname b/scripts/ofpathname +index c37c6bd..dc452c4 100755 +--- a/scripts/ofpathname ++++ b/scripts/ofpathname +@@ -803,9 +803,16 @@ l2of_scsi() + # move up directories until we find one with devspec information + goto_dir $PWD "devspec" + +- OF_PATH=`$CAT $PWD/devspec` ++ if [[ -e $PWD/devspec ]]; then ++ OF_PATH=`$CAT $PWD/devspec` ++ else ++ err $ERR_NO_OFPATH ++ fi ++ + if [[ -z $OF_PATH ]]; then + err $ERR_NO_OFPATH ++ elif [[ ! -e /proc/device-tree/$OF_PATH ]]; then ++ err $ERR_NO_OFPATH + fi + + local vdev=${OF_PATH%/*} diff --git a/powerpc-utils-manpage-lparstat.patch b/powerpc-utils-manpage-lparstat.patch new file mode 100644 index 0000000..9019368 --- /dev/null +++ b/powerpc-utils-manpage-lparstat.patch @@ -0,0 +1,40 @@ +lparstat -E option reports the actual and normalized system utilization +based on the PURR/SPURR registers. Update the lparstat man page too with +the -E option details. + +Reported-by: Pavithra Prakash +Signed-off-by: Kamalesh Babulal +--- +Applies on top of next branch. + + man/lparstat.8 | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/man/lparstat.8 b/man/lparstat.8 +index 0f4c923aaef5..d00e42600165 100644 +--- a/man/lparstat.8 ++++ b/man/lparstat.8 +@@ -209,6 +209,17 @@ The variable memory capacity weight of the LPAR. + .TP + .SH + .TP ++\fB\-E\fR ++Display Scaled Processor Utilization Resource Register(SPURR) based CPU utilization. ++.RS ++.RS ++Actual CPU utilization is based on Processor Utilization Resource Register(PURR). ++.RS ++.RE ++Normalized CPU utilization is based on Scaled Processor Utilization Resource Register(SPURR). ++.TP ++.SH ++.TP + \fB\-l, --legacy\fR + Display the report in legacy format. + .RS + +base-commit: 60d9f54b13b75feee3fd7b25a92b24d0d97ea984 +-- +2.26.2 + + diff --git a/powerpc-utils-ofpathname-c97fe35b5b6d767b88419fa2084a59e986ac3da0.patch b/powerpc-utils-ofpathname-c97fe35b5b6d767b88419fa2084a59e986ac3da0.patch new file mode 100644 index 0000000..2215fc6 --- /dev/null +++ b/powerpc-utils-ofpathname-c97fe35b5b6d767b88419fa2084a59e986ac3da0.patch @@ -0,0 +1,30 @@ +commit c97fe35b5b6d767b88419fa2084a59e986ac3da0 +Author: Nathan Lynch +Date: Mon Apr 27 20:48:04 2020 -0500 + + ofpathname: speed up l2of_scsi() + + There is no need to search the entire /sys hierarchy for kernel device + names like "sda". We know that if it is present it will be in + /sys/class/block. + + In an environment with more than 800 scsi devices, this brings the + execution time for a command like "lsdevinfo -F name -c -q + parent=host1" from over 20 minutes to under two minutes. + + Signed-off-by: Nathan Lynch + Signed-off-by: Tyrel Datwyler + +diff --git a/scripts/ofpathname b/scripts/ofpathname +index 7c6345e..bd61ee0 100755 +--- a/scripts/ofpathname ++++ b/scripts/ofpathname +@@ -773,7 +773,7 @@ l2of_scsi() + local devtype + + # There may be many instances of DEVICE under /sys +- for dir in `$FIND /sys -name $DEVICE`; do ++ for dir in `$FIND /sys/class/block -name $DEVICE`; do + # Move up until we find one with a device link + goto_dir $dir "device" 0 + if [ $? -eq 0 ]; then diff --git a/powerpc-utils.spec b/powerpc-utils.spec index 2a03b80..70f728b 100644 --- a/powerpc-utils.spec +++ b/powerpc-utils.spec @@ -1,6 +1,6 @@ Name: powerpc-utils Version: 1.3.7 -Release: 5%{?dist} +Release: 6%{?dist} Summary: Utilities for PowerPC platforms License: GPLv2 @@ -38,6 +38,30 @@ Patch5: powerpc-utils-1.3.5-install-man.patch Patch6: powerpc-utils-1.3.4-systemd.patch Patch7: powerpc-utils-segfault_when_running_drmgr_-c_pmig_-h.patch Patch8: powerpc-utils-fixup_null_byte.patch +# Improve handling of errors from subsidiary scripts +Patch12: 0001-powerpc-utils-Suppress-errors-reading-kern.v2.patch +Patch13: powerpc-utils-ea4db66e941720313af2c6b1afb32a74f3e360f4.patch +Patch15: powerpc-utils-b0586b5938e9d371e55671422b2f0a5d2cd10c54.patch +# Track and expose idle PURR and SPURR ticks +Patch17: 0001-common-cpu_info_helpers-library-to-capture-CPU-infor.patch +Patch18: 0002-lparstat-Remove-ppc64_cpu-tool-dependency.patch +Patch19: 0003-lparstat-Read-the-online-cores.patch +Patch20: 0004-lparstat-Capture-nominal-frequency.patch +Patch21: 0005-lparstat-Assign-file-descriptors-to-speed-up-read.patch +Patch22: 0006-lparstat-Read-SPURR-Idle_-PURR-SPURR-values.patch +Patch23: 0007-lparstat-Add-helper-function-to-calculate-delta.patch +Patch24: 0008-lparstat-Derive-effective-frequency.patch +Patch25: 0009-lparstat-Add-helper-to-calculate-scaled-timebase.patch +Patch26: 0010-lparstat-Add-helpers-to-derive-PURR-SPURR-values.patch +Patch27: 0011-lparstat-Move-displaying-system-configuration-detail.patch +Patch28: 0012-lparstat-Add-switch-to-print-Scaled-metrics.patch +Patch29: 0013-lparstat-Add-support-for-cpu-hotplug.patch +Patch30: 0014-lparstat-Use-get_delta_value-helper.patch +# ofpathname: speed up l2of_scsi() +Patch31: powerpc-utils-ofpathname-c97fe35b5b6d767b88419fa2084a59e986ac3da0.patch +# Update man page with -E option +Patch32: powerpc-utils-manpage-lparstat.patch +Patch33: powerpc-utils-1.3.6-bz#1847604.patch %description Utilities for PowerPC platforms. @@ -181,6 +205,13 @@ rm -f $RPM_BUILD_ROOT%{_sbindir}/snap $RPM_BUILD_ROOT%{_mandir}/man8/snap.8* %changelog +* Thu Jul 09 2020 Than Ngo - 1.3.7-6 +- Track and expose idle PURR and SPURR ticks +- ofpathname: speed up l2of_scsi() +- ofpathname: failed to boot +- update lparstat man page with -E option +- enable support for ibm,drc-info property + * Sat Mar 28 2020 Than Ngo - 1.3.7-5 - move drmgr in core to avoid pulling in Perl