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

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.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 1a6abdde
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include "util/cputopo.h"
#include "util/debug.h" #include "util/debug.h"
#include "util/expr.h" #include "util/expr.h"
#include "util/header.h" #include "util/header.h"
...@@ -154,15 +155,20 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u ...@@ -154,15 +155,20 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u
(void **)&val_ptr)); (void **)&val_ptr));
/* Only EVENT1 or EVENT2 need be measured depending on the value of smt_on. */ /* Only EVENT1 or EVENT2 need be measured depending on the value of smt_on. */
expr__ctx_clear(ctx); {
TEST_ASSERT_VAL("find ids", struct cpu_topology *topology = cpu_topology__new();
expr__find_ids("EVENT1 if #smt_on else EVENT2", bool smton = smt_on(topology);
NULL, ctx) == 0);
TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 1); cpu_topology__delete(topology);
TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, expr__ctx_clear(ctx);
smt_on() ? "EVENT1" : "EVENT2", TEST_ASSERT_VAL("find ids",
(void **)&val_ptr)); 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,
smton ? "EVENT1" : "EVENT2",
(void **)&val_ptr));
}
/* The expression is a constant 1.0 without needing to evaluate EVENT1. */ /* The expression is a constant 1.0 without needing to evaluate EVENT1. */
expr__ctx_clear(ctx); expr__ctx_clear(ctx);
TEST_ASSERT_VAL("find ids", TEST_ASSERT_VAL("find ids",
......
...@@ -157,6 +157,21 @@ void cpu_topology__delete(struct cpu_topology *tp) ...@@ -157,6 +157,21 @@ void cpu_topology__delete(struct cpu_topology *tp)
free(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) static bool has_die_topology(void)
{ {
char filename[MAXPATHLEN]; char filename[MAXPATHLEN];
......
...@@ -58,6 +58,8 @@ struct hybrid_topology { ...@@ -58,6 +58,8 @@ struct hybrid_topology {
struct cpu_topology *cpu_topology__new(void); struct cpu_topology *cpu_topology__new(void);
void cpu_topology__delete(struct cpu_topology *tp); 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); struct numa_topology *numa_topology__new(void);
void numa_topology__delete(struct numa_topology *tp); void numa_topology__delete(struct numa_topology *tp);
......
...@@ -412,11 +412,6 @@ double expr__get_literal(const char *literal) ...@@ -412,11 +412,6 @@ double expr__get_literal(const char *literal)
static struct cpu_topology *topology; static struct cpu_topology *topology;
double result = NAN; double result = NAN;
if (!strcasecmp("#smt_on", literal)) {
result = smt_on() > 0 ? 1.0 : 0.0;
goto out;
}
if (!strcmp("#num_cpus", literal)) { if (!strcmp("#num_cpus", literal)) {
result = cpu__max_present_cpu().cpu; result = cpu__max_present_cpu().cpu;
goto out; goto out;
...@@ -440,6 +435,10 @@ double expr__get_literal(const char *literal) ...@@ -440,6 +435,10 @@ double expr__get_literal(const char *literal)
goto out; goto out;
} }
} }
if (!strcasecmp("#smt_on", literal)) {
result = smt_on(topology) ? 1.0 : 0.0;
goto out;
}
if (!strcmp("#num_packages", literal)) { if (!strcmp("#num_packages", literal)) {
result = topology->package_cpus_lists; result = topology->package_cpus_lists;
goto out; goto out;
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
#include <stdio.h> #include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/bitops.h>
#include "api/fs/fs.h" #include "api/fs/fs.h"
#include "cputopo.h"
#include "smt.h" #include "smt.h"
/** bool smt_on(const struct cpu_topology *topology)
* 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)
{ {
static bool cached; static bool cached;
static int cached_result; static bool cached_result;
int cpu; int fs_value;
int ncpu;
if (cached) if (cached)
return cached_result; return cached_result;
if (sysfs__read_int("devices/system/cpu/smt/active", &cached_result) >= 0) { if (sysfs__read_int("devices/system/cpu/smt/active", &fs_value) >= 0)
cached = true; cached_result = (fs_value == 1);
return cached_result; else
} cached_result = cpu_topology__smt_on(topology);
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];
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; cached = true;
return cached_result; return cached_result;
} }
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
#ifndef __SMT_H #ifndef __SMT_H
#define __SMT_H 1 #define __SMT_H 1
int smt_on(void); struct cpu_topology;
/* Returns true if SMT (aka hyperthreading) is enabled. */
bool smt_on(const struct cpu_topology *topology);
#endif /* __SMT_H */ #endif /* __SMT_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment