Blob Blame History Raw
From 8f0bf6a9dd14c16ee95092f43c45ee256f10637b Mon Sep 17 00:00:00 2001
Message-Id: <8f0bf6a9dd14c16ee95092f43c45ee256f10637b.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: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 <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>

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 <kamalesh@linux.vnet.ibm.com>
---
 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 <string.h>
 #include <getopt.h>
 #include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #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