public inbox for devnull+historical-speck@kernel.org
 help / color / mirror / Atom feed
* [MODERATED] [PATCH 0/1] SMTCTL 0
@ 2018-06-07 20:54 Andi Kleen
  2018-06-07 20:54 ` [MODERATED] [PATCH 1/1] SMTCTL 1 Andi Kleen
  0 siblings, 1 reply; 2+ messages in thread
From: Andi Kleen @ 2018-06-07 20:54 UTC (permalink / raw)
  To: speck

Here's an alternative proposal for SMT disabling.

I reimplemented my script as a C tool and put it into tools/* 

# smtctl --enable
# smtctl --disable
# smtctl --print

Advantages:
- No kernel changes (although it would benefit from a minor one,
see the commit)
- Much easier to use at runtime than opaque sysfs
- Encourages the right use model of only switching SMT state
when it is actually needed and based on a conscious decision, 
not unnecessarily or globally.

Andi Kleen (1):
  tools/smtctl: Add smtctl to enable/disable SMT at runtime

 tools/smtctl/Makefile |  10 ++
 tools/smtctl/smtctl.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 267 insertions(+)
 create mode 100644 tools/smtctl/Makefile
 create mode 100644 tools/smtctl/smtctl.c

-- 
2.14.3

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [MODERATED] [PATCH 1/1] SMTCTL 1
  2018-06-07 20:54 [MODERATED] [PATCH 0/1] SMTCTL 0 Andi Kleen
@ 2018-06-07 20:54 ` Andi Kleen
  0 siblings, 0 replies; 2+ messages in thread
From: Andi Kleen @ 2018-06-07 20:54 UTC (permalink / raw)
  To: speck

Add a new tool called "smtctl" that allows to enable/disable SMT from
the command line.

It supports --enable, --disable, --print, and a filter --cpus
to only apply enable or disable to a subset of CPUs.

Open issue:
- The filtering only works for online CPUs because the kernel
does not preserve the topology information for offlined CPUs.
This could be fixed in the kernel.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 tools/smtctl/Makefile |  10 ++
 tools/smtctl/smtctl.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 267 insertions(+)
 create mode 100644 tools/smtctl/Makefile
 create mode 100644 tools/smtctl/smtctl.c

