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: Ian 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: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
1a6abdde13
commit
09b73fe9e3
@ -1,4 +1,5 @@
|
||||
// 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. */
|
||||
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",
|
||||
(void **)&val_ptr));
|
||||
{
|
||||
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,
|
||||
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",
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -1,100 +1,23 @@
|
||||
// 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;
|
||||
}
|
||||
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);
|
||||
|
||||
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;
|
||||
return cached_result;
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
#ifndef __SMT_H
|
||||
#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 */
|
||||
|
Loading…
Reference in New Issue
Block a user