perf smt: Compute SMT from topology
authorIan Rogers <irogers@google.com>
Wed, 31 Aug 2022 17:49:22 +0000 (10:49 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 4 Oct 2022 11:55:22 +0000 (08:55 -0300)
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>
tools/perf/tests/expr.c
tools/perf/util/cputopo.c
tools/perf/util/cputopo.h
tools/perf/util/expr.c
tools/perf/util/smt.c
tools/perf/util/smt.h

index 7ca5e37..db736ed 100644 (file)
@@ -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",
index d275d84..511002e 100644 (file)
@@ -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];
index 854e18f..469db77 100644 (file)
@@ -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);
index 00bde68..8aa7daf 100644 (file)
@@ -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;
index 8fed032..ce90c4e 100644 (file)
 // 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;
 }
index a98d658..e26999c 100644 (file)
@@ -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 */