diff --git a/tools/smtctl/Makefile b/tools/smtctl/Makefile
new file mode 100644
index 000000000000..6457f5368e32
--- /dev/null
+++ b/tools/smtctl/Makefile
@@ -0,0 +1,10 @@
+PREFIX := /usr/local
+CFLAGS := -g -Wall -O2
+
+all: smtctl
+
+clean:
+	rm -f smtctl smtctl.o
+
+install:
+	cp smtctl ${PREFIX}/bin
diff --git a/tools/smtctl/smtctl.c b/tools/smtctl/smtctl.c
new file mode 100644
index 000000000000..d0100f415e52
--- /dev/null
+++ b/tools/smtctl/smtctl.c
@@ -0,0 +1,257 @@
+/* Enable and disable SMT */
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2018 Intel Corporation. Author: Andi Kleen */
+#define _GNU_SOURCE 1
+#include <getopt.h>
+#include <unistd.h>
+#include <glob.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+struct option opts[] = {
+	{"enable", no_argument, NULL, 'e' },
+	{"disable", no_argument, NULL, 'd' },
+	{"print", no_argument, NULL, 'p' },
+	{"cpus", required_argument, NULL, 'c' },
+	{"verbose", no_argument, NULL, 'v' },
+	{}
+};
+
+struct cpu {
+	int core;
+	int pkg;
+	int thread;
+	bool filter;
+	int num_online;
+	int online;
+};
+
+struct cpu *cpus;
+int num_cpus;
+bool verbose;
+
+
+static int match_core(int a, int b)
+{
+	return cpus[a].pkg == cpus[b].pkg && cpus[a].core == cpus[b].core;
+}
+
+int get_cpu(char *p)
+{
+	char *s = strstr(p, "cpu/cpu");
+	if (s)
+		return strtoul(s + 7, NULL, 10);
+	assert(0);
+}
+
+void writefile(char *val, char *fmt, ...)
+{
+	char *fn;
+	va_list ap;
+	va_start(ap, fmt);
+	vasprintf(&fn, fmt, ap);
+	va_end(ap);
+	FILE *f = fopen(fn, "w");
+	if (!f) {
+		fprintf(stderr, "Cannot write %s: %s\n", fn, strerror(errno));
+		return;
+	}
+	fputs(val, f);
+	fclose(f);
+	free(fn);
+}
+
+int read_num(char *fmt, ...)
+{
+	char *fn;
+	va_list ap;
+	va_start(ap, fmt);
+	vasprintf(&fn, fmt, ap);
+	va_end(ap);
+	int res;
+	FILE *f = fopen(fn, "r");
+	if (!f || fscanf(f, "%d", &res) != 1) {
+		fprintf(stderr, "Cannot read %s: %s\n", fn, strerror(errno));
+		return -1;
+	}
+	free(fn);
+	fclose(f);
+	return res;
+}
+
+void read_topology(void)
+{
+	num_cpus = sysconf(_SC_NPROCESSORS_CONF);
+
+	cpus = calloc(num_cpus, sizeof(struct cpu));
+	if (!cpus)
+		exit(ENOMEM);
+	memset(cpus, -1, num_cpus * sizeof(struct cpu));
+
+	glob_t core_ids, packages;
+
+	memset(&core_ids, 0, sizeof(glob_t));
+	memset(&packages, 0, sizeof(glob_t));
+
+	if (glob("/sys/devices/system/cpu/cpu*/topology/core_id",
+				0, NULL, &core_ids) ||
+	    glob("/sys/devices/system/cpu/cpu*/topology/physical_package_id",
+		    0, NULL, &packages)) {
+		fprintf(stderr, "Cannot read cpu topology: %s\n", strerror(errno));
+		exit(1);
+	}
+
+	int i;
+	for (i = 0; i < core_ids.gl_pathc; i++) {
+		int cpu = get_cpu(core_ids.gl_pathv[i]);
+		cpus[cpu].core = read_num(core_ids.gl_pathv[i]);
+	}
+	for (i = 0; i < packages.gl_pathc; i++) {
+		int cpu = get_cpu(packages.gl_pathv[i]);
+		cpus[cpu].pkg = read_num(packages.gl_pathv[i]);
+	}
+
+	globfree(&core_ids);
+	globfree(&packages);
+
+	/* n^2 algorithm, but we assume the number of cpus stays reasonable */
+	for (i = 0; i < num_cpus; i++) {
+		int thread = 0;
+		int j;
+		for (j = 0; j < num_cpus; j++) {
+			if (cpus[i].pkg == -1)
+				continue;
+			if (match_core(i, j))
+				cpus[j].thread = thread++;
+		}
+		cpus[i].filter = true;
+		cpus[i].num_online = 0;
+	}
+}
+
+void apply_filter(char *filter)
+{
+	int i, j;
+	char *s;
+
+	for (i = 0; i < num_cpus; i++)
+		cpus[i].filter = false;
+	while ((s = strtok(filter, ",")) != NULL) {
+		unsigned cpu = strtoul(s, NULL, 0);
+		if (cpu >= num_cpus) {
+			fprintf(stderr, "filter cpu %d out of bounds\n", cpu);
+			continue;
+		}
+		for (j = 0; j < num_cpus; j++)
+			if (match_core(cpu, j))
+				cpus[j].filter = true;
+		filter = NULL;
+	}
+}
+
+void usage(void)
+{
+	fprintf(stderr, "Enable or disable SMT in CPUs\n"
+			"Usage: smtctl [--enable] [--disable] [--filter cpus]\n"
+			"--enable | -e			Enable SMT on CPUs\n"
+			"--disable | -d			Disable SMT on CPUs\n"
+			"--print | -p			Print status\n"
+			"--verbose | -v			Be verbose\n"
+			"--cpus | -c cpunum1,...	Only affect CPUs in list\n");
+	exit(1);
+}
+
+int main(int ac, char **av)
+{
+	int i;
+	static char *aname[] = { "Enabling", "Disabling" }; /* Match the enum */
+	enum { ENABLE, DISABLE, PRINT, NONE } action = NONE;
+	char *filter = NULL;
+
+	int c;
+	while ((c = getopt_long(ac, av, "edc:v", opts, NULL)) != -1) {
+		switch (c) {
+		case 'e': /* on */
+			action = ENABLE;
+			break;
+
+		case 'd': /* off */
+			action = DISABLE;
+			break;
+
+		case 'p':
+			action = PRINT;
+			break;
+
+		case 'c': /* cpu */
+			filter = optarg;
+			break;
+
+		case 'v':
+			verbose = true;
+			break;
+
+		default:
+			usage();
+		}
+	}
+	if (optind > ac)
+		usage();
+	read_topology();
+	if (filter)
+		apply_filter(filter);
+
+	switch (action) {
+	case ENABLE:
+	case DISABLE:
+		for (i = 0; i < num_cpus; i++) {
+			if (!cpus[i].filter)
+				continue;
+			if (cpus[i].thread == 0)
+				continue;
+			if (verbose)
+				printf("%s cpu %d\n", aname[action], i);
+			writefile(action == ENABLE ? "1" : "0",
+				  "/sys/devices/system/cpu/cpu%d/online", i);
+		}
+		break;
+	case PRINT:
+		for (i = 0; i < num_cpus; i++) {
+			if (!cpus[i].filter)
+				continue;
+			cpus[i].online = read_num("/sys/devices/system/cpu/cpu%d/online", i);
+			if (!cpus[i].online)
+				continue;
+			int j;
+			for (j = 0; j < num_cpus; j++)
+				if (match_core(i, j))
+					cpus[i].num_online++;
+		}
+
+		for (i = 0; i < num_cpus; i++) {
+			if (!cpus[i].filter)
+				continue;
+			printf("%3d: ", i);
+			if (cpus[i].num_online == 0)
+				printf("offline");
+			else if (cpus[i].num_online == 1)
+				printf("SMT:off");
+			else
+				printf("SMT:%d", cpus[i].num_online);
+			if (verbose)
+				printf(" package %2d core %2d thread %2d online %d",
+					cpus[i].pkg, cpus[i].core,
+					cpus[i].thread, cpus[i].online);
+			fputc('\n', stdout);
+		}
+		break;
+	default:
+		usage();
+	}
+	return 0;
+}
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-06-07 20:54 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-06-07 20:54 [MODERATED] [PATCH 0/1] SMTCTL 0 Andi Kleen
2018-06-07 20:54 ` [MODERATED] [PATCH 1/1] SMTCTL 1 Andi Kleen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox