diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-05-07 20:32:18 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-05-07 20:32:18 +0200 |
commit | f085df1be60abf670315c11036261cfaec16b2eb (patch) | |
tree | c02c07ad31578b90c3cc99be6b5ba680d163bca7 /tools/perf/tests | |
parent | Merge tag 'core-debugobjects-2023-05-06' of git://git.kernel.org/pub/scm/linu... (diff) | |
parent | Revert "perf build: Make BUILD_BPF_SKEL default, rename to NO_BPF_SKEL" (diff) | |
download | linux-f085df1be60abf670315c11036261cfaec16b2eb.tar.xz linux-f085df1be60abf670315c11036261cfaec16b2eb.zip |
Merge tag 'perf-tools-for-v6.4-3-2023-05-06' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux
Pull perf tool updates from Arnaldo Carvalho de Melo:
"Third version of perf tool updates, with the build problems with with
using a 'vmlinux.h' generated from the main build fixed, and the bpf
skeleton build disabled by default.
Build:
- Require libtraceevent to build, one can disable it using
NO_LIBTRACEEVENT=1.
It is required for tools like 'perf sched', 'perf kvm', 'perf
trace', etc.
libtraceevent is available in most distros so installing
'libtraceevent-devel' should be a one-time event to continue
building perf as usual.
Using NO_LIBTRACEEVENT=1 produces tooling that is functional and
sufficient for lots of users not interested in those libtraceevent
dependent features.
- Allow Python support in 'perf script' when libtraceevent isn't
linked, as not all features requires it, for instance Intel PT does
not use tracepoints.
- Error if the python interpreter needed for jevents to work isn't
available and NO_JEVENTS=1 isn't set, preventing a build without
support for JSON vendor events, which is a rare but possible
condition. The two check error messages:
$(error ERROR: No python interpreter needed for jevents generation. Install python or build with NO_JEVENTS=1.)
$(error ERROR: Python interpreter needed for jevents generation too old (older than 3.6). Install a newer python or build with NO_JEVENTS=1.)
- Make libbpf 1.0 the minimum required when building with out of
tree, distro provided libbpf.
- Use libsdtc++'s and LLVM's libcxx's __cxa_demangle, a portable C++
demangler, add 'perf test' entry for it.
- Make binutils libraries opt in, as distros disable building with it
due to licensing, they were used for C++ demangling, for instance.
- Switch libpfm4 to opt-out rather than opt-in, if libpfm-devel (or
equivalent) isn't installed, we'll just have a build warning:
Makefile.config:1144: libpfm4 not found, disables libpfm4 support. Please install libpfm4-dev
- Add a feature test for scandirat(), that is not implemented so far
in musl and uclibc, disabling features that need it, such as
scanning for tracepoints in /sys/kernel/tracing/events.
perf BPF filters:
- New feature where BPF can be used to filter samples, for instance:
$ sudo ./perf record -e cycles --filter 'period > 1000' true
$ sudo ./perf script
perf-exec 2273949 546850.708501: 5029 cycles: ffffffff826f9e25 finish_wait+0x5 ([kernel.kallsyms])
perf-exec 2273949 546850.708508: 32409 cycles: ffffffff826f9e25 finish_wait+0x5 ([kernel.kallsyms])
perf-exec 2273949 546850.708526: 143369 cycles: ffffffff82b4cdbf xas_start+0x5f ([kernel.kallsyms])
perf-exec 2273949 546850.708600: 372650 cycles: ffffffff8286b8f7 __pagevec_lru_add+0x117 ([kernel.kallsyms])
perf-exec 2273949 546850.708791: 482953 cycles: ffffffff829190de __mod_memcg_lruvec_state+0x4e ([kernel.kallsyms])
true 2273949 546850.709036: 501985 cycles: ffffffff828add7c tlb_gather_mmu+0x4c ([kernel.kallsyms])
true 2273949 546850.709292: 503065 cycles: 7f2446d97c03 _dl_map_object_deps+0x973 (/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2)
- In addition to 'period' (PERF_SAMPLE_PERIOD), the other
PERF_SAMPLE_ can be used for filtering, and also some other sample
accessible values, from tools/perf/Documentation/perf-record.txt:
Essentially the BPF filter expression is:
<term> <operator> <value> (("," | "||") <term> <operator> <value>)*
The <term> can be one of:
ip, id, tid, pid, cpu, time, addr, period, txn, weight, phys_addr,
code_pgsz, data_pgsz, weight1, weight2, weight3, ins_lat, retire_lat,
p_stage_cyc, mem_op, mem_lvl, mem_snoop, mem_remote, mem_lock,
mem_dtlb, mem_blk, mem_hops
The <operator> can be one of:
==, !=, >, >=, <, <=, &
The <value> can be one of:
<number> (for any term)
na, load, store, pfetch, exec (for mem_op)
l1, l2, l3, l4, cxl, io, any_cache, lfb, ram, pmem (for mem_lvl)
na, none, hit, miss, hitm, fwd, peer (for mem_snoop)
remote (for mem_remote)
na, locked (for mem_locked)
na, l1_hit, l1_miss, l2_hit, l2_miss, any_hit, any_miss, walk, fault (for mem_dtlb)
na, by_data, by_addr (for mem_blk)
hops0, hops1, hops2, hops3 (for mem_hops)
perf lock contention:
- Show lock type with address.
- Track and show mmap_lock, siglock and per-cpu rq_lock with address.
This is done for mmap_lock by following the current->mm pointer:
$ sudo ./perf lock con -abl -- sleep 10
contended total wait max wait avg wait address symbol
...
16344 312.30 ms 2.22 ms 19.11 us ffff8cc702595640
17686 310.08 ms 1.49 ms 17.53 us ffff8cc7025952c0
3 84.14 ms 45.79 ms 28.05 ms ffff8cc78114c478 mmap_lock
3557 76.80 ms 68.75 us 21.59 us ffff8cc77ca3af58
1 68.27 ms 68.27 ms 68.27 ms ffff8cda745dfd70
9 54.53 ms 7.96 ms 6.06 ms ffff8cc7642a48b8 mmap_lock
14629 44.01 ms 60.00 us 3.01 us ffff8cc7625f9ca0
3481 42.63 ms 140.71 us 12.24 us ffffffff937906ac vmap_area_lock
16194 38.73 ms 42.15 us 2.39 us ffff8cd397cbc560
11 38.44 ms 10.39 ms 3.49 ms ffff8ccd6d12fbb8 mmap_lock
1 5.43 ms 5.43 ms 5.43 ms ffff8cd70018f0d8
1674 5.38 ms 422.93 us 3.21 us ffffffff92e06080 tasklist_lock
581 4.51 ms 130.68 us 7.75 us ffff8cc9b1259058
5 3.52 ms 1.27 ms 703.23 us ffff8cc754510070
112 3.47 ms 56.47 us 31.02 us ffff8ccee38b3120
381 3.31 ms 73.44 us 8.69 us ffffffff93790690 purge_vmap_area_lock
255 3.19 ms 36.35 us 12.49 us ffff8d053ce30c80
- Update default map size to 16384.
- Allocate single letter option -M for --map-nr-entries, as it is
proving being frequently used.
- Fix struct rq lock access for older kernels with BPF's CO-RE
(Compile once, run everywhere).
- Fix problems found with MSAn.
perf report/top:
- Add inline information when using --call-graph=fp or lbr, as was
already done to the --call-graph=dwarf callchain mode.
- Improve the 'srcfile' sort key performance by really using an
optimization introduced in 6.2 for the 'srcline' sort key that
avoids calling addr2line for comparision with each sample.
perf sched:
- Make 'perf sched latency/map/replay' to use "sched:sched_waking"
instead of "sched:sched_waking", consistent with 'perf record'
since d566a9c2d482 ("perf sched: Prefer sched_waking event when it
exists").
perf ftrace:
- Make system wide the default target for latency subcommand, run the
following command then generate some network traffic and press
control+C:
# perf ftrace latency -T __kfree_skb
^C
DURATION | COUNT | GRAPH |
0 - 1 us | 27 | ############# |
1 - 2 us | 22 | ########### |
2 - 4 us | 8 | #### |
4 - 8 us | 5 | ## |
8 - 16 us | 24 | ############ |
16 - 32 us | 2 | # |
32 - 64 us | 1 | |
64 - 128 us | 0 | |
128 - 256 us | 0 | |
256 - 512 us | 0 | |
512 - 1024 us | 0 | |
1 - 2 ms | 0 | |
2 - 4 ms | 0 | |
4 - 8 ms | 0 | |
8 - 16 ms | 0 | |
16 - 32 ms | 0 | |
32 - 64 ms | 0 | |
64 - 128 ms | 0 | |
128 - 256 ms | 0 | |
256 - 512 ms | 0 | |
512 - 1024 ms | 0 | |
1 - ... s | 0 | |
#
perf top:
- Add --branch-history (LBR: Last Branch Record) option, just like
already available for 'perf record'.
- Fix segfault in thread__comm_len() where thread->comm was being
used outside thread->comm_lock.
perf annotate:
- Allow configuring objdump and addr2line in ~/.perfconfig., so that
you can use alternative binaries, such as llvm's.
perf kvm:
- Add TUI mode for 'perf kvm stat report'.
Reference counting:
- Add reference count checking infrastructure to check for use after
free, done to the 'cpumap', 'namespaces', 'maps' and 'map' structs,
more to come.
To build with it use -DREFCNT_CHECKING=1 in the make command line
to build tools/perf. Documented at:
https://perf.wiki.kernel.org/index.php/Reference_Count_Checking
- The above caught, for instance, fix, present in this series:
- Fix maps use after put in 'perf test "Share thread maps"':
'maps' is copied from leader, but the leader is put on line 79
and then 'maps' is used to read the reference count below - so
a use after put, with the put of maps happening within
thread__put.
Fixed by reversing the order of puts so that the leader is put
last.
- Also several fixes were made to places where reference counts were
not being held.
- Make this one of the tests in 'make -C tools/perf build-test' to
regularly build test it and to make sure no direct access to the
reference counted structs are made, doing that via accessors to
check the validity of the struct pointer.
ARM64:
- Fix 'perf report' segfault when filtering coresight traces by
sparse lists of CPUs.
- Add support for 'simd' as a sort field for 'perf report', to show
ARM's NEON SIMD's predicate flags: "partial" and "empty".
arm64 vendor events:
- Add N1 metrics.
Intel vendor events:
- Add graniterapids, grandridge and sierraforrest events.
- Refresh events for: alderlake, aldernaken, broadwell, broadwellde,
broadwellx, cascadelakx, haswell, haswellx, icelake, icelakex,
jaketown, meteorlake, knightslanding, sandybridge, sapphirerapids,
silvermont, skylake, tigerlake and westmereep-dp
- Refresh metrics for alderlake-n, broadwell, broadwellde,
broadwellx, haswell, haswellx, icelakex, ivybridge, ivytown and
skylakex.
perf stat:
- Implement --topdown using JSON metrics.
- Add TopdownL1 JSON metric as a default if present, but disable it
for now for some Intel hybrid architectures, a series of patches
addressing this is being reviewed and will be submitted for v6.5.
- Use metrics for --smi-cost.
- Update topdown documentation.
Vendor events (JSON) infrastructure:
- Add support for computing and printing metric threshold values. For
instance, here is one found in thesapphirerapids json file:
{
"BriefDescription": "Percentage of cycles spent in System Management Interrupts.",
"MetricExpr": "((msr@aperf@ - cycles) / msr@aperf@ if msr@smi@ > 0 else 0)",
"MetricGroup": "smi",
"MetricName": "smi_cycles",
"MetricThreshold": "smi_cycles > 0.1",
"ScaleUnit": "100%"
},
- Test parsing metric thresholds with the fake PMU in 'perf test
pmu-events'.
- Support for printing metric thresholds in 'perf list'.
- Add --metric-no-threshold option to 'perf stat'.
- Add rand (reverse and) and has_pmem (optane memory) support to
metrics.
- Sort list of input files to avoid depending on the order from
readdir() helping in obtaining reproducible builds.
S/390:
- Add common metrics: - CPI (cycles per instruction), prbstate (ratio
of instructions executed in problem state compared to total number
of instructions), l1mp (Level one instruction and data cache misses
per 100 instructions).
- Add cache metrics for z13, z14, z15 and z16.
- Add metric for TLB and cache.
ARM:
- Add raw decoding for SPE (Statistical Profiling Extension) v1.3 MTE
(Memory Tagging Extension) and MOPS (Memory Operations) load/store.
Intel PT hardware tracing:
- Add event type names UINTR (User interrupt delivered) and UIRET
(Exiting from user interrupt routine), documented in table 32-50
"CFE Packet Type and Vector Fields Details" in the Intel Processor
Trace chapter of The Intel SDM Volume 3 version 078.
- Add support for new branch instructions ERETS and ERETU.
- Fix CYC timestamps after standalone CBR
ARM CoreSight hardware tracing:
- Allow user to override timestamp and contextid settings.
- Fix segfault in dso lookup.
- Fix timeless decode mode detection.
- Add separate decode paths for timeless and per-thread modes.
auxtrace:
- Fix address filter entire kernel size.
Miscellaneous:
- Fix use-after-free and unaligned bugs in the PLT handling routines.
- Use zfree() to reduce chances of use after free.
- Add missing 0x prefix for addresses printed in hexadecimal in 'perf
probe'.
- Suppress massive unsupported target platform errors in the unwind
code.
- Fix return incorrect build_id size in elf_read_build_id().
- Fix 'perf scripts intel-pt-events.py' IPC output for Python 2 .
- Add missing new parameter in kfree_skb tracepoint to the python
scripts using it.
- Add 'perf bench syscall fork' benchmark.
- Add support for printing PERF_MEM_LVLNUM_UNC (Uncached access) in
'perf mem'.
- Fix wrong size expectation for perf test 'Setup struct
perf_event_attr' caused by the patch adding
perf_event_attr::config3.
- Fix some spelling mistakes"
* tag 'perf-tools-for-v6.4-3-2023-05-06' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux: (365 commits)
Revert "perf build: Make BUILD_BPF_SKEL default, rename to NO_BPF_SKEL"
Revert "perf build: Warn for BPF skeletons if endian mismatches"
perf metrics: Fix SEGV with --for-each-cgroup
perf bpf skels: Stop using vmlinux.h generated from BTF, use subset of used structs + CO-RE
perf stat: Separate bperf from bpf_profiler
perf test record+probe_libc_inet_pton: Fix call chain match on x86_64
perf test record+probe_libc_inet_pton: Fix call chain match on s390
perf tracepoint: Fix memory leak in is_valid_tracepoint()
perf cs-etm: Add fix for coresight trace for any range of CPUs
perf build: Fix unescaped # in perf build-test
perf unwind: Suppress massive unsupported target platform errors
perf script: Add new parameter in kfree_skb tracepoint to the python scripts using it
perf script: Print raw ip instead of binary offset for callchain
perf symbols: Fix return incorrect build_id size in elf_read_build_id()
perf list: Modify the warning message about scandirat(3)
perf list: Fix memory leaks in print_tracepoint_events()
perf lock contention: Rework offset calculation with BPF CO-RE
perf lock contention: Fix struct rq lock access
perf stat: Disable TopdownL1 on hybrid
perf stat: Avoid SEGV on counter->name
...
Diffstat (limited to 'tools/perf/tests')
32 files changed, 457 insertions, 228 deletions
diff --git a/tools/perf/tests/api-io.c b/tools/perf/tests/api-io.c index e91cf2c127f1..0ba3d5ccebcf 100644 --- a/tools/perf/tests/api-io.c +++ b/tools/perf/tests/api-io.c @@ -12,6 +12,7 @@ #include "tests.h" #include <api/io.h> #include <linux/kernel.h> +#include <linux/zalloc.h> #define TEMPL "/tmp/perf-test-XXXXXX" @@ -79,7 +80,7 @@ static int setup_test(char path[PATH_MAX], const char *contents, static void cleanup_test(char path[PATH_MAX], struct io *io) { - free(io->buf); + zfree(&io->buf); close(io->fd); unlink(path); } @@ -289,6 +290,40 @@ static int test_get_dec(void) return ret; } +static int test_get_line(void) +{ + char path[PATH_MAX]; + struct io io; + char test_string[1024]; + char *line = NULL; + size_t i, line_len = 0; + size_t buf_size = 128; + int ret = 0; + + for (i = 0; i < 512; i++) + test_string[i] = 'a'; + test_string[512] = '\n'; + for (i = 513; i < 1023; i++) + test_string[i] = 'b'; + test_string[1023] = '\0'; + + if (setup_test(path, test_string, buf_size, &io)) + return -1; + + EXPECT_EQUAL((int)io__getline(&io, &line, &line_len), 513); + EXPECT_EQUAL((int)strlen(line), 513); + for (i = 0; i < 512; i++) + EXPECT_EQUAL(line[i], 'a'); + EXPECT_EQUAL(line[512], '\n'); + EXPECT_EQUAL((int)io__getline(&io, &line, &line_len), 510); + for (i = 0; i < 510; i++) + EXPECT_EQUAL(line[i], 'b'); + + free(line); + cleanup_test(path, &io); + return ret; +} + static int test__api_io(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { @@ -300,6 +335,8 @@ static int test__api_io(struct test_suite *test __maybe_unused, ret = TEST_FAIL; if (test_get_dec()) ret = TEST_FAIL; + if (test_get_line()) + ret = TEST_FAIL; return ret; } diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record index 3ef07a12aa14..27c21271a16c 100644 --- a/tools/perf/tests/attr/base-record +++ b/tools/perf/tests/attr/base-record @@ -5,7 +5,7 @@ group_fd=-1 flags=0|8 cpu=* type=0|1 -size=128 +size=136 config=0 sample_period=* sample_type=263 diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat index 408164456530..a21fb65bc012 100644 --- a/tools/perf/tests/attr/base-stat +++ b/tools/perf/tests/attr/base-stat @@ -5,7 +5,7 @@ group_fd=-1 flags=0|8 cpu=* type=0 -size=128 +size=136 config=0 sample_period=0 sample_type=65536 diff --git a/tools/perf/tests/attr/system-wide-dummy b/tools/perf/tests/attr/system-wide-dummy index 8fec06eda5f9..2f3e3eb728eb 100644 --- a/tools/perf/tests/attr/system-wide-dummy +++ b/tools/perf/tests/attr/system-wide-dummy @@ -7,7 +7,7 @@ cpu=* pid=-1 flags=8 type=1 -size=128 +size=136 config=9 sample_period=4000 sample_type=455 diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index ae9223f27cfb..8beb46066034 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c @@ -153,7 +153,6 @@ static int do_test(struct bpf_object *obj, int (*func)(void), } evlist__splice_list_tail(evlist, &parse_state.list); - evlist->core.nr_groups = parse_state.nr_groups; evlist__config(evlist, &opts, NULL); diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 35cc3807cc9e..b89d69afcef0 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -256,8 +256,8 @@ static int run_test(struct test_suite *test, int subtest) } #define for_each_test(j, k, t) \ - for (j = 0; j < ARRAY_SIZE(tests); j++) \ - for (k = 0, t = tests[j][k]; tests[j][k]; k++, t = tests[j][k]) + for (j = 0, k = 0; j < ARRAY_SIZE(tests); j++, k = 0) \ + while ((t = tests[j][k++]) != NULL) static int test_and_print(struct test_suite *t, int subtest) { diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index cb8cd09938d5..efe026a35010 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -236,26 +236,27 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, const char *objdump_name; char decomp_name[KMOD_DECOMP_LEN]; bool decomp = false; - int ret; + int ret, err = 0; + struct dso *dso; pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); - if (!thread__find_map(thread, cpumode, addr, &al) || !al.map->dso) { + if (!thread__find_map(thread, cpumode, addr, &al) || !map__dso(al.map)) { if (cpumode == PERF_RECORD_MISC_HYPERVISOR) { pr_debug("Hypervisor address can not be resolved - skipping\n"); - return 0; + goto out; } pr_debug("thread__find_map failed\n"); - return -1; + err = -1; + goto out; } + dso = map__dso(al.map); + pr_debug("File is: %s\n", dso->long_name); - pr_debug("File is: %s\n", al.map->dso->long_name); - - if (al.map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && - !dso__is_kcore(al.map->dso)) { + if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && !dso__is_kcore(dso)) { pr_debug("Unexpected kernel address - skipping\n"); - return 0; + goto out; } pr_debug("On file address is: %#"PRIx64"\n", al.addr); @@ -264,49 +265,53 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, len = BUFSZ; /* Do not go off the map */ - if (addr + len > al.map->end) - len = al.map->end - addr; + if (addr + len > map__end(al.map)) + len = map__end(al.map) - addr; /* Read the object code using perf */ - ret_len = dso__data_read_offset(al.map->dso, thread->maps->machine, + ret_len = dso__data_read_offset(dso, maps__machine(thread->maps), al.addr, buf1, len); if (ret_len != len) { pr_debug("dso__data_read_offset failed\n"); - return -1; + err = -1; + goto out; } /* * Converting addresses for use by objdump requires more information. * map__load() does that. See map__rip_2objdump() for details. */ - if (map__load(al.map)) - return -1; + if (map__load(al.map)) { + err = -1; + goto out; + } /* objdump struggles with kcore - try each map only once */ - if (dso__is_kcore(al.map->dso)) { + if (dso__is_kcore(dso)) { size_t d; for (d = 0; d < state->done_cnt; d++) { - if (state->done[d] == al.map->start) { + if (state->done[d] == map__start(al.map)) { pr_debug("kcore map tested already"); pr_debug(" - skipping\n"); - return 0; + goto out; } } if (state->done_cnt >= ARRAY_SIZE(state->done)) { pr_debug("Too many kcore maps - skipping\n"); - return 0; + goto out; } - state->done[state->done_cnt++] = al.map->start; + state->done[state->done_cnt++] = map__start(al.map); } - objdump_name = al.map->dso->long_name; - if (dso__needs_decompress(al.map->dso)) { - if (dso__decompress_kmodule_path(al.map->dso, objdump_name, + objdump_name = dso->long_name; + if (dso__needs_decompress(dso)) { + if (dso__decompress_kmodule_path(dso, objdump_name, decomp_name, sizeof(decomp_name)) < 0) { pr_debug("decompression failed\n"); - return -1; + err = -1; + goto out; } decomp = true; @@ -330,22 +335,23 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, len -= ret; if (len) { pr_debug("Reducing len to %zu\n", len); - } else if (dso__is_kcore(al.map->dso)) { + } else if (dso__is_kcore(dso)) { /* * objdump cannot handle very large segments * that may be found in kcore. */ pr_debug("objdump failed for kcore"); pr_debug(" - skipping\n"); - return 0; } else { - return -1; + err = -1; } + goto out; } } if (ret < 0) { pr_debug("read_via_objdump failed\n"); - return -1; + err = -1; + goto out; } /* The results should be identical */ @@ -355,11 +361,13 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, dump_buf(buf1, len); pr_debug("buf2 (objdump):\n"); dump_buf(buf2, len); - return -1; + err = -1; + goto out; } pr_debug("Bytes read match those read by objdump\n"); - - return 0; +out: + map__put(al.map); + return err; } static int process_sample_event(struct machine *machine, @@ -565,6 +573,7 @@ static int do_test_code_reading(bool try_kcore) pid_t pid; struct map *map; bool have_vmlinux, have_kcore, excl_kernel = false; + struct dso *dso; pid = getpid(); @@ -588,8 +597,9 @@ static int do_test_code_reading(bool try_kcore) pr_debug("map__load failed\n"); goto out_err; } - have_vmlinux = dso__is_vmlinux(map->dso); - have_kcore = dso__is_kcore(map->dso); + dso = map__dso(map); + have_vmlinux = dso__is_vmlinux(dso); + have_kcore = dso__is_kcore(dso); /* 2nd time through we just try kcore */ if (try_kcore && !have_kcore) diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index 3150fc1fed6f..b1a924314e09 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -68,7 +68,7 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong nr", perf_cpu_map__nr(map) == 2); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__cpu(map, 0).cpu == 1); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__cpu(map, 1).cpu == 256); - TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) == 1); + TEST_ASSERT_VAL("wrong refcnt", refcount_read(perf_cpu_map__refcnt(map)) == 1); perf_cpu_map__put(map); return 0; } @@ -94,7 +94,7 @@ static int process_event_range_cpus(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong nr", perf_cpu_map__nr(map) == 256); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__cpu(map, 0).cpu == 1); TEST_ASSERT_VAL("wrong cpu", perf_cpu_map__max(map).cpu == 256); - TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) == 1); + TEST_ASSERT_VAL("wrong refcnt", refcount_read(perf_cpu_map__refcnt(map)) == 1); perf_cpu_map__put(map); return 0; } diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c index 672a27f37060..9c1a1f18db75 100644 --- a/tools/perf/tests/expand-cgroup.c +++ b/tools/perf/tests/expand-cgroup.c @@ -61,7 +61,7 @@ static int test_expand_events(struct evlist *evlist, i = 0; evlist__for_each_entry(evlist, evsel) { - if (strcmp(evsel->name, ev_name[i % nr_events])) { + if (!evsel__name_is(evsel, ev_name[i % nr_events])) { pr_debug("event name doesn't match:\n"); pr_debug(" evsel[%d]: %s\n expected: %s\n", i, evsel->name, ev_name[i % nr_events]); @@ -187,8 +187,7 @@ static int expand_metric_events(void) rblist__init(&metric_events); pme_test = find_core_metrics_table("testarch", "testcpu"); - ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str, - false, false, &metric_events); + ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str, &metric_events); if (ret < 0) { pr_debug("failed to parse '%s' metric\n", metric_str); goto out; diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index a9eb1ed6bd63..cbf0e0c74906 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -154,13 +154,10 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u /* Only EVENT1 or EVENT2 need be measured depending on the value of smt_on. */ { - struct cpu_topology *topology = cpu_topology__new(); - bool smton = smt_on(topology); + bool smton = smt_on(); bool corewide = core_wide(/*system_wide=*/false, - /*user_requested_cpus=*/false, - topology); + /*user_requested_cpus=*/false); - cpu_topology__delete(topology); expr__ctx_clear(ctx); TEST_ASSERT_VAL("find ids", expr__find_ids("EVENT1 if #smt_on else EVENT2", diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c index 6f34d08b84e5..745ab18d17db 100644 --- a/tools/perf/tests/hists_common.c +++ b/tools/perf/tests/hists_common.c @@ -179,9 +179,11 @@ void print_hists_in(struct hists *hists) he = rb_entry(node, struct hist_entry, rb_node_in); if (!he->filtered) { + struct dso *dso = map__dso(he->ms.map); + pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n", i, thread__comm_str(he->thread), - he->ms.map->dso->short_name, + dso->short_name, he->ms.sym->name, he->stat.period); } @@ -206,9 +208,11 @@ void print_hists_out(struct hists *hists) he = rb_entry(node, struct hist_entry, rb_node); if (!he->filtered) { + struct dso *dso = map__dso(he->ms.map); + pr_info("%2d: entry: %8s:%5d [%-8s] %20s: period = %"PRIu64"/%"PRIu64"\n", i, thread__comm_str(he->thread), he->thread->tid, - he->ms.map->dso->short_name, + dso->short_name, he->ms.sym->name, he->stat.period, he->stat_acc ? he->stat_acc->period : 0); } diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index b42d37ff2399..8c0e3f334747 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c @@ -112,6 +112,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) } fake_samples[i].thread = al.thread; + map__put(fake_samples[i].map); fake_samples[i].map = al.map; fake_samples[i].sym = al.sym; } @@ -147,15 +148,23 @@ static void del_hist_entries(struct hists *hists) } } +static void put_fake_samples(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(fake_samples); i++) + map__put(fake_samples[i].map); +} + typedef int (*test_fn_t)(struct evsel *, struct machine *); #define COMM(he) (thread__comm_str(he->thread)) -#define DSO(he) (he->ms.map->dso->short_name) +#define DSO(he) (map__dso(he->ms.map)->short_name) #define SYM(he) (he->ms.sym->name) #define CPU(he) (he->cpu) #define PID(he) (he->thread->tid) #define DEPTH(he) (he->callchain->max_depth) -#define CDSO(cl) (cl->ms.map->dso->short_name) +#define CDSO(cl) (map__dso(cl->ms.map)->short_name) #define CSYM(cl) (cl->ms.sym->name) struct result { @@ -733,6 +742,7 @@ out: /* tear down everything */ evlist__delete(evlist); machines__exit(&machines); + put_fake_samples(); return err; } diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index 8e1ceeb9b7b6..98eff5935a1c 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c @@ -89,6 +89,7 @@ static int add_hist_entries(struct evlist *evlist, } fake_samples[i].thread = al.thread; + map__put(fake_samples[i].map); fake_samples[i].map = al.map; fake_samples[i].sym = al.sym; } @@ -101,6 +102,14 @@ out: return TEST_FAIL; } +static void put_fake_samples(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(fake_samples); i++) + map__put(fake_samples[i].map); +} + static int test__hists_filter(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { int err = TEST_FAIL; @@ -194,7 +203,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes hists__filter_by_thread(hists); /* now applying dso filter for 'kernel' */ - hists->dso_filter = fake_samples[0].map->dso; + hists->dso_filter = map__dso(fake_samples[0].map); hists__filter_by_dso(hists); if (verbose > 2) { @@ -288,7 +297,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes /* now applying all filters at once. */ hists->thread_filter = fake_samples[1].thread; - hists->dso_filter = fake_samples[1].map->dso; + hists->dso_filter = map__dso(fake_samples[1].map); hists__filter_by_thread(hists); hists__filter_by_dso(hists); @@ -322,6 +331,7 @@ out: evlist__delete(evlist); reset_output_field(); machines__exit(&machines); + put_fake_samples(); return err; } diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 14b2ff808b5e..141e2972e34f 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -6,6 +6,7 @@ #include "evsel.h" #include "evlist.h" #include "machine.h" +#include "map.h" #include "parse-events.h" #include "hists_common.h" #include "util/mmap.h" @@ -87,13 +88,14 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine) goto out; he = hists__add_entry(hists, &al, NULL, - NULL, NULL, &sample, true); + NULL, NULL, NULL, &sample, true); if (he == NULL) { addr_location__put(&al); goto out; } fake_common_samples[k].thread = al.thread; + map__put(fake_common_samples[k].map); fake_common_samples[k].map = al.map; fake_common_samples[k].sym = al.sym; } @@ -106,7 +108,7 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine) goto out; he = hists__add_entry(hists, &al, NULL, - NULL, NULL, &sample, true); + NULL, NULL, NULL, &sample, true); if (he == NULL) { addr_location__put(&al); goto out; @@ -126,11 +128,24 @@ out: return -1; } +static void put_fake_samples(void) +{ + size_t i, j; + + for (i = 0; i < ARRAY_SIZE(fake_common_samples); i++) + map__put(fake_common_samples[i].map); + for (i = 0; i < ARRAY_SIZE(fake_samples); i++) { + for (j = 0; j < ARRAY_SIZE(fake_samples[0]); j++) + map__put(fake_samples[i][j].map); + } +} + static int find_sample(struct sample *samples, size_t nr_samples, struct thread *t, struct map *m, struct symbol *s) { while (nr_samples--) { - if (samples->thread == t && samples->map == m && + if (samples->thread == t && + RC_CHK_ACCESS(samples->map) == RC_CHK_ACCESS(m) && samples->sym == s) return 1; samples++; @@ -336,6 +351,7 @@ out: evlist__delete(evlist); reset_output_field(); machines__exit(&machines); + put_fake_samples(); return err; } diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index 62b0093253e3..cebd5226bb12 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c @@ -78,6 +78,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) } fake_samples[i].thread = al.thread; + map__put(fake_samples[i].map); fake_samples[i].map = al.map; fake_samples[i].sym = al.sym; } @@ -113,10 +114,18 @@ static void del_hist_entries(struct hists *hists) } } +static void put_fake_samples(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(fake_samples); i++) + map__put(fake_samples[i].map); +} + typedef int (*test_fn_t)(struct evsel *, struct machine *); #define COMM(he) (thread__comm_str(he->thread)) -#define DSO(he) (he->ms.map->dso->short_name) +#define DSO(he) (map__dso(he->ms.map)->short_name) #define SYM(he) (he->ms.sym->name) #define CPU(he) (he->cpu) #define PID(he) (he->thread->tid) @@ -620,6 +629,7 @@ out: /* tear down everything */ evlist__delete(evlist); machines__exit(&machines); + put_fake_samples(); return err; } diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 009d6efb673c..8dd3f8090352 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -62,18 +62,19 @@ lib = lib endif has = $(shell which $1 2>/dev/null) +python_perf_so := $(shell $(MAKE) python_perf_target|grep "Target is:"|awk '{print $$3}') # standard single make variable specified make_clean_all := clean all -make_python_perf_so := python/perf.so +make_python_perf_so := $(python_perf_so) make_debug := DEBUG=1 +make_nondistro := BUILD_NONDISTRO=1 make_no_libperl := NO_LIBPERL=1 make_no_libpython := NO_LIBPYTHON=1 make_no_scripts := NO_LIBPYTHON=1 NO_LIBPERL=1 -make_no_newt := NO_NEWT=1 make_no_slang := NO_SLANG=1 make_no_gtk2 := NO_GTK2=1 -make_no_ui := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1 +make_no_ui := NO_SLANG=1 NO_GTK2=1 make_no_demangle := NO_DEMANGLE=1 make_no_libelf := NO_LIBELF=1 make_no_libunwind := NO_LIBUNWIND=1 @@ -92,8 +93,9 @@ make_with_coresight := CORESIGHT=1 make_no_sdt := NO_SDT=1 make_no_syscall_tbl := NO_SYSCALL_TABLE=1 make_with_clangllvm := LIBCLANGLLVM=1 -make_with_libpfm4 := LIBPFM4=1 +make_no_libpfm4 := NO_LIBPFM4=1 make_with_gtk2 := GTK2=1 +make_refcnt_check := EXTRA_CFLAGS="-DREFCNT_CHECKING=1" make_tags := tags make_cscope := cscope make_help := help @@ -110,10 +112,10 @@ make_install_info := install-info make_install_pdf := install-pdf make_install_prefix := install prefix=/tmp/krava make_install_prefix_slash := install prefix=/tmp/krava/ -make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1 +make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1 NO_LIBTRACEEVENT=1 NO_LIBELF=1 # all the NO_* variable combined -make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 +make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_GTK2=1 make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 @@ -133,10 +135,10 @@ MAKE_F := $(MAKE) -f $(MK) endif run += make_python_perf_so run += make_debug +run += make_nondistro run += make_no_libperl run += make_no_libpython run += make_no_scripts -run += make_no_newt run += make_no_slang run += make_no_gtk2 run += make_no_ui @@ -150,7 +152,6 @@ run += make_no_libaudit run += make_no_libbionic run += make_no_auxtrace run += make_no_libbpf -run += make_libbpf_dynamic run += make_no_libbpf_DEBUG run += make_no_libcrypto run += make_no_sdt @@ -158,7 +159,8 @@ run += make_no_syscall_tbl run += make_with_babeltrace run += make_with_coresight run += make_with_clangllvm -run += make_with_libpfm4 +run += make_no_libpfm4 +run += make_refcnt_check run += make_help run += make_doc run += make_perf_o @@ -176,6 +178,12 @@ run += make_install_prefix_slash # run += make_install_pdf run += make_minimal +old_libbpf := $(shell echo '\#include <bpf/libbpf.h>' | $(CC) -E -dM -x c -| egrep -q "define[[:space:]]+LIBBPF_MAJOR_VERSION[[:space:]]+0{1}") + +ifneq ($(old_libbpf),) +run += make_libbpf_dynamic +endif + ifneq ($(call has,ctags),) run += make_tags endif @@ -204,7 +212,7 @@ test_make_doc := $(test_ok) test_make_help_O := $(test_ok) test_make_doc_O := $(test_ok) -test_make_python_perf_so := test -f $(PERF_O)/python/perf.so +test_make_python_perf_so := test -f $(PERF_O)/$(python_perf_so) test_make_perf_o := test -f $(PERF_O)/perf.o test_make_util_map_o := test -f $(PERF_O)/util/map.o diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c index a69988a89d26..8c0eb5cf8bb5 100644 --- a/tools/perf/tests/maps.c +++ b/tools/perf/tests/maps.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include <inttypes.h> #include <linux/compiler.h> #include <linux/kernel.h> #include "tests.h" @@ -15,22 +16,44 @@ struct map_def { static int check_maps(struct map_def *merged, unsigned int size, struct maps *maps) { - struct map *map; + struct map_rb_node *rb_node; unsigned int i = 0; - - maps__for_each_entry(maps, map) { - if (i > 0) - TEST_ASSERT_VAL("less maps expected", (map && i < size) || (!map && i == size)); - - TEST_ASSERT_VAL("wrong map start", map->start == merged[i].start); - TEST_ASSERT_VAL("wrong map end", map->end == merged[i].end); - TEST_ASSERT_VAL("wrong map name", !strcmp(map->dso->name, merged[i].name)); - TEST_ASSERT_VAL("wrong map refcnt", refcount_read(&map->refcnt) == 1); - - i++; + bool failed = false; + + if (maps__nr_maps(maps) != size) { + pr_debug("Expected %d maps, got %d", size, maps__nr_maps(maps)); + failed = true; + } else { + maps__for_each_entry(maps, rb_node) { + struct map *map = rb_node->map; + + if (map__start(map) != merged[i].start || + map__end(map) != merged[i].end || + strcmp(map__dso(map)->name, merged[i].name) || + refcount_read(map__refcnt(map)) != 1) { + failed = true; + } + i++; + } } - - return TEST_OK; + if (failed) { + pr_debug("Expected:\n"); + for (i = 0; i < size; i++) { + pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: 1\n", + merged[i].start, merged[i].end, merged[i].name); + } + pr_debug("Got:\n"); + maps__for_each_entry(maps, rb_node) { + struct map *map = rb_node->map; + + pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: %d\n", + map__start(map), + map__end(map), + map__dso(map)->name, + refcount_read(map__refcnt(map))); + } + } + return failed ? TEST_FAIL : TEST_OK; } static int test__maps__merge_in(struct test_suite *t __maybe_unused, int subtest __maybe_unused) @@ -72,9 +95,9 @@ static int test__maps__merge_in(struct test_suite *t __maybe_unused, int subtest map = dso__new_map(bpf_progs[i].name); TEST_ASSERT_VAL("failed to create map", map); - map->start = bpf_progs[i].start; - map->end = bpf_progs[i].end; - maps__insert(maps, map); + map__set_start(map, bpf_progs[i].start); + map__set_end(map, bpf_progs[i].end); + TEST_ASSERT_VAL("failed to insert map", maps__insert(maps, map) == 0); map__put(map); } @@ -88,16 +111,16 @@ static int test__maps__merge_in(struct test_suite *t __maybe_unused, int subtest TEST_ASSERT_VAL("failed to create map", map_kcore3); /* kcore1 map overlaps over all bpf maps */ - map_kcore1->start = 100; - map_kcore1->end = 1000; + map__set_start(map_kcore1, 100); + map__set_end(map_kcore1, 1000); /* kcore2 map hides behind bpf_prog_2 */ - map_kcore2->start = 550; - map_kcore2->end = 570; + map__set_start(map_kcore2, 550); + map__set_end(map_kcore2, 570); /* kcore3 map hides behind bpf_prog_3, kcore1 and adds new map */ - map_kcore3->start = 880; - map_kcore3->end = 1100; + map__set_start(map_kcore3, 880); + map__set_end(map_kcore3, 1100); ret = maps__merge_in(maps, map_kcore1); TEST_ASSERT_VAL("failed to merge map", !ret); diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c index a4301fc7b770..898eda55b7a8 100644 --- a/tools/perf/tests/mmap-thread-lookup.c +++ b/tools/perf/tests/mmap-thread-lookup.c @@ -202,7 +202,8 @@ static int mmap_events(synth_cb synth) break; } - pr_debug("map %p, addr %" PRIx64 "\n", al.map, al.map->start); + pr_debug("map %p, addr %" PRIx64 "\n", al.map, map__start(al.map)); + map__put(al.map); } machine__delete_threads(machine); diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 71a5cb343311..8068cfd89b84 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -53,7 +53,7 @@ static int test__checkevent_tracepoint(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 0 == evlist__nr_groups(evlist)); TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type); TEST_ASSERT_VAL("wrong sample_type", PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); @@ -66,7 +66,7 @@ static int test__checkevent_tracepoint_multi(struct evlist *evlist) struct evsel *evsel; TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries > 1); - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 0 == evlist__nr_groups(evlist)); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_VAL("wrong type", @@ -449,6 +449,7 @@ static int test__checkevent_pmu(struct evlist *evlist) TEST_ASSERT_VAL("wrong config", 10 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong config1", 1 == evsel->core.attr.config1); TEST_ASSERT_VAL("wrong config2", 3 == evsel->core.attr.config2); + TEST_ASSERT_VAL("wrong config3", 0 == evsel->core.attr.config3); /* * The period value gets configured within evlist__config, * while this test executes only parse events method. @@ -470,6 +471,7 @@ static int test__checkevent_list(struct evlist *evlist) TEST_ASSERT_VAL("wrong config", 1 == evsel->core.attr.config); TEST_ASSERT_VAL("wrong config1", 0 == evsel->core.attr.config1); TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2); + TEST_ASSERT_VAL("wrong config3", 0 == evsel->core.attr.config3); TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -632,6 +634,15 @@ static int test__checkterms_simple(struct list_head *terms) TEST_ASSERT_VAL("wrong val", term->val.num == 3); TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "config2")); + /* config3=4 */ + term = list_entry(term->list.next, struct parse_events_term, list); + TEST_ASSERT_VAL("wrong type term", + term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG3); + TEST_ASSERT_VAL("wrong type val", + term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); + TEST_ASSERT_VAL("wrong val", term->val.num == 4); + TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "config3")); + /* umask=1*/ term = list_entry(term->list.next, struct parse_events_term, list); TEST_ASSERT_VAL("wrong type term", @@ -677,7 +688,7 @@ static int test__group1(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* instructions:k */ evsel = leader = evlist__first(evlist); @@ -719,7 +730,7 @@ static int test__group2(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* faults + :ku modifier */ evsel = leader = evlist__first(evlist); @@ -775,7 +786,7 @@ static int test__group3(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 2 == evlist__nr_groups(evlist)); /* group1 syscalls:sys_enter_openat:H */ evsel = leader = evlist__first(evlist); @@ -868,7 +879,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* cycles:u + p */ evsel = leader = evlist__first(evlist); @@ -912,7 +923,7 @@ static int test__group5(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 2 == evlist__nr_groups(evlist)); /* cycles + G */ evsel = leader = evlist__first(evlist); @@ -998,7 +1009,7 @@ static int test__group_gh1(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* cycles + :H group modifier */ evsel = leader = evlist__first(evlist); @@ -1038,7 +1049,7 @@ static int test__group_gh2(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* cycles + :G group modifier */ evsel = leader = evlist__first(evlist); @@ -1078,7 +1089,7 @@ static int test__group_gh3(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* cycles:G + :u group modifier */ evsel = leader = evlist__first(evlist); @@ -1118,7 +1129,7 @@ static int test__group_gh4(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); /* cycles:G + :uG group modifier */ evsel = leader = evlist__first(evlist); @@ -1390,7 +1401,7 @@ static int test__checkevent_config_symbol(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "insn") == 0); + TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "insn")); return TEST_OK; } @@ -1398,7 +1409,7 @@ static int test__checkevent_config_raw(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "rawpmu") == 0); + TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "rawpmu")); return TEST_OK; } @@ -1406,7 +1417,7 @@ static int test__checkevent_config_num(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "numpmu") == 0); + TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "numpmu")); return TEST_OK; } @@ -1414,7 +1425,7 @@ static int test__checkevent_config_cache(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "cachepmu") == 0); + TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "cachepmu")); return TEST_OK; } @@ -1427,7 +1438,7 @@ static int test__intel_pt(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "intel_pt//u") == 0); + TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "intel_pt//u")); return TEST_OK; } @@ -1435,7 +1446,7 @@ static int test__checkevent_complex_name(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong complex name parsing", strcmp(evsel->name, "COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks") == 0); + TEST_ASSERT_VAL("wrong complex name parsing", evsel__name_is(evsel, "COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks")); return TEST_OK; } @@ -2004,7 +2015,7 @@ struct terms_test { static const struct terms_test test__terms[] = { [0] = { - .str = "config=10,config1,config2=3,umask=1,read,r0xead", + .str = "config=10,config1,config2=3,config3=4,umask=1,read,r0xead", .check = test__checkterms_simple, }, }; @@ -2103,7 +2114,7 @@ static int test_event_fake_pmu(const char *str) parse_events_error__init(&err); perf_pmu__test_parse_init(); - ret = __parse_events(evlist, str, &err, &perf_pmu__fake); + ret = __parse_events(evlist, str, &err, &perf_pmu__fake, /*warn_if_reordered=*/true); if (ret) { pr_debug("failed to parse event '%s', err %d, str '%s'\n", str, ret, err.str); diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c index 9fec6040950c..1185b79e6274 100644 --- a/tools/perf/tests/parse-metric.c +++ b/tools/perf/tests/parse-metric.c @@ -30,23 +30,22 @@ static u64 find_value(const char *name, struct value *values) return 0; } -static void load_runtime_stat(struct runtime_stat *st, struct evlist *evlist, - struct value *vals) +static void load_runtime_stat(struct evlist *evlist, struct value *vals) { struct evsel *evsel; u64 count; - perf_stat__reset_shadow_stats(); + evlist__alloc_aggr_stats(evlist, 1); evlist__for_each_entry(evlist, evsel) { count = find_value(evsel->name, vals); - perf_stat__update_shadow_stats(evsel, count, 0, st); - if (!strcmp(evsel->name, "duration_time")) + evsel->stats->aggr->counts.val = count; + if (evsel__name_is(evsel, "duration_time")) update_stats(&walltime_nsecs_stats, count); } } static double compute_single(struct rblist *metric_events, struct evlist *evlist, - struct runtime_stat *st, const char *name) + const char *name) { struct metric_expr *mexp; struct metric_event *me; @@ -58,7 +57,7 @@ static double compute_single(struct rblist *metric_events, struct evlist *evlist list_for_each_entry (mexp, &me->head, nd) { if (strcmp(mexp->metric_name, name)) continue; - return test_generic_metric(mexp, 0, st); + return test_generic_metric(mexp, 0); } } } @@ -74,7 +73,6 @@ static int __compute_metric(const char *name, struct value *vals, }; const struct pmu_metrics_table *pme_test; struct perf_cpu_map *cpus; - struct runtime_stat st; struct evlist *evlist; int err; @@ -93,12 +91,10 @@ static int __compute_metric(const char *name, struct value *vals, } perf_evlist__set_maps(&evlist->core, cpus, NULL); - runtime_stat__init(&st); /* Parse the metric into metric_events list. */ pme_test = find_core_metrics_table("testarch", "testcpu"); err = metricgroup__parse_groups_test(evlist, pme_test, name, - false, false, &metric_events); if (err) goto out; @@ -108,18 +104,17 @@ static int __compute_metric(const char *name, struct value *vals, goto out; /* Load the runtime stats with given numbers for events. */ - load_runtime_stat(&st, evlist, vals); + load_runtime_stat(evlist, vals); /* And execute the metric */ if (name1 && ratio1) - *ratio1 = compute_single(&metric_events, evlist, &st, name1); + *ratio1 = compute_single(&metric_events, evlist, name1); if (name2 && ratio2) - *ratio2 = compute_single(&metric_events, evlist, &st, name2); + *ratio2 = compute_single(&metric_events, evlist, name2); out: /* ... cleanup. */ metricgroup__rblist_exit(&metric_events); - runtime_stat__exit(&st); evlist__free_stats(evlist); perf_cpu_map__put(cpus); evlist__delete(evlist); diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c index 71b76deb1f92..2e38dfa34b6c 100644 --- a/tools/perf/tests/pfm.c +++ b/tools/perf/tests/pfm.c @@ -76,7 +76,7 @@ static int test__pfm_events(struct test_suite *test __maybe_unused, count_pfm_events(&evlist->core), table[i].nr_events); TEST_ASSERT_EQUAL(table[i].events, - evlist->core.nr_groups, + evlist__nr_groups(evlist), 0); evlist__delete(evlist); @@ -103,22 +103,22 @@ static int test__pfm_group(struct test_suite *test __maybe_unused, { .events = "{instructions}", .nr_events = 1, - .nr_groups = 1, + .nr_groups = 0, }, { .events = "{instructions},{}", .nr_events = 1, - .nr_groups = 1, + .nr_groups = 0, }, { .events = "{},{instructions}", .nr_events = 1, - .nr_groups = 1, + .nr_groups = 0, }, { .events = "{instructions},{instructions}", .nr_events = 2, - .nr_groups = 2, + .nr_groups = 0, }, { .events = "{instructions,cycles},{instructions,cycles}", @@ -161,7 +161,7 @@ static int test__pfm_group(struct test_suite *test __maybe_unused, count_pfm_events(&evlist->core), table[i].nr_events); TEST_ASSERT_EQUAL(table[i].events, - evlist->core.nr_groups, + evlist__nr_groups(evlist), table[i].nr_groups); evlist__delete(evlist); diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index accf44b3d968..1dff863b9711 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -325,20 +325,14 @@ static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event return -1; } - if (!is_same(e1->perpkg, e2->perpkg)) { - pr_debug2("testing event e1 %s: mismatched perpkg, %s vs %s\n", + if (e1->perpkg != e2->perpkg) { + pr_debug2("testing event e1 %s: mismatched perpkg, %d vs %d\n", e1->name, e1->perpkg, e2->perpkg); return -1; } - if (!is_same(e1->aggr_mode, e2->aggr_mode)) { - pr_debug2("testing event e1 %s: mismatched aggr_mode, %s vs %s\n", - e1->name, e1->aggr_mode, e2->aggr_mode); - return -1; - } - - if (!is_same(e1->deprecated, e2->deprecated)) { - pr_debug2("testing event e1 %s: mismatched deprecated, %s vs %s\n", + if (e1->deprecated != e2->deprecated) { + pr_debug2("testing event e1 %s: mismatched deprecated, %d vs %d\n", e1->name, e1->deprecated, e2->deprecated); return -1; } @@ -791,7 +785,7 @@ static int check_parse_id(const char *id, struct parse_events_error *error, */ perf_pmu__test_parse_init(); } - ret = __parse_events(evlist, dup, error, fake_pmu); + ret = __parse_events(evlist, dup, error, fake_pmu, /*warn_if_reordered=*/true); free(dup); evlist__delete(evlist); @@ -822,7 +816,6 @@ static int test__parsing_callback(const struct pmu_metric *pm, int k; struct evlist *evlist; struct perf_cpu_map *cpus; - struct runtime_stat st; struct evsel *evsel; struct rblist metric_events = { .nr_entries = 0, @@ -850,11 +843,8 @@ static int test__parsing_callback(const struct pmu_metric *pm, } perf_evlist__set_maps(&evlist->core, cpus, NULL); - runtime_stat__init(&st); - err = metricgroup__parse_groups_test(evlist, table, pm->metric_name, - false, false, - &metric_events); + err = metricgroup__parse_groups_test(evlist, table, pm->metric_name, &metric_events); if (err) { if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") || !strcmp(pm->metric_name, "M3")) { @@ -873,10 +863,10 @@ static int test__parsing_callback(const struct pmu_metric *pm, * zero when subtracted and so try to make them unique. */ k = 1; - perf_stat__reset_shadow_stats(); + evlist__alloc_aggr_stats(evlist, 1); evlist__for_each_entry(evlist, evsel) { - perf_stat__update_shadow_stats(evsel, k, 0, &st); - if (!strcmp(evsel->name, "duration_time")) + evsel->stats->aggr->counts.val = k; + if (evsel__name_is(evsel, "duration_time")) update_stats(&walltime_nsecs_stats, k); k++; } @@ -889,7 +879,7 @@ static int test__parsing_callback(const struct pmu_metric *pm, list_for_each_entry (mexp, &me->head, nd) { if (strcmp(mexp->metric_name, pm->metric_name)) continue; - pr_debug("Result %f\n", test_generic_metric(mexp, 0, &st)); + pr_debug("Result %f\n", test_generic_metric(mexp, 0)); err = 0; (*failures)--; goto out_err; @@ -904,7 +894,6 @@ out_err: /* ... cleanup. */ metricgroup__rblist_exit(&metric_events); - runtime_stat__exit(&st); evlist__free_stats(evlist); perf_cpu_map__put(cpus); evlist__delete(evlist); @@ -1027,12 +1016,34 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused, return pmu_for_each_sys_metric(test__parsing_fake_callback, NULL); } +static int test__parsing_threshold_callback(const struct pmu_metric *pm, + const struct pmu_metrics_table *table __maybe_unused, + void *data __maybe_unused) +{ + if (!pm->metric_threshold) + return 0; + return metric_parse_fake(pm->metric_name, pm->metric_threshold); +} + +static int test__parsing_threshold(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + int err = 0; + + err = pmu_for_each_core_metric(test__parsing_threshold_callback, NULL); + if (err) + return err; + + return pmu_for_each_sys_metric(test__parsing_threshold_callback, NULL); +} + static struct test_case pmu_events_tests[] = { TEST_CASE("PMU event table sanity", pmu_event_table), TEST_CASE("PMU event map aliases", aliases), TEST_CASE_REASON("Parsing of PMU event table metrics", parsing, "some metrics failed"), TEST_CASE("Parsing of PMU event table metrics with fake PMUs", parsing_fake), + TEST_CASE("Parsing of metric thresholds with fake PMUs", parsing_threshold), { .name = NULL, } }; diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c index 8507bd615e97..3cf25f883df7 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c @@ -3,6 +3,7 @@ #include "pmu.h" #include "tests.h" #include <errno.h> +#include <fcntl.h> #include <stdio.h> #include <linux/kernel.h> #include <linux/limits.h> @@ -149,10 +150,16 @@ static int test__pmu(struct test_suite *test __maybe_unused, int subtest __maybe do { struct perf_event_attr attr; + int fd; memset(&attr, 0, sizeof(attr)); - ret = perf_pmu__format_parse(format, &formats); + fd = open(format, O_DIRECTORY); + if (fd < 0) { + ret = fd; + break; + } + ret = perf_pmu__format_parse(fd, &formats); if (ret) break; diff --git a/tools/perf/tests/shell/lib/perf_json_output_lint.py b/tools/perf/tests/shell/lib/perf_json_output_lint.py index 97598d14e532..61f3059ca54b 100644 --- a/tools/perf/tests/shell/lib/perf_json_output_lint.py +++ b/tools/perf/tests/shell/lib/perf_json_output_lint.py @@ -17,9 +17,10 @@ ap.add_argument('--per-thread', action='store_true') ap.add_argument('--per-die', action='store_true') ap.add_argument('--per-node', action='store_true') ap.add_argument('--per-socket', action='store_true') +ap.add_argument('--file', type=argparse.FileType('r'), default=sys.stdin) args = ap.parse_args() -Lines = sys.stdin.readlines() +Lines = args.file.readlines() def isfloat(num): try: diff --git a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh index b4149b2db4c6..bbb5b3d185fa 100755 --- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh @@ -38,8 +38,6 @@ trace_libc_inet_pton_backtrace() { case "$(uname -m)" in s390x) eventattr='call-graph=dwarf,max-stack=4' - echo "text_to_binary_address.*\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected - echo "gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected echo "(__GI_)?getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected echo "main\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$" >> $expected ;; @@ -51,7 +49,6 @@ trace_libc_inet_pton_backtrace() { ;; *) eventattr='max-stack=3' - echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected echo ".*(\+0x[[:xdigit:]]+|\[unknown\])[[:space:]]\(.*/bin/ping.*\)$" >> $expected ;; esac diff --git a/tools/perf/tests/shell/record_offcpu.sh b/tools/perf/tests/shell/record_offcpu.sh index e01973d4e0fb..f062ae9a95e1 100755 --- a/tools/perf/tests/shell/record_offcpu.sh +++ b/tools/perf/tests/shell/record_offcpu.sh @@ -65,7 +65,7 @@ test_offcpu_child() { # perf bench sched messaging creates 400 processes if ! perf record --off-cpu -e dummy -o ${perfdata} -- \ - perf bench sched messaging -g 10 > /dev/null 2&>1 + perf bench sched messaging -g 10 > /dev/null 2>&1 then echo "Child task off-cpu test [Failed record]" err=1 diff --git a/tools/perf/tests/shell/stat+csv_output.sh b/tools/perf/tests/shell/stat+csv_output.sh index 324fc9e6edd7..fb78b6251a4e 100755 --- a/tools/perf/tests/shell/stat+csv_output.sh +++ b/tools/perf/tests/shell/stat+csv_output.sh @@ -9,6 +9,20 @@ set -e skip_test=0 csv_sep=@ +stat_output=$(mktemp /tmp/__perf_test.stat_output.csv.XXXXX) + +cleanup() { + rm -f "${stat_output}" + + trap - EXIT TERM INT +} + +trap_cleanup() { + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + function commachecker() { local -i cnt=0 @@ -30,9 +44,11 @@ function commachecker() while read line do - # Check for lines beginning with Failed - x=${line:0:6} - [ "$x" = "Failed" ] && continue + # Ignore initial "started on" comment. + x=${line:0:1} + [ "$x" = "#" ] && continue + # Ignore initial blank line. + [ "$line" = "" ] && continue # Count the number of commas x=$(echo $line | tr -d -c $csv_sep) @@ -42,7 +58,7 @@ function commachecker() echo "wrong number of fields. expected $exp in $line" 1>&2 exit 1; } - done + done < "${stat_output}" return 0 } @@ -55,7 +71,8 @@ function ParanoidAndNotRoot() check_no_args() { echo -n "Checking CSV output: no args " - perf stat -x$csv_sep true 2>&1 | commachecker --no-args + perf stat -x$csv_sep -o "${stat_output}" true + commachecker --no-args echo "[Success]" } @@ -67,27 +84,29 @@ check_system_wide() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep -a true 2>&1 | commachecker --system-wide + perf stat -x$csv_sep -a -o "${stat_output}" true + commachecker --system-wide echo "[Success]" } check_system_wide_no_aggr() { - echo -n "Checking CSV output: system wide " + echo -n "Checking CSV output: system wide no aggregation " if ParanoidAndNotRoot 0 then echo "[Skip] paranoid and not root" return fi - echo -n "Checking CSV output: system wide no aggregation " - perf stat -x$csv_sep -A -a --no-merge true 2>&1 | commachecker --system-wide-no-aggr + perf stat -x$csv_sep -A -a --no-merge -o "${stat_output}" true + commachecker --system-wide-no-aggr echo "[Success]" } check_interval() { echo -n "Checking CSV output: interval " - perf stat -x$csv_sep -I 1000 true 2>&1 | commachecker --interval + perf stat -x$csv_sep -I 1000 -o "${stat_output}" true + commachecker --interval echo "[Success]" } @@ -95,7 +114,8 @@ check_interval() check_event() { echo -n "Checking CSV output: event " - perf stat -x$csv_sep -e cpu-clock true 2>&1 | commachecker --event + perf stat -x$csv_sep -e cpu-clock -o "${stat_output}" true + commachecker --event echo "[Success]" } @@ -107,7 +127,8 @@ check_per_core() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep --per-core -a true 2>&1 | commachecker --per-core + perf stat -x$csv_sep --per-core -a -o "${stat_output}" true + commachecker --per-core echo "[Success]" } @@ -119,7 +140,8 @@ check_per_thread() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep --per-thread -a true 2>&1 | commachecker --per-thread + perf stat -x$csv_sep --per-thread -a -o "${stat_output}" true + commachecker --per-thread echo "[Success]" } @@ -131,7 +153,8 @@ check_per_die() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep --per-die -a true 2>&1 | commachecker --per-die + perf stat -x$csv_sep --per-die -a -o "${stat_output}" true + commachecker --per-die echo "[Success]" } @@ -143,7 +166,8 @@ check_per_node() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep --per-node -a true 2>&1 | commachecker --per-node + perf stat -x$csv_sep --per-node -a -o "${stat_output}" true + commachecker --per-node echo "[Success]" } @@ -155,7 +179,8 @@ check_per_socket() echo "[Skip] paranoid and not root" return fi - perf stat -x$csv_sep --per-socket -a true 2>&1 | commachecker --per-socket + perf stat -x$csv_sep --per-socket -a -o "${stat_output}" true + commachecker --per-socket echo "[Success]" } @@ -202,4 +227,5 @@ then else echo "[Skip] Skipping tests for system_wide_no_aggr, per_core, per_die and per_socket since socket id exposed via topology is invalid" fi +cleanup exit 0 diff --git a/tools/perf/tests/shell/stat+json_output.sh b/tools/perf/tests/shell/stat+json_output.sh index 2c4212c641ed..f3e4967cc72e 100755 --- a/tools/perf/tests/shell/stat+json_output.sh +++ b/tools/perf/tests/shell/stat+json_output.sh @@ -23,6 +23,20 @@ then fi fi +stat_output=$(mktemp /tmp/__perf_test.stat_output.json.XXXXX) + +cleanup() { + rm -f "${stat_output}" + + trap - EXIT TERM INT +} + +trap_cleanup() { + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + # Return true if perf_event_paranoid is > $1 and not running as root. function ParanoidAndNotRoot() { @@ -32,7 +46,8 @@ function ParanoidAndNotRoot() check_no_args() { echo -n "Checking json output: no args " - perf stat -j true 2>&1 | $PYTHON $pythonchecker --no-args + perf stat -j -o "${stat_output}" true + $PYTHON $pythonchecker --no-args --file "${stat_output}" echo "[Success]" } @@ -44,27 +59,29 @@ check_system_wide() echo "[Skip] paranoia and not root" return fi - perf stat -j -a true 2>&1 | $PYTHON $pythonchecker --system-wide + perf stat -j -a -o "${stat_output}" true + $PYTHON $pythonchecker --system-wide --file "${stat_output}" echo "[Success]" } check_system_wide_no_aggr() { - echo -n "Checking json output: system wide " + echo -n "Checking json output: system wide no aggregation " if ParanoidAndNotRoot 0 then echo "[Skip] paranoia and not root" return fi - echo -n "Checking json output: system wide no aggregation " - perf stat -j -A -a --no-merge true 2>&1 | $PYTHON $pythonchecker --system-wide-no-aggr + perf stat -j -A -a --no-merge -o "${stat_output}" true + $PYTHON $pythonchecker --system-wide-no-aggr --file "${stat_output}" echo "[Success]" } check_interval() { echo -n "Checking json output: interval " - perf stat -j -I 1000 true 2>&1 | $PYTHON $pythonchecker --interval + perf stat -j -I 1000 -o "${stat_output}" true + $PYTHON $pythonchecker --interval --file "${stat_output}" echo "[Success]" } @@ -72,7 +89,8 @@ check_interval() check_event() { echo -n "Checking json output: event " - perf stat -j -e cpu-clock true 2>&1 | $PYTHON $pythonchecker --event + perf stat -j -e cpu-clock -o "${stat_output}" true + $PYTHON $pythonchecker --event --file "${stat_output}" echo "[Success]" } @@ -84,7 +102,8 @@ check_per_core() echo "[Skip] paranoia and not root" return fi - perf stat -j --per-core -a true 2>&1 | $PYTHON $pythonchecker --per-core + perf stat -j --per-core -a -o "${stat_output}" true + $PYTHON $pythonchecker --per-core --file "${stat_output}" echo "[Success]" } @@ -96,7 +115,8 @@ check_per_thread() echo "[Skip] paranoia and not root" return fi - perf stat -j --per-thread -a true 2>&1 | $PYTHON $pythonchecker --per-thread + perf stat -j --per-thread -a -o "${stat_output}" true + $PYTHON $pythonchecker --per-thread --file "${stat_output}" echo "[Success]" } @@ -108,7 +128,8 @@ check_per_die() echo "[Skip] paranoia and not root" return fi - perf stat -j --per-die -a true 2>&1 | $PYTHON $pythonchecker --per-die + perf stat -j --per-die -a -o "${stat_output}" true + $PYTHON $pythonchecker --per-die --file "${stat_output}" echo "[Success]" } @@ -120,7 +141,8 @@ check_per_node() echo "[Skip] paranoia and not root" return fi - perf stat -j --per-node -a true 2>&1 | $PYTHON $pythonchecker --per-node + perf stat -j --per-node -a -o "${stat_output}" true + $PYTHON $pythonchecker --per-node --file "${stat_output}" echo "[Success]" } @@ -132,7 +154,8 @@ check_per_socket() echo "[Skip] paranoia and not root" return fi - perf stat -j --per-socket -a true 2>&1 | $PYTHON $pythonchecker --per-socket + perf stat -j --per-socket -a -o "${stat_output}" true + $PYTHON $pythonchecker --per-socket --file "${stat_output}" echo "[Success]" } @@ -179,4 +202,5 @@ then else echo "[Skip] Skipping tests for system_wide_no_aggr, per_core, per_die and per_socket since socket id exposed via topology is invalid" fi +cleanup exit 0 diff --git a/tools/perf/tests/shell/test_arm_coresight.sh b/tools/perf/tests/shell/test_arm_coresight.sh index 565ce525c40b..482009e17bda 100755 --- a/tools/perf/tests/shell/test_arm_coresight.sh +++ b/tools/perf/tests/shell/test_arm_coresight.sh @@ -150,6 +150,8 @@ arm_cs_etm_system_wide_test() { echo "Recording trace with system wide mode" perf record -o ${perfdata} -e cs_etm// -a -- ls > /dev/null 2>&1 + # System-wide mode should include perf samples so test for that + # instead of ls perf_script_branch_samples perf && perf_report_branch_samples perf && perf_report_instruction_samples perf @@ -182,7 +184,29 @@ arm_cs_etm_snapshot_test() { arm_cs_report "CoreSight snapshot testing" $err } +arm_cs_etm_basic_test() { + echo "Recording trace with '$*'" + perf record -o ${perfdata} "$@" -- ls > /dev/null 2>&1 + + perf_script_branch_samples ls && + perf_report_branch_samples ls && + perf_report_instruction_samples ls + + err=$? + arm_cs_report "CoreSight basic testing with '$*'" $err +} + arm_cs_etm_traverse_path_test arm_cs_etm_system_wide_test arm_cs_etm_snapshot_test + +# Test all combinations of per-thread, system-wide and normal mode with +# and without timestamps +arm_cs_etm_basic_test -e cs_etm/timestamp=0/ --per-thread +arm_cs_etm_basic_test -e cs_etm/timestamp=1/ --per-thread +arm_cs_etm_basic_test -e cs_etm/timestamp=0/ -a +arm_cs_etm_basic_test -e cs_etm/timestamp=1/ -a +arm_cs_etm_basic_test -e cs_etm/timestamp=0/ +arm_cs_etm_basic_test -e cs_etm/timestamp=1/ + exit $glb_err diff --git a/tools/perf/tests/symbols.c b/tools/perf/tests/symbols.c index 057b16df6416..2d1aa42d36a9 100644 --- a/tools/perf/tests/symbols.c +++ b/tools/perf/tests/symbols.c @@ -38,6 +38,7 @@ static int init_test_info(struct test_info *ti) static void exit_test_info(struct test_info *ti) { thread__put(ti->thread); + machine__delete_threads(ti->machine); machine__delete(ti->machine); } @@ -101,6 +102,7 @@ static int test_file(struct test_info *ti, char *filename) { struct map *map = NULL; int ret, nr; + struct dso *dso; pr_debug("Testing %s\n", filename); @@ -108,7 +110,8 @@ static int test_file(struct test_info *ti, char *filename) if (ret != TEST_OK) return ret; - nr = dso__load(map->dso, map); + dso = map__dso(map); + nr = dso__load(dso, map); if (nr < 0) { pr_debug("dso__load() failed!\n"); ret = TEST_FAIL; @@ -121,7 +124,7 @@ static int test_file(struct test_info *ti, char *filename) goto out_put; } - ret = test_dso(map->dso); + ret = test_dso(dso); out_put: map__put(map); diff --git a/tools/perf/tests/thread-maps-share.c b/tools/perf/tests/thread-maps-share.c index 84edd82c519e..858e725318a9 100644 --- a/tools/perf/tests/thread-maps-share.c +++ b/tools/perf/tests/thread-maps-share.c @@ -43,12 +43,12 @@ static int test__thread_maps_share(struct test_suite *test __maybe_unused, int s leader && t1 && t2 && t3 && other); maps = leader->maps; - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 4); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 4); /* test the maps pointer is shared */ - TEST_ASSERT_VAL("maps don't match", maps == t1->maps); - TEST_ASSERT_VAL("maps don't match", maps == t2->maps); - TEST_ASSERT_VAL("maps don't match", maps == t3->maps); + TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(maps) == RC_CHK_ACCESS(t1->maps)); + TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(maps) == RC_CHK_ACCESS(t2->maps)); + TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(maps) == RC_CHK_ACCESS(t3->maps)); /* * Verify the other leader was created by previous call. @@ -71,25 +71,25 @@ static int test__thread_maps_share(struct test_suite *test __maybe_unused, int s machine__remove_thread(machine, other_leader); other_maps = other->maps; - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_maps->refcnt), 2); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(other_maps)), 2); - TEST_ASSERT_VAL("maps don't match", other_maps == other_leader->maps); + TEST_ASSERT_VAL("maps don't match", RC_CHK_ACCESS(other_maps) == RC_CHK_ACCESS(other_leader->maps)); /* release thread group */ - thread__put(leader); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 3); - - thread__put(t1); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 2); + thread__put(t3); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 3); thread__put(t2); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&maps->refcnt), 1); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 2); - thread__put(t3); + thread__put(t1); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(maps)), 1); + + thread__put(leader); /* release other group */ thread__put(other_leader); - TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_maps->refcnt), 1); + TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(maps__refcnt(other_maps)), 1); thread__put(other); diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 8ab035b55875..1078a93b01aa 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -13,7 +13,7 @@ #include "debug.h" #include "machine.h" -#define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x)) +#define UM(x) map__unmap_ip(kallsyms_map, (x)) static bool is_ignored_symbol(const char *name, char type) { @@ -118,7 +118,8 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused int err = TEST_FAIL; struct rb_node *nd; struct symbol *sym; - struct map *kallsyms_map, *vmlinux_map, *map; + struct map *kallsyms_map, *vmlinux_map; + struct map_rb_node *rb_node; struct machine kallsyms, vmlinux; struct maps *maps; u64 mem_start, mem_end; @@ -220,8 +221,8 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused if (sym->start == sym->end) continue; - mem_start = vmlinux_map->unmap_ip(vmlinux_map, sym->start); - mem_end = vmlinux_map->unmap_ip(vmlinux_map, sym->end); + mem_start = map__unmap_ip(vmlinux_map, sym->start); + mem_end = map__unmap_ip(vmlinux_map, sym->end); first_pair = machine__find_kernel_symbol(&kallsyms, mem_start, NULL); pair = first_pair; @@ -266,7 +267,7 @@ next_pair: continue; } - } else if (mem_start == kallsyms.vmlinux_map->end) { + } else if (mem_start == map__end(kallsyms.vmlinux_map)) { /* * Ignore aliases to _etext, i.e. to the end of the kernel text area, * such as __indirect_thunk_end. @@ -290,19 +291,20 @@ next_pair: header_printed = false; - maps__for_each_entry(maps, map) { - struct map * + maps__for_each_entry(maps, rb_node) { + struct map *map = rb_node->map; + struct dso *dso = map__dso(map); /* * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while * the kernel will have the path for the vmlinux file being used, * so use the short name, less descriptive but the same ("[kernel]" in * both cases. */ - pair = maps__find_by_name(kallsyms.kmaps, (map->dso->kernel ? - map->dso->short_name : - map->dso->name)); + struct map *pair = maps__find_by_name(kallsyms.kmaps, (dso->kernel ? + dso->short_name : + dso->name)); if (pair) { - pair->priv = 1; + map__set_priv(pair, 1); } else { if (!header_printed) { pr_info("WARN: Maps only in vmlinux:\n"); @@ -314,29 +316,31 @@ next_pair: header_printed = false; - maps__for_each_entry(maps, map) { - struct map *pair; + maps__for_each_entry(maps, rb_node) { + struct map *pair, *map = rb_node->map; - mem_start = vmlinux_map->unmap_ip(vmlinux_map, map->start); - mem_end = vmlinux_map->unmap_ip(vmlinux_map, map->end); + mem_start = map__unmap_ip(vmlinux_map, map__start(map)); + mem_end = map__unmap_ip(vmlinux_map, map__end(map)); pair = maps__find(kallsyms.kmaps, mem_start); - if (pair == NULL || pair->priv) + if (pair == NULL || map__priv(pair)) continue; - if (pair->start == mem_start) { + if (map__start(pair) == mem_start) { + struct dso *dso = map__dso(map); + if (!header_printed) { pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n"); header_printed = true; } pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", - map->start, map->end, map->pgoff, map->dso->name); - if (mem_end != pair->end) + map__start(map), map__end(map), map__pgoff(map), dso->name); + if (mem_end != map__end(pair)) pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64, - pair->start, pair->end, pair->pgoff); - pr_info(" %s\n", pair->dso->name); - pair->priv = 1; + map__start(pair), map__end(pair), map__pgoff(pair)); + pr_info(" %s\n", dso->name); + map__set_priv(pair, 1); } } @@ -344,8 +348,10 @@ next_pair: maps = machine__kernel_maps(&kallsyms); - maps__for_each_entry(maps, map) { - if (!map->priv) { + maps__for_each_entry(maps, rb_node) { + struct map *map = rb_node->map; + + if (!map__priv(map)) { if (!header_printed) { pr_info("WARN: Maps only in kallsyms:\n"); header_printed = true; |