brintos

brintos / linux-shallow public Read only

0
0
Text · 5.0 KiB · d312e63 Raw
326 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3/*4 * Context switch microbenchmark.5 *6 * Copyright 2018, Anton Blanchard, IBM Corp.7 */8 9#define _GNU_SOURCE10#include <assert.h>11#include <errno.h>12#include <getopt.h>13#include <limits.h>14#include <linux/futex.h>15#include <pthread.h>16#include <sched.h>17#include <signal.h>18#include <stdio.h>19#include <stdlib.h>20#include <string.h>21#include <sys/shm.h>22#include <sys/syscall.h>23#include <sys/time.h>24#include <sys/types.h>25#include <sys/wait.h>26#include <unistd.h>27 28static unsigned int timeout = 30;29 30static void set_cpu(int cpu)31{32	cpu_set_t cpuset;33 34	if (cpu == -1)35		return;36 37	CPU_ZERO(&cpuset);38	CPU_SET(cpu, &cpuset);39 40	if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) {41		perror("sched_setaffinity");42		exit(1);43	}44}45 46static void start_process_on(void *(*fn)(void *), void *arg, int cpu)47{48	int pid;49 50	pid = fork();51	if (pid == -1) {52		perror("fork");53		exit(1);54	}55 56	if (pid)57		return;58 59	set_cpu(cpu);60 61	fn(arg);62 63	exit(0);64}65 66static int cpu;67static int do_fork = 0;68static int do_vfork = 0;69static int do_exec = 0;70static char *exec_file;71static int exec_target = 0;72static unsigned long iterations;73static unsigned long iterations_prev;74 75static void run_exec(void)76{77	char *const argv[] = { "./exec_target", NULL };78 79	if (execve("./exec_target", argv, NULL) == -1) {80		perror("execve");81		exit(1);82	}83}84 85static void bench_fork(void)86{87	while (1) {88		pid_t pid = fork();89		if (pid == -1) {90			perror("fork");91			exit(1);92		}93		if (pid == 0) {94			if (do_exec)95				run_exec();96			_exit(0);97		}98		pid = waitpid(pid, NULL, 0);99		if (pid == -1) {100			perror("waitpid");101			exit(1);102		}103		iterations++;104	}105}106 107static void bench_vfork(void)108{109	while (1) {110		pid_t pid = vfork();111		if (pid == -1) {112			perror("fork");113			exit(1);114		}115		if (pid == 0) {116			if (do_exec)117				run_exec();118			_exit(0);119		}120		pid = waitpid(pid, NULL, 0);121		if (pid == -1) {122			perror("waitpid");123			exit(1);124		}125		iterations++;126	}127}128 129static void *null_fn(void *arg)130{131	pthread_exit(NULL);132}133 134static void bench_thread(void)135{136	pthread_t tid;137	cpu_set_t cpuset;138	pthread_attr_t attr;139	int rc;140 141	rc = pthread_attr_init(&attr);142	if (rc) {143		errno = rc;144		perror("pthread_attr_init");145		exit(1);146	}147 148	if (cpu != -1) {149		CPU_ZERO(&cpuset);150		CPU_SET(cpu, &cpuset);151 152		rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);153		if (rc) {154			errno = rc;155			perror("pthread_attr_setaffinity_np");156			exit(1);157		}158	}159 160	while (1) {161		rc = pthread_create(&tid, &attr, null_fn, NULL);162		if (rc) {163			errno = rc;164			perror("pthread_create");165			exit(1);166		}167		rc = pthread_join(tid, NULL);168		if (rc) {169			errno = rc;170			perror("pthread_join");171			exit(1);172		}173		iterations++;174	}175}176 177static void sigalrm_handler(int junk)178{179	unsigned long i = iterations;180 181	printf("%ld\n", i - iterations_prev);182	iterations_prev = i;183 184	if (--timeout == 0)185		kill(0, SIGUSR1);186 187	alarm(1);188}189 190static void sigusr1_handler(int junk)191{192	exit(0);193}194 195static void *bench_proc(void *arg)196{197	signal(SIGALRM, sigalrm_handler);198	alarm(1);199 200	if (do_fork)201		bench_fork();202	else if (do_vfork)203		bench_vfork();204	else205		bench_thread();206 207	return NULL;208}209 210static struct option options[] = {211	{ "fork", no_argument, &do_fork, 1 },212	{ "vfork", no_argument, &do_vfork, 1 },213	{ "exec", no_argument, &do_exec, 1 },214	{ "timeout", required_argument, 0, 's' },215	{ "exec-target", no_argument, &exec_target, 1 },216	{ NULL },217};218 219static void usage(void)220{221	fprintf(stderr, "Usage: fork <options> CPU\n\n");222	fprintf(stderr, "\t\t--fork\tUse fork() (default threads)\n");223	fprintf(stderr, "\t\t--vfork\tUse vfork() (default threads)\n");224	fprintf(stderr, "\t\t--exec\tAlso exec() (default no exec)\n");225	fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n");226	fprintf(stderr, "\t\t--exec-target\tInternal option for exec workload\n");227}228 229int main(int argc, char *argv[])230{231	signed char c;232 233	while (1) {234		int option_index = 0;235 236		c = getopt_long(argc, argv, "", options, &option_index);237 238		if (c == -1)239			break;240 241		switch (c) {242		case 0:243			if (options[option_index].flag != 0)244				break;245 246			usage();247			exit(1);248			break;249 250		case 's':251			timeout = atoi(optarg);252			break;253 254		default:255			usage();256			exit(1);257		}258	}259 260	if (do_fork && do_vfork) {261		usage();262		exit(1);263	}264	if (do_exec && !do_fork && !do_vfork) {265		usage();266		exit(1);267	}268 269	if (do_exec) {270		char *dirname = strdup(argv[0]);271		int i;272		i = strlen(dirname) - 1;273		while (i) {274			if (dirname[i] == '/') {275				dirname[i] = '\0';276				if (chdir(dirname) == -1) {277					perror("chdir");278					exit(1);279				}280				break;281			}282			i--;283		}284	}285 286	if (exec_target) {287		exit(0);288	}289 290	if (((argc - optind) != 1)) {291		cpu = -1;292	} else {293		cpu = atoi(argv[optind++]);294	}295 296	if (do_exec)297		exec_file = argv[0];298 299	set_cpu(cpu);300 301	printf("Using ");302	if (do_fork)303		printf("fork");304	else if (do_vfork)305		printf("vfork");306	else307		printf("clone");308 309	if (do_exec)310		printf(" + exec");311 312	printf(" on cpu %d\n", cpu);313 314	/* Create a new process group so we can signal everyone for exit */315	setpgid(getpid(), getpid());316 317	signal(SIGUSR1, sigusr1_handler);318 319	start_process_on(bench_proc, NULL, cpu);320 321	while (1)322		sleep(3600);323 324	return 0;325}326