brintos

brintos / linux-shallow public Read only

0
0
Text · 6.4 KiB · e471d8e Raw
392 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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_SOURCE9#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			} else136				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: %u)]"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}392