Commit 09b73fe9 authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo
Browse files

perf smt: Compute SMT from topology



The topology records sibling threads. Rather than computing SMT using
siblings in sysfs, reuse the values in topology. This only applies
when the file smt/active isn't available.

Signed-off-by: default avatarIan Rogers <irogers@google.com>
Cc: Ahmad Yasin <ahmad.yasin@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Caleb Biggers <caleb.biggers@intel.com>
Cc: Florian Fischer <florian.fischer@muhq.space>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Kshipra Bopardikar <kshipra.bopardikar@intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Miaoqian Lin <linmq006@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: https://lore.kernel.org/r/20220831174926.579643-4-irogers@google.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 1a6abdde
Loading
Loading
Loading
Loading
+15 −9
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
#include "util/cputopo.h"
#include "util/debug.h"
#include "util/expr.h"
#include "util/header.h"
@@ -154,15 +155,20 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u
						    (void **)&val_ptr));

	/* Only EVENT1 or EVENT2 need be measured depending on the value of smt_on. */
	{
		struct cpu_topology *topology = cpu_topology__new();
		bool smton = smt_on(topology);

		cpu_topology__delete(topology);
		expr__ctx_clear(ctx);
		TEST_ASSERT_VAL("find ids",
				expr__find_ids("EVENT1 if #smt_on else EVENT2",
					NULL, ctx) == 0);
		TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 1);
		TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids,
						  smt_on() ? "EVENT1" : "EVENT2",
							  smton ? "EVENT1" : "EVENT2",
							  (void **)&val_ptr));

	}
	/* The expression is a constant 1.0 without needing to evaluate EVENT1. */
	expr__ctx_clear(ctx);
	TEST_ASSERT_VAL("find ids",
+15 −0
Original line number Diff line number Diff line
@@ -157,6 +157,21 @@ void cpu_topology__delete(struct cpu_topology *tp)
	free(tp);
}

bool cpu_topology__smt_on(const struct cpu_topology *topology)
{
	for (u32 i = 0; i < topology->core_cpus_lists; i++) {
		const char *cpu_list = topology->core_cpus_list[i];

		/*
		 * If there is a need to separate siblings in a core then SMT is
		 * enabled.
		 */
		if (strchr(cpu_list, ',') || strchr(cpu_list, '-'))
			return true;
	}
	return false;
}

static bool has_die_topology(void)
{
	char filename[MAXPATHLEN];
+2 −0
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@ struct hybrid_topology {

struct cpu_topology *cpu_topology__new(void);
void cpu_topology__delete(struct cpu_topology *tp);
/* Determine from the core list whether SMT was enabled. */
bool cpu_topology__smt_on(const struct cpu_topology *topology);

struct numa_topology *numa_topology__new(void);
void numa_topology__delete(struct numa_topology *tp);
+4 −5
Original line number Diff line number Diff line
@@ -412,11 +412,6 @@ double expr__get_literal(const char *literal)
	static struct cpu_topology *topology;
	double result = NAN;

	if (!strcasecmp("#smt_on", literal)) {
		result = smt_on() > 0 ? 1.0 : 0.0;
		goto out;
	}

	if (!strcmp("#num_cpus", literal)) {
		result = cpu__max_present_cpu().cpu;
		goto out;
@@ -440,6 +435,10 @@ double expr__get_literal(const char *literal)
			goto out;
		}
	}
	if (!strcasecmp("#smt_on", literal)) {
		result = smt_on(topology) ? 1.0 : 0.0;
		goto out;
	}
	if (!strcmp("#num_packages", literal)) {
		result = topology->package_cpus_lists;
		goto out;
+9 −86
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/bitops.h>
#include <string.h>
#include "api/fs/fs.h"
#include "cputopo.h"
#include "smt.h"

/**
 * hweight_str - Returns the number of bits set in str. Stops at first non-hex
 *	       or ',' character.
 */
static int hweight_str(char *str)
{
	int result = 0;

	while (*str) {
		switch (*str++) {
		case '0':
		case ',':
			break;
		case '1':
		case '2':
		case '4':
		case '8':
			result++;
			break;
		case '3':
		case '5':
		case '6':
		case '9':
		case 'a':
		case 'A':
		case 'c':
		case 'C':
			result += 2;
			break;
		case '7':
		case 'b':
		case 'B':
		case 'd':
		case 'D':
		case 'e':
		case 'E':
			result += 3;
			break;
		case 'f':
		case 'F':
			result += 4;
			break;
		default:
			goto done;
		}
	}
done:
	return result;
}

int smt_on(void)
bool smt_on(const struct cpu_topology *topology)
{
	static bool cached;
	static int cached_result;
	int cpu;
	int ncpu;
	static bool cached_result;
	int fs_value;

	if (cached)
		return cached_result;

	if (sysfs__read_int("devices/system/cpu/smt/active", &cached_result) >= 0) {
		cached = true;
		return cached_result;
	}

	cached_result = 0;
	ncpu = sysconf(_SC_NPROCESSORS_CONF);
	for (cpu = 0; cpu < ncpu; cpu++) {
		unsigned long long siblings;
		char *str;
		size_t strlen;
		char fn[256];
	if (sysfs__read_int("devices/system/cpu/smt/active", &fs_value) >= 0)
		cached_result = (fs_value == 1);
	else
		cached_result = cpu_topology__smt_on(topology);

		snprintf(fn, sizeof fn,
			"devices/system/cpu/cpu%d/topology/thread_siblings", cpu);
		if (sysfs__read_str(fn, &str, &strlen) < 0) {
			snprintf(fn, sizeof fn,
				"devices/system/cpu/cpu%d/topology/core_cpus", cpu);
			if (sysfs__read_str(fn, &str, &strlen) < 0)
				continue;
		}
		/* Entry is hex, but does not have 0x, so need custom parser */
		siblings = hweight_str(str);
		free(str);
		if (siblings > 1) {
			cached_result = 1;
			break;
		}
	}
	cached = true;
	return cached_result;
}
Loading