diff options
| author | Kees Cook <kees+treewide@kernel.org> | 2026-09-02 15:31:14 -0700 |
|---|---|---|
| committer | Kees Cook <kees@kernel.org> | 2026-09-04 21:37:00 -0700 |
| commit | 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d (patch) | |
| tree | c65086f9bdcd48c6360fb7cb4598bca084da1f32 /tools/perf/tests/event-times.c | |
| download | linux-stable-3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d.tar.gz linux-stable-3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d.zip | |
treewide: refresh kmalloc_obj() conversionsgrafted
This is another run of the Coccinelle script for converting kmalloc()
family of allocations to kmalloc_obj() via the existing rules in
scripts/coccinelle/api/kmalloc_objs.cocci
This catches both the set of kmalloc() uses added since the first
kmalloc_obj() conversions in v7.0 and adds a large group missed in the
first pass due to Coccinelle not interacting well with the cleanup.h
scoped_...() family of macros[1]. I worked around this with spatch's
"--macro-file" argument to a file with all the scoped_...() macros mapped
to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control
flow indicator I could find.
Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc,
riscv, and s390 with no new warnings.
Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1]
Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2]
Signed-off-by: Kees Cook <kees+treewide@kernel.org>
Diffstat (limited to 'tools/perf/tests/event-times.c')
| -rw-r--r-- | tools/perf/tests/event-times.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c new file mode 100644 index 000000000..56dd37ca7 --- /dev/null +++ b/tools/perf/tests/event-times.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/compiler.h> +#include <linux/string.h> +#include <errno.h> +#include <inttypes.h> +#include <string.h> +#include <sys/wait.h> +#include <perf/cpumap.h> +#include "tests.h" +#include "evlist.h" +#include "evsel.h" +#include "debug.h" +#include "parse-events.h" +#include "thread_map.h" +#include "target.h" + +static int attach__enable_on_exec(struct evlist *evlist) +{ + struct evsel *evsel = evlist__last(evlist); + struct target target = {}; + const char *argv[] = { "true", NULL, }; + char sbuf[STRERR_BUFSIZE]; + int err; + + pr_debug("attaching to spawned child, enable on exec\n"); + + err = evlist__create_maps(evlist, &target); + if (err < 0) { + pr_debug("Not enough memory to create thread/cpu maps\n"); + return err; + } + + err = evlist__prepare_workload(evlist, &target, argv, false, NULL); + if (err < 0) { + pr_debug("Couldn't run the workload!\n"); + return err; + } + + evsel->core.attr.enable_on_exec = 1; + + err = evlist__open(evlist); + if (err < 0) { + pr_debug("perf_evlist__open: %s\n", + str_error_r(errno, sbuf, sizeof(sbuf))); + return err; + } + + return evlist__start_workload(evlist) == 1 ? TEST_OK : TEST_FAIL; +} + +static int detach__enable_on_exec(struct evlist *evlist) +{ + waitpid(evlist__workload_pid(evlist), NULL, 0); + return 0; +} + +static int attach__current_disabled(struct evlist *evlist) +{ + struct evsel *evsel = evlist__last(evlist); + struct perf_thread_map *threads; + int err; + + pr_debug("attaching to current thread as disabled\n"); + + threads = thread_map__new_by_tid(getpid()); + if (threads == NULL) { + pr_debug("thread_map__new\n"); + return -1; + } + + evsel->core.attr.disabled = 1; + + err = evsel__open_per_thread(evsel, threads); + if (err) { + pr_debug("Failed to open event cpu-clock:u\n"); + return err; + } + + perf_thread_map__put(threads); + return evsel__enable(evsel) == 0 ? TEST_OK : TEST_FAIL; +} + +static int attach__current_enabled(struct evlist *evlist) +{ + struct evsel *evsel = evlist__last(evlist); + struct perf_thread_map *threads; + int err; + + pr_debug("attaching to current thread as enabled\n"); + + threads = thread_map__new_by_tid(getpid()); + if (threads == NULL) { + pr_debug("failed to call thread_map__new\n"); + return -1; + } + + err = evsel__open_per_thread(evsel, threads); + + perf_thread_map__put(threads); + return err == 0 ? TEST_OK : TEST_FAIL; +} + +static int detach__disable(struct evlist *evlist) +{ + struct evsel *evsel = evlist__last(evlist); + + return evsel__enable(evsel); +} + +static int attach__cpu_disabled(struct evlist *evlist) +{ + struct evsel *evsel = evlist__last(evlist); + struct perf_cpu_map *cpus; + int err; + + pr_debug("attaching to CPU 0 as enabled\n"); + + cpus = perf_cpu_map__new("0"); + if (cpus == NULL) { + pr_debug("failed to call perf_cpu_map__new\n"); + return -1; + } + + evsel->core.attr.disabled = 1; + + err = evsel__open_per_cpu(evsel, cpus, -1); + perf_cpu_map__put(cpus); + if (err) { + if (err == -EACCES) + return TEST_SKIP; + + pr_debug("Failed to open event cpu-clock:u\n"); + return err; + } + + return evsel__enable(evsel); +} + +static int attach__cpu_enabled(struct evlist *evlist) +{ + struct evsel *evsel = evlist__last(evlist); + struct perf_cpu_map *cpus; + int err; + + pr_debug("attaching to CPU 0 as enabled\n"); + + cpus = perf_cpu_map__new("0"); + if (cpus == NULL) { + pr_debug("failed to call perf_cpu_map__new\n"); + return -1; + } + + err = evsel__open_per_cpu(evsel, cpus, -1); + perf_cpu_map__put(cpus); + if (err == -EACCES) + return TEST_SKIP; + + return err ? TEST_FAIL : TEST_OK; +} + +static int test_times(int (attach)(struct evlist *), + int (detach)(struct evlist *)) +{ + struct perf_counts_values count; + struct evlist *evlist = NULL; + struct evsel *evsel; + int err = -1, i; + + evlist = evlist__new(); + if (!evlist) { + pr_debug("failed to create event list\n"); + goto out_err; + } + + err = parse_event(evlist, "cpu-clock:u"); + if (err) { + pr_debug("failed to parse event cpu-clock:u\n"); + goto out_err; + } + + evsel = evlist__last(evlist); + evsel->core.attr.read_format |= + PERF_FORMAT_TOTAL_TIME_ENABLED | + PERF_FORMAT_TOTAL_TIME_RUNNING; + + err = attach(evlist); + if (err == TEST_SKIP) { + pr_debug(" SKIP : not enough rights\n"); + evlist__put(evlist); + return err; + } + + TEST_ASSERT_VAL("failed to attach", !err); + + for (i = 0; i < 100000000; i++) { } + + TEST_ASSERT_VAL("failed to detach", !detach(evlist)); + + perf_evsel__read(&evsel->core, 0, 0, &count); + + err = !(count.ena == count.run); + + pr_debug(" %s: ena %" PRIu64", run %" PRIu64"\n", + !err ? "OK " : "FAILED", + count.ena, count.run); + +out_err: + evlist__put(evlist); + return !err ? TEST_OK : TEST_FAIL; +} + +/* + * This test creates software event 'cpu-clock' + * attaches it in several ways (explained below) + * and checks that enabled and running times + * match. + */ +static int test__event_times(struct test_suite *test __maybe_unused, int subtest __maybe_unused) +{ + int err, ret = 0; + +#define _T(attach, detach) \ + err = test_times(attach, detach); \ + if (err && (ret == TEST_OK || ret == TEST_SKIP)) \ + ret = err; + + /* attach on newly spawned process after exec */ + _T(attach__enable_on_exec, detach__enable_on_exec) + /* attach on current process as enabled */ + _T(attach__current_enabled, detach__disable) + /* attach on current process as disabled */ + _T(attach__current_disabled, detach__disable) + /* attach on cpu as disabled */ + _T(attach__cpu_disabled, detach__disable) + /* attach on cpu as enabled */ + _T(attach__cpu_enabled, detach__disable) + +#undef _T + return ret; +} + +DEFINE_SUITE("Event times", event_times); |
