cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

event-times.c (5525B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/compiler.h>
      3#include <linux/string.h>
      4#include <errno.h>
      5#include <inttypes.h>
      6#include <string.h>
      7#include <sys/wait.h>
      8#include <perf/cpumap.h>
      9#include "tests.h"
     10#include "evlist.h"
     11#include "evsel.h"
     12#include "debug.h"
     13#include "parse-events.h"
     14#include "thread_map.h"
     15#include "target.h"
     16
     17static int attach__enable_on_exec(struct evlist *evlist)
     18{
     19	struct evsel *evsel = evlist__last(evlist);
     20	struct target target = {
     21		.uid = UINT_MAX,
     22	};
     23	const char *argv[] = { "true", NULL, };
     24	char sbuf[STRERR_BUFSIZE];
     25	int err;
     26
     27	pr_debug("attaching to spawned child, enable on exec\n");
     28
     29	err = evlist__create_maps(evlist, &target);
     30	if (err < 0) {
     31		pr_debug("Not enough memory to create thread/cpu maps\n");
     32		return err;
     33	}
     34
     35	err = evlist__prepare_workload(evlist, &target, argv, false, NULL);
     36	if (err < 0) {
     37		pr_debug("Couldn't run the workload!\n");
     38		return err;
     39	}
     40
     41	evsel->core.attr.enable_on_exec = 1;
     42
     43	err = evlist__open(evlist);
     44	if (err < 0) {
     45		pr_debug("perf_evlist__open: %s\n",
     46			 str_error_r(errno, sbuf, sizeof(sbuf)));
     47		return err;
     48	}
     49
     50	return evlist__start_workload(evlist) == 1 ? TEST_OK : TEST_FAIL;
     51}
     52
     53static int detach__enable_on_exec(struct evlist *evlist)
     54{
     55	waitpid(evlist->workload.pid, NULL, 0);
     56	return 0;
     57}
     58
     59static int attach__current_disabled(struct evlist *evlist)
     60{
     61	struct evsel *evsel = evlist__last(evlist);
     62	struct perf_thread_map *threads;
     63	int err;
     64
     65	pr_debug("attaching to current thread as disabled\n");
     66
     67	threads = thread_map__new(-1, getpid(), UINT_MAX);
     68	if (threads == NULL) {
     69		pr_debug("thread_map__new\n");
     70		return -1;
     71	}
     72
     73	evsel->core.attr.disabled = 1;
     74
     75	err = evsel__open_per_thread(evsel, threads);
     76	if (err) {
     77		pr_debug("Failed to open event cpu-clock:u\n");
     78		return err;
     79	}
     80
     81	perf_thread_map__put(threads);
     82	return evsel__enable(evsel) == 0 ? TEST_OK : TEST_FAIL;
     83}
     84
     85static int attach__current_enabled(struct evlist *evlist)
     86{
     87	struct evsel *evsel = evlist__last(evlist);
     88	struct perf_thread_map *threads;
     89	int err;
     90
     91	pr_debug("attaching to current thread as enabled\n");
     92
     93	threads = thread_map__new(-1, getpid(), UINT_MAX);
     94	if (threads == NULL) {
     95		pr_debug("failed to call thread_map__new\n");
     96		return -1;
     97	}
     98
     99	err = evsel__open_per_thread(evsel, threads);
    100
    101	perf_thread_map__put(threads);
    102	return err == 0 ? TEST_OK : TEST_FAIL;
    103}
    104
    105static int detach__disable(struct evlist *evlist)
    106{
    107	struct evsel *evsel = evlist__last(evlist);
    108
    109	return evsel__enable(evsel);
    110}
    111
    112static int attach__cpu_disabled(struct evlist *evlist)
    113{
    114	struct evsel *evsel = evlist__last(evlist);
    115	struct perf_cpu_map *cpus;
    116	int err;
    117
    118	pr_debug("attaching to CPU 0 as enabled\n");
    119
    120	cpus = perf_cpu_map__new("0");
    121	if (cpus == NULL) {
    122		pr_debug("failed to call perf_cpu_map__new\n");
    123		return -1;
    124	}
    125
    126	evsel->core.attr.disabled = 1;
    127
    128	err = evsel__open_per_cpu(evsel, cpus, -1);
    129	if (err) {
    130		if (err == -EACCES)
    131			return TEST_SKIP;
    132
    133		pr_debug("Failed to open event cpu-clock:u\n");
    134		return err;
    135	}
    136
    137	perf_cpu_map__put(cpus);
    138	return evsel__enable(evsel);
    139}
    140
    141static int attach__cpu_enabled(struct evlist *evlist)
    142{
    143	struct evsel *evsel = evlist__last(evlist);
    144	struct perf_cpu_map *cpus;
    145	int err;
    146
    147	pr_debug("attaching to CPU 0 as enabled\n");
    148
    149	cpus = perf_cpu_map__new("0");
    150	if (cpus == NULL) {
    151		pr_debug("failed to call perf_cpu_map__new\n");
    152		return -1;
    153	}
    154
    155	err = evsel__open_per_cpu(evsel, cpus, -1);
    156	if (err == -EACCES)
    157		return TEST_SKIP;
    158
    159	perf_cpu_map__put(cpus);
    160	return err ? TEST_FAIL : TEST_OK;
    161}
    162
    163static int test_times(int (attach)(struct evlist *),
    164		      int (detach)(struct evlist *))
    165{
    166	struct perf_counts_values count;
    167	struct evlist *evlist = NULL;
    168	struct evsel *evsel;
    169	int err = -1, i;
    170
    171	evlist = evlist__new();
    172	if (!evlist) {
    173		pr_debug("failed to create event list\n");
    174		goto out_err;
    175	}
    176
    177	err = parse_events(evlist, "cpu-clock:u", NULL);
    178	if (err) {
    179		pr_debug("failed to parse event cpu-clock:u\n");
    180		goto out_err;
    181	}
    182
    183	evsel = evlist__last(evlist);
    184	evsel->core.attr.read_format |=
    185		PERF_FORMAT_TOTAL_TIME_ENABLED |
    186		PERF_FORMAT_TOTAL_TIME_RUNNING;
    187
    188	err = attach(evlist);
    189	if (err == TEST_SKIP) {
    190		pr_debug("  SKIP  : not enough rights\n");
    191		return err;
    192	}
    193
    194	TEST_ASSERT_VAL("failed to attach", !err);
    195
    196	for (i = 0; i < 100000000; i++) { }
    197
    198	TEST_ASSERT_VAL("failed to detach", !detach(evlist));
    199
    200	perf_evsel__read(&evsel->core, 0, 0, &count);
    201
    202	err = !(count.ena == count.run);
    203
    204	pr_debug("  %s: ena %" PRIu64", run %" PRIu64"\n",
    205		 !err ? "OK    " : "FAILED",
    206		 count.ena, count.run);
    207
    208out_err:
    209	evlist__delete(evlist);
    210	return !err ? TEST_OK : TEST_FAIL;
    211}
    212
    213/*
    214 * This test creates software event 'cpu-clock'
    215 * attaches it in several ways (explained below)
    216 * and checks that enabled and running times
    217 * match.
    218 */
    219static int test__event_times(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
    220{
    221	int err, ret = 0;
    222
    223#define _T(attach, detach)			\
    224	err = test_times(attach, detach);	\
    225	if (err && (ret == TEST_OK || ret == TEST_SKIP))	\
    226		ret = err;
    227
    228	/* attach on newly spawned process after exec */
    229	_T(attach__enable_on_exec,   detach__enable_on_exec)
    230	/* attach on current process as enabled */
    231	_T(attach__current_enabled,  detach__disable)
    232	/* attach on current process as disabled */
    233	_T(attach__current_disabled, detach__disable)
    234	/* attach on cpu as disabled */
    235	_T(attach__cpu_disabled,     detach__disable)
    236	/* attach on cpu as enabled */
    237	_T(attach__cpu_enabled,      detach__disable)
    238
    239#undef _T
    240	return ret;
    241}
    242
    243DEFINE_SUITE("Event times", event_times);