linux-stable/tools/perf/tests/task-exit.c
Namhyung Kim 83d25ccde5 perf test: Fix cpu and thread map leaks in task_exit test
The evlist has the maps with its own refcounts so we don't need to set
the pointers to NULL.  Otherwise following error was reported by Asan.

Also change the goto label since it doesn't need to have two.

  # perf test -v 24
  24: Number of exit events of a simple workload :
  --- start ---
  test child forked, pid 145915
  mmap size 528384B

  =================================================================
  ==145915==ERROR: LeakSanitizer: detected memory leaks

  Direct leak of 32 byte(s) in 1 object(s) allocated from:
    #0 0x7fc44e50d1f8 in __interceptor_realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:164
    #1 0x561cf50f4d2e in perf_thread_map__realloc /home/namhyung/project/linux/tools/lib/perf/threadmap.c:23
    #2 0x561cf4eeb949 in thread_map__new_by_tid util/thread_map.c:63
    #3 0x561cf4db7fd2 in test__task_exit tests/task-exit.c:74
    #4 0x561cf4d798fb in run_test tests/builtin-test.c:428
    #5 0x561cf4d798fb in test_and_print tests/builtin-test.c:458
    #6 0x561cf4d7ba53 in __cmd_test tests/builtin-test.c:679
    #7 0x561cf4d7ba53 in cmd_test tests/builtin-test.c:825
    #8 0x561cf4de7d04 in run_builtin /home/namhyung/project/linux/tools/perf/perf.c:313
    #9 0x561cf4c71a88 in handle_internal_command /home/namhyung/project/linux/tools/perf/perf.c:365
    #10 0x561cf4c71a88 in run_argv /home/namhyung/project/linux/tools/perf/perf.c:409
    #11 0x561cf4c71a88 in main /home/namhyung/project/linux/tools/perf/perf.c:539
    #12 0x7fc44e042d09 in __libc_start_main ../csu/libc-start.c:308

    ...
  test child finished with 1
  ---- end ----
  Number of exit events of a simple workload: FAILED!

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: https://lore.kernel.org/r/20210301140409.184570-4-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-03-06 16:54:28 -03:00

153 lines
3.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include "debug.h"
#include "evlist.h"
#include "evsel.h"
#include "target.h"
#include "thread_map.h"
#include "tests.h"
#include "util/mmap.h"
#include <errno.h>
#include <signal.h>
#include <linux/string.h>
#include <perf/cpumap.h>
#include <perf/evlist.h>
#include <perf/mmap.h>
static int exited;
static int nr_exit;
static void sig_handler(int sig __maybe_unused)
{
exited = 1;
}
/*
* evlist__prepare_workload will send a SIGUSR1 if the fork fails, since
* we asked by setting its exec_error to this handler.
*/
static void workload_exec_failed_signal(int signo __maybe_unused,
siginfo_t *info __maybe_unused,
void *ucontext __maybe_unused)
{
exited = 1;
nr_exit = -1;
}
/*
* This test will start a workload that does nothing then it checks
* if the number of exit event reported by the kernel is 1 or not
* in order to check the kernel returns correct number of event.
*/
int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused)
{
int err = -1;
union perf_event *event;
struct evsel *evsel;
struct evlist *evlist;
struct target target = {
.uid = UINT_MAX,
.uses_mmap = true,
};
const char *argv[] = { "true", NULL };
char sbuf[STRERR_BUFSIZE];
struct perf_cpu_map *cpus;
struct perf_thread_map *threads;
struct mmap *md;
int retry_count = 0;
signal(SIGCHLD, sig_handler);
evlist = evlist__new_default();
if (evlist == NULL) {
pr_debug("evlist__new_default\n");
return -1;
}
/*
* Create maps of threads and cpus to monitor. In this case
* we start with all threads and cpus (-1, -1) but then in
* evlist__prepare_workload we'll fill in the only thread
* we're monitoring, the one forked there.
*/
cpus = perf_cpu_map__dummy_new();
threads = thread_map__new_by_tid(-1);
if (!cpus || !threads) {
err = -ENOMEM;
pr_debug("Not enough memory to create thread/cpu maps\n");
goto out_delete_evlist;
}
perf_evlist__set_maps(&evlist->core, cpus, threads);
err = evlist__prepare_workload(evlist, &target, argv, false, workload_exec_failed_signal);
if (err < 0) {
pr_debug("Couldn't run the workload!\n");
goto out_delete_evlist;
}
evsel = evlist__first(evlist);
evsel->core.attr.task = 1;
#ifdef __s390x__
evsel->core.attr.sample_freq = 1000000;
#else
evsel->core.attr.sample_freq = 1;
#endif
evsel->core.attr.inherit = 0;
evsel->core.attr.watermark = 0;
evsel->core.attr.wakeup_events = 1;
evsel->core.attr.exclude_kernel = 1;
err = evlist__open(evlist);
if (err < 0) {
pr_debug("Couldn't open the evlist: %s\n",
str_error_r(-err, sbuf, sizeof(sbuf)));
goto out_delete_evlist;
}
if (evlist__mmap(evlist, 128) < 0) {
pr_debug("failed to mmap events: %d (%s)\n", errno,
str_error_r(errno, sbuf, sizeof(sbuf)));
err = -1;
goto out_delete_evlist;
}
evlist__start_workload(evlist);
retry:
md = &evlist->mmap[0];
if (perf_mmap__read_init(&md->core) < 0)
goto out_init;
while ((event = perf_mmap__read_event(&md->core)) != NULL) {
if (event->header.type == PERF_RECORD_EXIT)
nr_exit++;
perf_mmap__consume(&md->core);
}
perf_mmap__read_done(&md->core);
out_init:
if (!exited || !nr_exit) {
evlist__poll(evlist, -1);
if (retry_count++ > 1000) {
pr_debug("Failed after retrying 1000 times\n");
err = -1;
goto out_delete_evlist;
}
goto retry;
}
if (nr_exit != 1) {
pr_debug("received %d EXIT records\n", nr_exit);
err = -1;
}
out_delete_evlist:
perf_cpu_map__put(cpus);
perf_thread_map__put(threads);
evlist__delete(evlist);
return err;
}