diff options
Diffstat (limited to 'tools/perf/lib/tests/test-evlist.c')
| -rw-r--r-- | tools/perf/lib/tests/test-evlist.c | 219 | 
1 files changed, 218 insertions, 1 deletions
diff --git a/tools/perf/lib/tests/test-evlist.c b/tools/perf/lib/tests/test-evlist.c index e6b2ab2e2bde..6d8ebe0c2504 100644 --- a/tools/perf/lib/tests/test-evlist.c +++ b/tools/perf/lib/tests/test-evlist.c @@ -1,12 +1,23 @@  // SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET) +#include <sched.h>  #include <stdio.h>  #include <stdarg.h> +#include <unistd.h> +#include <stdlib.h>  #include <linux/perf_event.h> +#include <linux/limits.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/prctl.h>  #include <perf/cpumap.h>  #include <perf/threadmap.h>  #include <perf/evlist.h>  #include <perf/evsel.h> +#include <perf/mmap.h> +#include <perf/event.h>  #include <internal/tests.h> +#include <api/fs/fs.h>  static int libperf_print(enum libperf_print_level level,  			 const char *fmt, va_list ap) @@ -181,6 +192,210 @@ static int test_stat_thread_enable(void)  	return 0;  } +static int test_mmap_thread(void) +{ +	struct perf_evlist *evlist; +	struct perf_evsel *evsel; +	struct perf_mmap *map; +	struct perf_cpu_map *cpus; +	struct perf_thread_map *threads; +	struct perf_event_attr attr = { +		.type             = PERF_TYPE_TRACEPOINT, +		.sample_period    = 1, +		.wakeup_watermark = 1, +		.disabled         = 1, +	}; +	char path[PATH_MAX]; +	int id, err, pid, go_pipe[2]; +	union perf_event *event; +	char bf; +	int count = 0; + +	snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id", +		 sysfs__mountpoint()); + +	if (filename__read_int(path, &id)) { +		fprintf(stderr, "error: failed to get tracepoint id: %s\n", path); +		return -1; +	} + +	attr.config = id; + +	err = pipe(go_pipe); +	__T("failed to create pipe", err == 0); + +	fflush(NULL); + +	pid = fork(); +	if (!pid) { +		int i; + +		read(go_pipe[0], &bf, 1); + +		/* Generate 100 prctl calls. */ +		for (i = 0; i < 100; i++) +			prctl(0, 0, 0, 0, 0); + +		exit(0); +	} + +	threads = perf_thread_map__new_dummy(); +	__T("failed to create threads", threads); + +	cpus = perf_cpu_map__dummy_new(); +	__T("failed to create cpus", cpus); + +	perf_thread_map__set_pid(threads, 0, pid); + +	evlist = perf_evlist__new(); +	__T("failed to create evlist", evlist); + +	evsel = perf_evsel__new(&attr); +	__T("failed to create evsel1", evsel); + +	perf_evlist__add(evlist, evsel); + +	perf_evlist__set_maps(evlist, cpus, threads); + +	err = perf_evlist__open(evlist); +	__T("failed to open evlist", err == 0); + +	err = perf_evlist__mmap(evlist, 4); +	__T("failed to mmap evlist", err == 0); + +	perf_evlist__enable(evlist); + +	/* kick the child and wait for it to finish */ +	write(go_pipe[1], &bf, 1); +	waitpid(pid, NULL, 0); + +	/* +	 * There's no need to call perf_evlist__disable, +	 * monitored process is dead now. +	 */ + +	perf_evlist__for_each_mmap(evlist, map, false) { +		if (perf_mmap__read_init(map) < 0) +			continue; + +		while ((event = perf_mmap__read_event(map)) != NULL) { +			count++; +			perf_mmap__consume(map); +		} + +		perf_mmap__read_done(map); +	} + +	/* calls perf_evlist__munmap/perf_evlist__close */ +	perf_evlist__delete(evlist); + +	perf_thread_map__put(threads); +	perf_cpu_map__put(cpus); + +	/* +	 * The generated prctl calls should match the +	 * number of events in the buffer. +	 */ +	__T("failed count", count == 100); + +	return 0; +} + +static int test_mmap_cpus(void) +{ +	struct perf_evlist *evlist; +	struct perf_evsel *evsel; +	struct perf_mmap *map; +	struct perf_cpu_map *cpus; +	struct perf_event_attr attr = { +		.type             = PERF_TYPE_TRACEPOINT, +		.sample_period    = 1, +		.wakeup_watermark = 1, +		.disabled         = 1, +	}; +	cpu_set_t saved_mask; +	char path[PATH_MAX]; +	int id, err, cpu, tmp; +	union perf_event *event; +	int count = 0; + +	snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id", +		 sysfs__mountpoint()); + +	if (filename__read_int(path, &id)) { +		fprintf(stderr, "error: failed to get tracepoint id: %s\n", path); +		return -1; +	} + +	attr.config = id; + +	cpus = perf_cpu_map__new(NULL); +	__T("failed to create cpus", cpus); + +	evlist = perf_evlist__new(); +	__T("failed to create evlist", evlist); + +	evsel = perf_evsel__new(&attr); +	__T("failed to create evsel1", evsel); + +	perf_evlist__add(evlist, evsel); + +	perf_evlist__set_maps(evlist, cpus, NULL); + +	err = perf_evlist__open(evlist); +	__T("failed to open evlist", err == 0); + +	err = perf_evlist__mmap(evlist, 4); +	__T("failed to mmap evlist", err == 0); + +	perf_evlist__enable(evlist); + +	err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask); +	__T("sched_getaffinity failed", err == 0); + +	perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { +		cpu_set_t mask; + +		CPU_ZERO(&mask); +		CPU_SET(cpu, &mask); + +		err = sched_setaffinity(0, sizeof(mask), &mask); +		__T("sched_setaffinity failed", err == 0); + +		prctl(0, 0, 0, 0, 0); +	} + +	err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask); +	__T("sched_setaffinity failed", err == 0); + +	perf_evlist__disable(evlist); + +	perf_evlist__for_each_mmap(evlist, map, false) { +		if (perf_mmap__read_init(map) < 0) +			continue; + +		while ((event = perf_mmap__read_event(map)) != NULL) { +			count++; +			perf_mmap__consume(map); +		} + +		perf_mmap__read_done(map); +	} + +	/* calls perf_evlist__munmap/perf_evlist__close */ +	perf_evlist__delete(evlist); + +	/* +	 * The generated prctl events should match the +	 * number of cpus or be bigger (we are system-wide). +	 */ +	__T("failed count", count >= perf_cpu_map__nr(cpus)); + +	perf_cpu_map__put(cpus); + +	return 0; +} +  int main(int argc, char **argv)  {  	__T_START; @@ -190,7 +405,9 @@ int main(int argc, char **argv)  	test_stat_cpu();  	test_stat_thread();  	test_stat_thread_enable(); +	test_mmap_thread(); +	test_mmap_cpus(); -	__T_OK; +	__T_END;  	return 0;  }  |