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

main.c (6532B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2016 Red Hat, Inc.
      4 * Author: Michael S. Tsirkin <mst@redhat.com>
      5 *
      6 * Command line processing and common functions for ring benchmarking.
      7 */
      8#define _GNU_SOURCE
      9#include <getopt.h>
     10#include <pthread.h>
     11#include <assert.h>
     12#include <sched.h>
     13#include "main.h"
     14#include <sys/eventfd.h>
     15#include <stdlib.h>
     16#include <stdio.h>
     17#include <unistd.h>
     18#include <limits.h>
     19
     20int runcycles = 10000000;
     21int max_outstanding = INT_MAX;
     22int batch = 1;
     23int param = 0;
     24
     25bool do_sleep = false;
     26bool do_relax = false;
     27bool do_exit = true;
     28
     29unsigned ring_size = 256;
     30
     31static int kickfd = -1;
     32static int callfd = -1;
     33
     34void notify(int fd)
     35{
     36	unsigned long long v = 1;
     37	int r;
     38
     39	vmexit();
     40	r = write(fd, &v, sizeof v);
     41	assert(r == sizeof v);
     42	vmentry();
     43}
     44
     45void wait_for_notify(int fd)
     46{
     47	unsigned long long v = 1;
     48	int r;
     49
     50	vmexit();
     51	r = read(fd, &v, sizeof v);
     52	assert(r == sizeof v);
     53	vmentry();
     54}
     55
     56void kick(void)
     57{
     58	notify(kickfd);
     59}
     60
     61void wait_for_kick(void)
     62{
     63	wait_for_notify(kickfd);
     64}
     65
     66void call(void)
     67{
     68	notify(callfd);
     69}
     70
     71void wait_for_call(void)
     72{
     73	wait_for_notify(callfd);
     74}
     75
     76void set_affinity(const char *arg)
     77{
     78	cpu_set_t cpuset;
     79	int ret;
     80	pthread_t self;
     81	long int cpu;
     82	char *endptr;
     83
     84	if (!arg)
     85		return;
     86
     87	cpu = strtol(arg, &endptr, 0);
     88	assert(!*endptr);
     89
     90	assert(cpu >= 0 && cpu < CPU_SETSIZE);
     91
     92	self = pthread_self();
     93	CPU_ZERO(&cpuset);
     94	CPU_SET(cpu, &cpuset);
     95
     96	ret = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
     97	assert(!ret);
     98}
     99
    100void poll_used(void)
    101{
    102	while (used_empty())
    103		busy_wait();
    104}
    105
    106static void __attribute__((__flatten__)) run_guest(void)
    107{
    108	int completed_before;
    109	int completed = 0;
    110	int started = 0;
    111	int bufs = runcycles;
    112	int spurious = 0;
    113	int r;
    114	unsigned len;
    115	void *buf;
    116	int tokick = batch;
    117
    118	for (;;) {
    119		if (do_sleep)
    120			disable_call();
    121		completed_before = completed;
    122		do {
    123			if (started < bufs &&
    124			    started - completed < max_outstanding) {
    125				r = add_inbuf(0, "Buffer\n", "Hello, world!");
    126				if (__builtin_expect(r == 0, true)) {
    127					++started;
    128					if (!--tokick) {
    129						tokick = batch;
    130						if (do_sleep)
    131							kick_available();
    132					}
    133
    134				}
    135			} else
    136				r = -1;
    137
    138			/* Flush out completed bufs if any */
    139			if (get_buf(&len, &buf)) {
    140				++completed;
    141				if (__builtin_expect(completed == bufs, false))
    142					return;
    143				r = 0;
    144			}
    145		} while (r == 0);
    146		if (completed == completed_before)
    147			++spurious;
    148		assert(completed <= bufs);
    149		assert(started <= bufs);
    150		if (do_sleep) {
    151			if (used_empty() && enable_call())
    152				wait_for_call();
    153		} else {
    154			poll_used();
    155		}
    156	}
    157}
    158
    159void poll_avail(void)
    160{
    161	while (avail_empty())
    162		busy_wait();
    163}
    164
    165static void __attribute__((__flatten__)) run_host(void)
    166{
    167	int completed_before;
    168	int completed = 0;
    169	int spurious = 0;
    170	int bufs = runcycles;
    171	unsigned len;
    172	void *buf;
    173
    174	for (;;) {
    175		if (do_sleep) {
    176			if (avail_empty() && enable_kick())
    177				wait_for_kick();
    178		} else {
    179			poll_avail();
    180		}
    181		if (do_sleep)
    182			disable_kick();
    183		completed_before = completed;
    184		while (__builtin_expect(use_buf(&len, &buf), true)) {
    185			if (do_sleep)
    186				call_used();
    187			++completed;
    188			if (__builtin_expect(completed == bufs, false))
    189				return;
    190		}
    191		if (completed == completed_before)
    192			++spurious;
    193		assert(completed <= bufs);
    194		if (completed == bufs)
    195			break;
    196	}
    197}
    198
    199void *start_guest(void *arg)
    200{
    201	set_affinity(arg);
    202	run_guest();
    203	pthread_exit(NULL);
    204}
    205
    206void *start_host(void *arg)
    207{
    208	set_affinity(arg);
    209	run_host();
    210	pthread_exit(NULL);
    211}
    212
    213static const char optstring[] = "";
    214static const struct option longopts[] = {
    215	{
    216		.name = "help",
    217		.has_arg = no_argument,
    218		.val = 'h',
    219	},
    220	{
    221		.name = "host-affinity",
    222		.has_arg = required_argument,
    223		.val = 'H',
    224	},
    225	{
    226		.name = "guest-affinity",
    227		.has_arg = required_argument,
    228		.val = 'G',
    229	},
    230	{
    231		.name = "ring-size",
    232		.has_arg = required_argument,
    233		.val = 'R',
    234	},
    235	{
    236		.name = "run-cycles",
    237		.has_arg = required_argument,
    238		.val = 'C',
    239	},
    240	{
    241		.name = "outstanding",
    242		.has_arg = required_argument,
    243		.val = 'o',
    244	},
    245	{
    246		.name = "batch",
    247		.has_arg = required_argument,
    248		.val = 'b',
    249	},
    250	{
    251		.name = "param",
    252		.has_arg = required_argument,
    253		.val = 'p',
    254	},
    255	{
    256		.name = "sleep",
    257		.has_arg = no_argument,
    258		.val = 's',
    259	},
    260	{
    261		.name = "relax",
    262		.has_arg = no_argument,
    263		.val = 'x',
    264	},
    265	{
    266		.name = "exit",
    267		.has_arg = no_argument,
    268		.val = 'e',
    269	},
    270	{
    271	}
    272};
    273
    274static void help(void)
    275{
    276	fprintf(stderr, "Usage: <test> [--help]"
    277		" [--host-affinity H]"
    278		" [--guest-affinity G]"
    279		" [--ring-size R (default: %d)]"
    280		" [--run-cycles C (default: %d)]"
    281		" [--batch b]"
    282		" [--outstanding o]"
    283		" [--param p]"
    284		" [--sleep]"
    285		" [--relax]"
    286		" [--exit]"
    287		"\n",
    288		ring_size,
    289		runcycles);
    290}
    291
    292int main(int argc, char **argv)
    293{
    294	int ret;
    295	pthread_t host, guest;
    296	void *tret;
    297	char *host_arg = NULL;
    298	char *guest_arg = NULL;
    299	char *endptr;
    300	long int c;
    301
    302	kickfd = eventfd(0, 0);
    303	assert(kickfd >= 0);
    304	callfd = eventfd(0, 0);
    305	assert(callfd >= 0);
    306
    307	for (;;) {
    308		int o = getopt_long(argc, argv, optstring, longopts, NULL);
    309		switch (o) {
    310		case -1:
    311			goto done;
    312		case '?':
    313			help();
    314			exit(2);
    315		case 'H':
    316			host_arg = optarg;
    317			break;
    318		case 'G':
    319			guest_arg = optarg;
    320			break;
    321		case 'R':
    322			ring_size = strtol(optarg, &endptr, 0);
    323			assert(ring_size && !(ring_size & (ring_size - 1)));
    324			assert(!*endptr);
    325			break;
    326		case 'C':
    327			c = strtol(optarg, &endptr, 0);
    328			assert(!*endptr);
    329			assert(c > 0 && c < INT_MAX);
    330			runcycles = c;
    331			break;
    332		case 'o':
    333			c = strtol(optarg, &endptr, 0);
    334			assert(!*endptr);
    335			assert(c > 0 && c < INT_MAX);
    336			max_outstanding = c;
    337			break;
    338		case 'p':
    339			c = strtol(optarg, &endptr, 0);
    340			assert(!*endptr);
    341			assert(c > 0 && c < INT_MAX);
    342			param = c;
    343			break;
    344		case 'b':
    345			c = strtol(optarg, &endptr, 0);
    346			assert(!*endptr);
    347			assert(c > 0 && c < INT_MAX);
    348			batch = c;
    349			break;
    350		case 's':
    351			do_sleep = true;
    352			break;
    353		case 'x':
    354			do_relax = true;
    355			break;
    356		case 'e':
    357			do_exit = true;
    358			break;
    359		default:
    360			help();
    361			exit(4);
    362			break;
    363		}
    364	}
    365
    366	/* does nothing here, used to make sure all smp APIs compile */
    367	smp_acquire();
    368	smp_release();
    369	smp_mb();
    370done:
    371
    372	if (batch > max_outstanding)
    373		batch = max_outstanding;
    374
    375	if (optind < argc) {
    376		help();
    377		exit(4);
    378	}
    379	alloc_ring();
    380
    381	ret = pthread_create(&host, NULL, start_host, host_arg);
    382	assert(!ret);
    383	ret = pthread_create(&guest, NULL, start_guest, guest_arg);
    384	assert(!ret);
    385
    386	ret = pthread_join(guest, &tret);
    387	assert(!ret);
    388	ret = pthread_join(host, &tret);
    389	assert(!ret);
    390	return 0;
    391}