2015-09-04 16:58:31 +08:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "tests.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "session.h"
|
|
|
|
#include "evlist.h"
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
#define TEMPL "/tmp/perf-test-XXXXXX"
|
|
|
|
#define DATA_SIZE 10
|
|
|
|
|
|
|
|
static int get_temp(char *path)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
strcpy(path, TEMPL);
|
|
|
|
|
|
|
|
fd = mkstemp(path);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror("mkstemp failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int session_write_header(char *path)
|
|
|
|
{
|
|
|
|
struct perf_session *session;
|
|
|
|
struct perf_data_file file = {
|
|
|
|
.path = path,
|
|
|
|
.mode = PERF_DATA_MODE_WRITE,
|
|
|
|
};
|
|
|
|
|
|
|
|
session = perf_session__new(&file, false, NULL);
|
|
|
|
TEST_ASSERT_VAL("can't get session", session);
|
|
|
|
|
|
|
|
session->evlist = perf_evlist__new_default();
|
|
|
|
TEST_ASSERT_VAL("can't get evlist", session->evlist);
|
|
|
|
|
|
|
|
perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
|
|
|
|
perf_header__set_feat(&session->header, HEADER_NRCPUS);
|
|
|
|
|
|
|
|
session->header.data_size += DATA_SIZE;
|
|
|
|
|
|
|
|
TEST_ASSERT_VAL("failed to write header",
|
|
|
|
!perf_session__write_header(session, session->evlist, file.fd, true));
|
|
|
|
|
|
|
|
perf_session__delete(session);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_cpu_topology(char *path, struct cpu_map *map)
|
|
|
|
{
|
|
|
|
struct perf_session *session;
|
|
|
|
struct perf_data_file file = {
|
|
|
|
.path = path,
|
|
|
|
.mode = PERF_DATA_MODE_READ,
|
|
|
|
};
|
|
|
|
int i;
|
|
|
|
|
|
|
|
session = perf_session__new(&file, false, NULL);
|
|
|
|
TEST_ASSERT_VAL("can't get session", session);
|
|
|
|
|
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>
2017-02-17 19:10:26 +08:00
|
|
|
for (i = 0; i < session->header.env.nr_cpus_avail; i++) {
|
|
|
|
if (!cpu_map__has(map, i))
|
|
|
|
continue;
|
2015-09-04 16:58:31 +08:00
|
|
|
pr_debug("CPU %d, core %d, socket %d\n", i,
|
|
|
|
session->header.env.cpu[i].core_id,
|
|
|
|
session->header.env.cpu[i].socket_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < map->nr; i++) {
|
|
|
|
TEST_ASSERT_VAL("Core ID doesn't match",
|
2015-10-16 18:41:15 +08:00
|
|
|
(session->header.env.cpu[map->map[i]].core_id == (cpu_map__get_core(map, i, NULL) & 0xffff)));
|
2015-09-04 16:58:31 +08:00
|
|
|
|
|
|
|
TEST_ASSERT_VAL("Socket ID doesn't match",
|
2015-10-16 18:41:15 +08:00
|
|
|
(session->header.env.cpu[map->map[i]].socket_id == cpu_map__get_socket(map, i, NULL)));
|
2015-09-04 16:58:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
perf_session__delete(session);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
perf tests: Pass the subtest index to each test routine
Some tests have sub-tests we want to run, so allow passing this.
Wang tried to avoid having to touch all tests, but then, having the
test.func in an anonymous union makes the build fail on older compilers,
like the one in RHEL6, where:
test a = {
.func = foo,
};
fails.
To fix it leave the func pointer in the main structure and pass the subtest
index to all tests, end result function is the same, but we have just one
function pointer, not two, with and without the subtest index as an argument.
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-5genj0ficwdmelpoqlds0u4y@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-11-19 23:01:48 +08:00
|
|
|
int test_session_topology(int subtest __maybe_unused)
|
2015-09-04 16:58:31 +08:00
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
struct cpu_map *map;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
TEST_ASSERT_VAL("can't get templ file", !get_temp(path));
|
|
|
|
|
|
|
|
pr_debug("templ file: %s\n", path);
|
|
|
|
|
|
|
|
if (session_write_header(path))
|
|
|
|
goto free_path;
|
|
|
|
|
|
|
|
map = cpu_map__new(NULL);
|
|
|
|
if (map == NULL) {
|
|
|
|
pr_debug("failed to get system cpumap\n");
|
|
|
|
goto free_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (check_cpu_topology(path, map))
|
|
|
|
goto free_map;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
free_map:
|
|
|
|
cpu_map__put(map);
|
|
|
|
free_path:
|
|
|
|
unlink(path);
|
|
|
|
return ret;
|
|
|
|
}
|