diff options
author | Jan Stancek <jstancek@redhat.com> | 2017-02-17 06:10:26 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2017-02-17 10:56:35 -0500 |
commit | da8a58b56c661681f9b2fd2fa59c6da3a5bac8d1 (patch) | |
tree | 6c3d7be2c88dd61e006831715244fccf951cf35f /tools/perf | |
parent | 43db2843a4a41cc8cdb6ab696639aeee1f4d5062 (diff) |
perf tools: Replace _SC_NPROCESSORS_CONF with max_present_cpu in cpu_topology_map
There are 2 problems wrt. cpu_topology_map on systems with sparse CPUs:
1. offline/absent CPUs will have their socket_id and core_id set to -1
which triggers:
"socket_id number is too big.You may need to upgrade the perf tool."
2. size of cpu_topology_map (perf_env.cpu[]) is allocated based on
_SC_NPROCESSORS_CONF, but can be indexed with CPU ids going above.
Users of perf_env.cpu[] are using CPU id as index. This can lead
to read beyond what was allocated:
==19991== Invalid read of size 4
==19991== at 0x490CEB: check_cpu_topology (topology.c:69)
==19991== by 0x490CEB: test_session_topology (topology.c:106)
...
For example:
_SC_NPROCESSORS_CONF == 16
available: 2 nodes (0-1)
node 0 cpus: 0 6 8 10 16 22 24 26
node 0 size: 12004 MB
node 0 free: 9470 MB
node 1 cpus: 1 7 9 11 23 25 27
node 1 size: 12093 MB
node 1 free: 9406 MB
node distances:
node 0 1
0: 10 20
1: 20 10
This patch changes HEADER_NRCPUS.nr_cpus_available from _SC_NPROCESSORS_CONF
to max_present_cpu and updates any user of cpu_topology_map to iterate
with nr_cpus_avail.
As a consequence HEADER_CPU_TOPOLOGY core_id and socket_id lists get longer,
but maintain compatibility with pre-patch state - index to cpu_topology_map is
CPU id.
perf test 36 -v
36: Session topology :
--- start ---
test child forked, pid 22211
templ file: /tmp/perf-test-gmdX5i
CPU 0, core 0, socket 0
CPU 1, core 0, socket 1
CPU 6, core 10, socket 0
CPU 7, core 10, socket 1
CPU 8, core 1, socket 0
CPU 9, core 1, socket 1
CPU 10, core 9, socket 0
CPU 11, core 9, socket 1
CPU 16, core 0, socket 0
CPU 22, core 10, socket 0
CPU 23, core 10, socket 1
CPU 24, core 1, socket 0
CPU 25, core 1, socket 1
CPU 26, core 9, socket 0
CPU 27, core 9, socket 1
test child finished with 0
---- end ----
Session topology: Ok
Signed-off-by: Jan Stancek <jstancek@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/d7c05c6445fca74a8442c2c73cfffd349c52c44f.1487146877.git.jstancek@redhat.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/builtin-stat.c | 2 | ||||
-rw-r--r-- | tools/perf/tests/topology.c | 4 | ||||
-rw-r--r-- | tools/perf/util/env.c | 2 | ||||
-rw-r--r-- | tools/perf/util/header.c | 16 |
4 files changed, 10 insertions, 14 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index f28719178b51..ca27a8a705ac 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -1765,7 +1765,7 @@ static inline int perf_env__get_cpu(struct perf_env *env, struct cpu_map *map, i | |||
1765 | 1765 | ||
1766 | cpu = map->map[idx]; | 1766 | cpu = map->map[idx]; |
1767 | 1767 | ||
1768 | if (cpu >= env->nr_cpus_online) | 1768 | if (cpu >= env->nr_cpus_avail) |
1769 | return -1; | 1769 | return -1; |
1770 | 1770 | ||
1771 | return cpu; | 1771 | return cpu; |
diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index 98fe69ac553c..803f893550d6 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c | |||
@@ -65,7 +65,9 @@ static int check_cpu_topology(char *path, struct cpu_map *map) | |||
65 | session = perf_session__new(&file, false, NULL); | 65 | session = perf_session__new(&file, false, NULL); |
66 | TEST_ASSERT_VAL("can't get session", session); | 66 | TEST_ASSERT_VAL("can't get session", session); |
67 | 67 | ||
68 | for (i = 0; i < session->header.env.nr_cpus_online; i++) { | 68 | for (i = 0; i < session->header.env.nr_cpus_avail; i++) { |
69 | if (!cpu_map__has(map, i)) | ||
70 | continue; | ||
69 | pr_debug("CPU %d, core %d, socket %d\n", i, | 71 | pr_debug("CPU %d, core %d, socket %d\n", i, |
70 | session->header.env.cpu[i].core_id, | 72 | session->header.env.cpu[i].core_id, |
71 | session->header.env.cpu[i].socket_id); | 73 | session->header.env.cpu[i].socket_id); |
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index bb964e86b09d..075fc77286bf 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c | |||
@@ -66,7 +66,7 @@ int perf_env__read_cpu_topology_map(struct perf_env *env) | |||
66 | return 0; | 66 | return 0; |
67 | 67 | ||
68 | if (env->nr_cpus_avail == 0) | 68 | if (env->nr_cpus_avail == 0) |
69 | env->nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF); | 69 | env->nr_cpus_avail = cpu__max_present_cpu(); |
70 | 70 | ||
71 | nr_cpus = env->nr_cpus_avail; | 71 | nr_cpus = env->nr_cpus_avail; |
72 | if (nr_cpus == -1) | 72 | if (nr_cpus == -1) |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1222f6c5e7b3..05714d548584 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -295,11 +295,7 @@ static int write_nrcpus(int fd, struct perf_header *h __maybe_unused, | |||
295 | u32 nrc, nra; | 295 | u32 nrc, nra; |
296 | int ret; | 296 | int ret; |
297 | 297 | ||
298 | nr = sysconf(_SC_NPROCESSORS_CONF); | 298 | nrc = cpu__max_present_cpu(); |
299 | if (nr < 0) | ||
300 | return -1; | ||
301 | |||
302 | nrc = (u32)(nr & UINT_MAX); | ||
303 | 299 | ||
304 | nr = sysconf(_SC_NPROCESSORS_ONLN); | 300 | nr = sysconf(_SC_NPROCESSORS_ONLN); |
305 | if (nr < 0) | 301 | if (nr < 0) |
@@ -513,9 +509,7 @@ static struct cpu_topo *build_cpu_topology(void) | |||
513 | int ret = -1; | 509 | int ret = -1; |
514 | struct cpu_map *map; | 510 | struct cpu_map *map; |
515 | 511 | ||
516 | ncpus = sysconf(_SC_NPROCESSORS_CONF); | 512 | ncpus = cpu__max_present_cpu(); |
517 | if (ncpus < 0) | ||
518 | return NULL; | ||
519 | 513 | ||
520 | /* build online CPU map */ | 514 | /* build online CPU map */ |
521 | map = cpu_map__new(NULL); | 515 | map = cpu_map__new(NULL); |
@@ -1139,7 +1133,7 @@ static void print_cpu_topology(struct perf_header *ph, int fd __maybe_unused, | |||
1139 | { | 1133 | { |
1140 | int nr, i; | 1134 | int nr, i; |
1141 | char *str; | 1135 | char *str; |
1142 | int cpu_nr = ph->env.nr_cpus_online; | 1136 | int cpu_nr = ph->env.nr_cpus_avail; |
1143 | 1137 | ||
1144 | nr = ph->env.nr_sibling_cores; | 1138 | nr = ph->env.nr_sibling_cores; |
1145 | str = ph->env.sibling_cores; | 1139 | str = ph->env.sibling_cores; |
@@ -1794,7 +1788,7 @@ static int process_cpu_topology(struct perf_file_section *section, | |||
1794 | u32 nr, i; | 1788 | u32 nr, i; |
1795 | char *str; | 1789 | char *str; |
1796 | struct strbuf sb; | 1790 | struct strbuf sb; |
1797 | int cpu_nr = ph->env.nr_cpus_online; | 1791 | int cpu_nr = ph->env.nr_cpus_avail; |
1798 | u64 size = 0; | 1792 | u64 size = 0; |
1799 | 1793 | ||
1800 | ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu)); | 1794 | ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu)); |
@@ -1875,7 +1869,7 @@ static int process_cpu_topology(struct perf_file_section *section, | |||
1875 | if (ph->needs_swap) | 1869 | if (ph->needs_swap) |
1876 | nr = bswap_32(nr); | 1870 | nr = bswap_32(nr); |
1877 | 1871 | ||
1878 | if (nr > (u32)cpu_nr) { | 1872 | if (nr != (u32)-1 && nr > (u32)cpu_nr) { |
1879 | pr_debug("socket_id number is too big." | 1873 | pr_debug("socket_id number is too big." |
1880 | "You may need to upgrade the perf tool.\n"); | 1874 | "You may need to upgrade the perf tool.\n"); |
1881 | goto free_cpu; | 1875 | goto free_cpu; |