xref: /openbmc/linux/tools/testing/selftests/powerpc/benchmarks/context_switch.c (revision cbecf716ca618fd44feda6bd9a64a8179d031fc5)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
200b7ec5cSMichael Ellerman /*
300b7ec5cSMichael Ellerman  * Context switch microbenchmark.
400b7ec5cSMichael Ellerman  *
500b7ec5cSMichael Ellerman  * Copyright (C) 2015 Anton Blanchard <anton@au.ibm.com>, IBM
600b7ec5cSMichael Ellerman  */
700b7ec5cSMichael Ellerman 
800b7ec5cSMichael Ellerman #define _GNU_SOURCE
989aca475SCyril Bur #include <errno.h>
1000b7ec5cSMichael Ellerman #include <sched.h>
1100b7ec5cSMichael Ellerman #include <string.h>
1200b7ec5cSMichael Ellerman #include <stdio.h>
1300b7ec5cSMichael Ellerman #include <unistd.h>
1400b7ec5cSMichael Ellerman #include <stdlib.h>
1500b7ec5cSMichael Ellerman #include <getopt.h>
1600b7ec5cSMichael Ellerman #include <signal.h>
1700b7ec5cSMichael Ellerman #include <assert.h>
1800b7ec5cSMichael Ellerman #include <pthread.h>
1900b7ec5cSMichael Ellerman #include <limits.h>
2000b7ec5cSMichael Ellerman #include <sys/time.h>
2100b7ec5cSMichael Ellerman #include <sys/syscall.h>
22854eb502SHarish #include <sys/sysinfo.h>
2300b7ec5cSMichael Ellerman #include <sys/types.h>
2400b7ec5cSMichael Ellerman #include <sys/shm.h>
2500b7ec5cSMichael Ellerman #include <linux/futex.h>
26f2418ae8SCyril Bur #ifdef __powerpc__
27f2418ae8SCyril Bur #include <altivec.h>
28f2418ae8SCyril Bur #endif
2915ec3997SSimon Guo #include "utils.h"
30ea0c3217SMichael Ellerman 
31ea0c3217SMichael Ellerman static unsigned int timeout = 30;
3200b7ec5cSMichael Ellerman 
3300b7ec5cSMichael Ellerman static int touch_vdso;
3400b7ec5cSMichael Ellerman struct timeval tv;
3500b7ec5cSMichael Ellerman 
3651c21e72SMichael Ellerman static int touch_fp = 1;
3700b7ec5cSMichael Ellerman double fp;
3800b7ec5cSMichael Ellerman 
3951c21e72SMichael Ellerman static int touch_vector = 1;
40f2418ae8SCyril Bur vector int a, b, c;
4100b7ec5cSMichael Ellerman 
4200b7ec5cSMichael Ellerman #ifdef __powerpc__
4351c21e72SMichael Ellerman static int touch_altivec = 1;
4400b7ec5cSMichael Ellerman 
45f2418ae8SCyril Bur /*
46f2418ae8SCyril Bur  * Note: LTO (Link Time Optimisation) doesn't play well with this function
47f2418ae8SCyril Bur  * attribute. Be very careful enabling LTO for this test.
48f2418ae8SCyril Bur  */
altivec_touch_fn(void)4900b7ec5cSMichael Ellerman static void __attribute__((__target__("no-vsx"))) altivec_touch_fn(void)
5000b7ec5cSMichael Ellerman {
5100b7ec5cSMichael Ellerman 	c = a + b;
5200b7ec5cSMichael Ellerman }
5300b7ec5cSMichael Ellerman #endif
5400b7ec5cSMichael Ellerman 
touch(void)5500b7ec5cSMichael Ellerman static void touch(void)
5600b7ec5cSMichael Ellerman {
5700b7ec5cSMichael Ellerman 	if (touch_vdso)
5800b7ec5cSMichael Ellerman 		gettimeofday(&tv, NULL);
5900b7ec5cSMichael Ellerman 
6000b7ec5cSMichael Ellerman 	if (touch_fp)
6100b7ec5cSMichael Ellerman 		fp += 0.1;
6200b7ec5cSMichael Ellerman 
6300b7ec5cSMichael Ellerman #ifdef __powerpc__
6400b7ec5cSMichael Ellerman 	if (touch_altivec)
6500b7ec5cSMichael Ellerman 		altivec_touch_fn();
6600b7ec5cSMichael Ellerman #endif
6700b7ec5cSMichael Ellerman 
6800b7ec5cSMichael Ellerman 	if (touch_vector)
6900b7ec5cSMichael Ellerman 		c = a + b;
7000b7ec5cSMichael Ellerman 
7100b7ec5cSMichael Ellerman 	asm volatile("# %0 %1 %2": : "r"(&tv), "r"(&fp), "r"(&c));
7200b7ec5cSMichael Ellerman }
7300b7ec5cSMichael Ellerman 
start_thread_on(void * (* fn)(void *),void * arg,unsigned long cpu)7400b7ec5cSMichael Ellerman static void start_thread_on(void *(*fn)(void *), void *arg, unsigned long cpu)
7500b7ec5cSMichael Ellerman {
7689aca475SCyril Bur 	int rc;
7700b7ec5cSMichael Ellerman 	pthread_t tid;
7800b7ec5cSMichael Ellerman 	cpu_set_t cpuset;
7900b7ec5cSMichael Ellerman 	pthread_attr_t attr;
8000b7ec5cSMichael Ellerman 
8100b7ec5cSMichael Ellerman 	CPU_ZERO(&cpuset);
8200b7ec5cSMichael Ellerman 	CPU_SET(cpu, &cpuset);
8300b7ec5cSMichael Ellerman 
8489aca475SCyril Bur 	rc = pthread_attr_init(&attr);
8589aca475SCyril Bur 	if (rc) {
8689aca475SCyril Bur 		errno = rc;
8789aca475SCyril Bur 		perror("pthread_attr_init");
8889aca475SCyril Bur 		exit(1);
8989aca475SCyril Bur 	}
9000b7ec5cSMichael Ellerman 
9189aca475SCyril Bur 	rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
9289aca475SCyril Bur 	if (rc)	{
9389aca475SCyril Bur 		errno = rc;
9400b7ec5cSMichael Ellerman 		perror("pthread_attr_setaffinity_np");
9500b7ec5cSMichael Ellerman 		exit(1);
9600b7ec5cSMichael Ellerman 	}
9700b7ec5cSMichael Ellerman 
9889aca475SCyril Bur 	rc = pthread_create(&tid, &attr, fn, arg);
9989aca475SCyril Bur 	if (rc) {
10089aca475SCyril Bur 		errno = rc;
10100b7ec5cSMichael Ellerman 		perror("pthread_create");
10200b7ec5cSMichael Ellerman 		exit(1);
10300b7ec5cSMichael Ellerman 	}
10400b7ec5cSMichael Ellerman }
10500b7ec5cSMichael Ellerman 
start_process_on(void * (* fn)(void *),void * arg,unsigned long cpu)10600b7ec5cSMichael Ellerman static void start_process_on(void *(*fn)(void *), void *arg, unsigned long cpu)
10700b7ec5cSMichael Ellerman {
108854eb502SHarish 	int pid, ncpus;
109854eb502SHarish 	cpu_set_t *cpuset;
110854eb502SHarish 	size_t size;
11100b7ec5cSMichael Ellerman 
11200b7ec5cSMichael Ellerman 	pid = fork();
11300b7ec5cSMichael Ellerman 	if (pid == -1) {
11400b7ec5cSMichael Ellerman 		perror("fork");
11500b7ec5cSMichael Ellerman 		exit(1);
11600b7ec5cSMichael Ellerman 	}
11700b7ec5cSMichael Ellerman 
11800b7ec5cSMichael Ellerman 	if (pid)
11900b7ec5cSMichael Ellerman 		return;
12000b7ec5cSMichael Ellerman 
121854eb502SHarish 	ncpus = get_nprocs();
122854eb502SHarish 	size = CPU_ALLOC_SIZE(ncpus);
123854eb502SHarish 	cpuset = CPU_ALLOC(ncpus);
124854eb502SHarish 	if (!cpuset) {
125854eb502SHarish 		perror("malloc");
126854eb502SHarish 		exit(1);
127854eb502SHarish 	}
128854eb502SHarish 	CPU_ZERO_S(size, cpuset);
129854eb502SHarish 	CPU_SET_S(cpu, size, cpuset);
13000b7ec5cSMichael Ellerman 
131854eb502SHarish 	if (sched_setaffinity(0, size, cpuset)) {
13200b7ec5cSMichael Ellerman 		perror("sched_setaffinity");
133854eb502SHarish 		CPU_FREE(cpuset);
13400b7ec5cSMichael Ellerman 		exit(1);
13500b7ec5cSMichael Ellerman 	}
13600b7ec5cSMichael Ellerman 
137854eb502SHarish 	CPU_FREE(cpuset);
13800b7ec5cSMichael Ellerman 	fn(arg);
13900b7ec5cSMichael Ellerman 
14000b7ec5cSMichael Ellerman 	exit(0);
14100b7ec5cSMichael Ellerman }
14200b7ec5cSMichael Ellerman 
14300b7ec5cSMichael Ellerman static unsigned long iterations;
14400b7ec5cSMichael Ellerman static unsigned long iterations_prev;
14500b7ec5cSMichael Ellerman 
sigalrm_handler(int junk)14600b7ec5cSMichael Ellerman static void sigalrm_handler(int junk)
14700b7ec5cSMichael Ellerman {
14800b7ec5cSMichael Ellerman 	unsigned long i = iterations;
14900b7ec5cSMichael Ellerman 
15000b7ec5cSMichael Ellerman 	printf("%ld\n", i - iterations_prev);
15100b7ec5cSMichael Ellerman 	iterations_prev = i;
15200b7ec5cSMichael Ellerman 
15300b7ec5cSMichael Ellerman 	if (--timeout == 0)
15400b7ec5cSMichael Ellerman 		kill(0, SIGUSR1);
15500b7ec5cSMichael Ellerman 
15600b7ec5cSMichael Ellerman 	alarm(1);
15700b7ec5cSMichael Ellerman }
15800b7ec5cSMichael Ellerman 
sigusr1_handler(int junk)15900b7ec5cSMichael Ellerman static void sigusr1_handler(int junk)
16000b7ec5cSMichael Ellerman {
16100b7ec5cSMichael Ellerman 	exit(0);
16200b7ec5cSMichael Ellerman }
16300b7ec5cSMichael Ellerman 
16400b7ec5cSMichael Ellerman struct actions {
16500b7ec5cSMichael Ellerman 	void (*setup)(int, int);
16600b7ec5cSMichael Ellerman 	void *(*thread1)(void *);
16700b7ec5cSMichael Ellerman 	void *(*thread2)(void *);
16800b7ec5cSMichael Ellerman };
16900b7ec5cSMichael Ellerman 
17000b7ec5cSMichael Ellerman #define READ 0
17100b7ec5cSMichael Ellerman #define WRITE 1
17200b7ec5cSMichael Ellerman 
17300b7ec5cSMichael Ellerman static int pipe_fd1[2];
17400b7ec5cSMichael Ellerman static int pipe_fd2[2];
17500b7ec5cSMichael Ellerman 
pipe_setup(int cpu1,int cpu2)17600b7ec5cSMichael Ellerman static void pipe_setup(int cpu1, int cpu2)
17700b7ec5cSMichael Ellerman {
17800b7ec5cSMichael Ellerman 	if (pipe(pipe_fd1) || pipe(pipe_fd2))
17900b7ec5cSMichael Ellerman 		exit(1);
18000b7ec5cSMichael Ellerman }
18100b7ec5cSMichael Ellerman 
pipe_thread1(void * arg)18200b7ec5cSMichael Ellerman static void *pipe_thread1(void *arg)
18300b7ec5cSMichael Ellerman {
18400b7ec5cSMichael Ellerman 	signal(SIGALRM, sigalrm_handler);
18500b7ec5cSMichael Ellerman 	alarm(1);
18600b7ec5cSMichael Ellerman 
18700b7ec5cSMichael Ellerman 	while (1) {
18800b7ec5cSMichael Ellerman 		assert(read(pipe_fd1[READ], &c, 1) == 1);
18900b7ec5cSMichael Ellerman 		touch();
19000b7ec5cSMichael Ellerman 
19100b7ec5cSMichael Ellerman 		assert(write(pipe_fd2[WRITE], &c, 1) == 1);
19200b7ec5cSMichael Ellerman 		touch();
19300b7ec5cSMichael Ellerman 
19400b7ec5cSMichael Ellerman 		iterations += 2;
19500b7ec5cSMichael Ellerman 	}
19600b7ec5cSMichael Ellerman 
19700b7ec5cSMichael Ellerman 	return NULL;
19800b7ec5cSMichael Ellerman }
19900b7ec5cSMichael Ellerman 
pipe_thread2(void * arg)20000b7ec5cSMichael Ellerman static void *pipe_thread2(void *arg)
20100b7ec5cSMichael Ellerman {
20200b7ec5cSMichael Ellerman 	while (1) {
20300b7ec5cSMichael Ellerman 		assert(write(pipe_fd1[WRITE], &c, 1) == 1);
20400b7ec5cSMichael Ellerman 		touch();
20500b7ec5cSMichael Ellerman 
20600b7ec5cSMichael Ellerman 		assert(read(pipe_fd2[READ], &c, 1) == 1);
20700b7ec5cSMichael Ellerman 		touch();
20800b7ec5cSMichael Ellerman 	}
20900b7ec5cSMichael Ellerman 
21000b7ec5cSMichael Ellerman 	return NULL;
21100b7ec5cSMichael Ellerman }
21200b7ec5cSMichael Ellerman 
21300b7ec5cSMichael Ellerman static struct actions pipe_actions = {
21400b7ec5cSMichael Ellerman 	.setup = pipe_setup,
21500b7ec5cSMichael Ellerman 	.thread1 = pipe_thread1,
21600b7ec5cSMichael Ellerman 	.thread2 = pipe_thread2,
21700b7ec5cSMichael Ellerman };
21800b7ec5cSMichael Ellerman 
yield_setup(int cpu1,int cpu2)21900b7ec5cSMichael Ellerman static void yield_setup(int cpu1, int cpu2)
22000b7ec5cSMichael Ellerman {
22100b7ec5cSMichael Ellerman 	if (cpu1 != cpu2) {
22200b7ec5cSMichael Ellerman 		fprintf(stderr, "Both threads must be on the same CPU for yield test\n");
22300b7ec5cSMichael Ellerman 		exit(1);
22400b7ec5cSMichael Ellerman 	}
22500b7ec5cSMichael Ellerman }
22600b7ec5cSMichael Ellerman 
yield_thread1(void * arg)22700b7ec5cSMichael Ellerman static void *yield_thread1(void *arg)
22800b7ec5cSMichael Ellerman {
22900b7ec5cSMichael Ellerman 	signal(SIGALRM, sigalrm_handler);
23000b7ec5cSMichael Ellerman 	alarm(1);
23100b7ec5cSMichael Ellerman 
23200b7ec5cSMichael Ellerman 	while (1) {
23300b7ec5cSMichael Ellerman 		sched_yield();
23400b7ec5cSMichael Ellerman 		touch();
23500b7ec5cSMichael Ellerman 
23600b7ec5cSMichael Ellerman 		iterations += 2;
23700b7ec5cSMichael Ellerman 	}
23800b7ec5cSMichael Ellerman 
23900b7ec5cSMichael Ellerman 	return NULL;
24000b7ec5cSMichael Ellerman }
24100b7ec5cSMichael Ellerman 
yield_thread2(void * arg)24200b7ec5cSMichael Ellerman static void *yield_thread2(void *arg)
24300b7ec5cSMichael Ellerman {
24400b7ec5cSMichael Ellerman 	while (1) {
24500b7ec5cSMichael Ellerman 		sched_yield();
24600b7ec5cSMichael Ellerman 		touch();
24700b7ec5cSMichael Ellerman 	}
24800b7ec5cSMichael Ellerman 
24900b7ec5cSMichael Ellerman 	return NULL;
25000b7ec5cSMichael Ellerman }
25100b7ec5cSMichael Ellerman 
25200b7ec5cSMichael Ellerman static struct actions yield_actions = {
25300b7ec5cSMichael Ellerman 	.setup = yield_setup,
25400b7ec5cSMichael Ellerman 	.thread1 = yield_thread1,
25500b7ec5cSMichael Ellerman 	.thread2 = yield_thread2,
25600b7ec5cSMichael Ellerman };
25700b7ec5cSMichael Ellerman 
sys_futex(void * addr1,int op,int val1,struct timespec * timeout,void * addr2,int val3)25800b7ec5cSMichael Ellerman static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout,
25900b7ec5cSMichael Ellerman 		      void *addr2, int val3)
26000b7ec5cSMichael Ellerman {
26100b7ec5cSMichael Ellerman 	return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
26200b7ec5cSMichael Ellerman }
26300b7ec5cSMichael Ellerman 
cmpxchg(unsigned long * p,unsigned long expected,unsigned long desired)26400b7ec5cSMichael Ellerman static unsigned long cmpxchg(unsigned long *p, unsigned long expected,
26500b7ec5cSMichael Ellerman 			     unsigned long desired)
26600b7ec5cSMichael Ellerman {
26700b7ec5cSMichael Ellerman 	unsigned long exp = expected;
26800b7ec5cSMichael Ellerman 
26900b7ec5cSMichael Ellerman 	__atomic_compare_exchange_n(p, &exp, desired, 0,
27000b7ec5cSMichael Ellerman 				    __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
27100b7ec5cSMichael Ellerman 	return exp;
27200b7ec5cSMichael Ellerman }
27300b7ec5cSMichael Ellerman 
xchg(unsigned long * p,unsigned long val)27400b7ec5cSMichael Ellerman static unsigned long xchg(unsigned long *p, unsigned long val)
27500b7ec5cSMichael Ellerman {
27600b7ec5cSMichael Ellerman 	return __atomic_exchange_n(p, val, __ATOMIC_SEQ_CST);
27700b7ec5cSMichael Ellerman }
27800b7ec5cSMichael Ellerman 
279b27ce776SNicholas Piggin static int processes;
280b27ce776SNicholas Piggin 
mutex_lock(unsigned long * m)28100b7ec5cSMichael Ellerman static int mutex_lock(unsigned long *m)
28200b7ec5cSMichael Ellerman {
28300b7ec5cSMichael Ellerman 	int c;
284b27ce776SNicholas Piggin 	int flags = FUTEX_WAIT;
285b27ce776SNicholas Piggin 	if (!processes)
286b27ce776SNicholas Piggin 		flags |= FUTEX_PRIVATE_FLAG;
28700b7ec5cSMichael Ellerman 
28800b7ec5cSMichael Ellerman 	c = cmpxchg(m, 0, 1);
28900b7ec5cSMichael Ellerman 	if (!c)
29000b7ec5cSMichael Ellerman 		return 0;
29100b7ec5cSMichael Ellerman 
29200b7ec5cSMichael Ellerman 	if (c == 1)
29300b7ec5cSMichael Ellerman 		c = xchg(m, 2);
29400b7ec5cSMichael Ellerman 
29500b7ec5cSMichael Ellerman 	while (c) {
296b27ce776SNicholas Piggin 		sys_futex(m, flags, 2, NULL, NULL, 0);
29700b7ec5cSMichael Ellerman 		c = xchg(m, 2);
29800b7ec5cSMichael Ellerman 	}
29900b7ec5cSMichael Ellerman 
30000b7ec5cSMichael Ellerman 	return 0;
30100b7ec5cSMichael Ellerman }
30200b7ec5cSMichael Ellerman 
mutex_unlock(unsigned long * m)30300b7ec5cSMichael Ellerman static int mutex_unlock(unsigned long *m)
30400b7ec5cSMichael Ellerman {
305b27ce776SNicholas Piggin 	int flags = FUTEX_WAKE;
306b27ce776SNicholas Piggin 	if (!processes)
307b27ce776SNicholas Piggin 		flags |= FUTEX_PRIVATE_FLAG;
308b27ce776SNicholas Piggin 
30900b7ec5cSMichael Ellerman 	if (*m == 2)
31000b7ec5cSMichael Ellerman 		*m = 0;
31100b7ec5cSMichael Ellerman 	else if (xchg(m, 0) == 1)
31200b7ec5cSMichael Ellerman 		return 0;
31300b7ec5cSMichael Ellerman 
314b27ce776SNicholas Piggin 	sys_futex(m, flags, 1, NULL, NULL, 0);
31500b7ec5cSMichael Ellerman 
31600b7ec5cSMichael Ellerman 	return 0;
31700b7ec5cSMichael Ellerman }
31800b7ec5cSMichael Ellerman 
31900b7ec5cSMichael Ellerman static unsigned long *m1, *m2;
32000b7ec5cSMichael Ellerman 
futex_setup(int cpu1,int cpu2)32100b7ec5cSMichael Ellerman static void futex_setup(int cpu1, int cpu2)
32200b7ec5cSMichael Ellerman {
323b27ce776SNicholas Piggin 	if (!processes) {
324b27ce776SNicholas Piggin 		static unsigned long _m1, _m2;
325b27ce776SNicholas Piggin 		m1 = &_m1;
326b27ce776SNicholas Piggin 		m2 = &_m2;
327b27ce776SNicholas Piggin 	} else {
32800b7ec5cSMichael Ellerman 		int shmid;
32900b7ec5cSMichael Ellerman 		void *shmaddr;
33000b7ec5cSMichael Ellerman 
33100b7ec5cSMichael Ellerman 		shmid = shmget(IPC_PRIVATE, getpagesize(), SHM_R | SHM_W);
33200b7ec5cSMichael Ellerman 		if (shmid < 0) {
33300b7ec5cSMichael Ellerman 			perror("shmget");
33400b7ec5cSMichael Ellerman 			exit(1);
33500b7ec5cSMichael Ellerman 		}
33600b7ec5cSMichael Ellerman 
33700b7ec5cSMichael Ellerman 		shmaddr = shmat(shmid, NULL, 0);
33800b7ec5cSMichael Ellerman 		if (shmaddr == (char *)-1) {
33900b7ec5cSMichael Ellerman 			perror("shmat");
34000b7ec5cSMichael Ellerman 			shmctl(shmid, IPC_RMID, NULL);
34100b7ec5cSMichael Ellerman 			exit(1);
34200b7ec5cSMichael Ellerman 		}
34300b7ec5cSMichael Ellerman 
34400b7ec5cSMichael Ellerman 		shmctl(shmid, IPC_RMID, NULL);
34500b7ec5cSMichael Ellerman 
34600b7ec5cSMichael Ellerman 		m1 = shmaddr;
34700b7ec5cSMichael Ellerman 		m2 = shmaddr + sizeof(*m1);
348b27ce776SNicholas Piggin 	}
34900b7ec5cSMichael Ellerman 
35000b7ec5cSMichael Ellerman 	*m1 = 0;
35100b7ec5cSMichael Ellerman 	*m2 = 0;
35200b7ec5cSMichael Ellerman 
35300b7ec5cSMichael Ellerman 	mutex_lock(m1);
35400b7ec5cSMichael Ellerman 	mutex_lock(m2);
35500b7ec5cSMichael Ellerman }
35600b7ec5cSMichael Ellerman 
futex_thread1(void * arg)35700b7ec5cSMichael Ellerman static void *futex_thread1(void *arg)
35800b7ec5cSMichael Ellerman {
35900b7ec5cSMichael Ellerman 	signal(SIGALRM, sigalrm_handler);
36000b7ec5cSMichael Ellerman 	alarm(1);
36100b7ec5cSMichael Ellerman 
36200b7ec5cSMichael Ellerman 	while (1) {
36300b7ec5cSMichael Ellerman 		mutex_lock(m2);
36400b7ec5cSMichael Ellerman 		mutex_unlock(m1);
36500b7ec5cSMichael Ellerman 
36600b7ec5cSMichael Ellerman 		iterations += 2;
36700b7ec5cSMichael Ellerman 	}
36800b7ec5cSMichael Ellerman 
36900b7ec5cSMichael Ellerman 	return NULL;
37000b7ec5cSMichael Ellerman }
37100b7ec5cSMichael Ellerman 
futex_thread2(void * arg)37200b7ec5cSMichael Ellerman static void *futex_thread2(void *arg)
37300b7ec5cSMichael Ellerman {
37400b7ec5cSMichael Ellerman 	while (1) {
37500b7ec5cSMichael Ellerman 		mutex_unlock(m2);
37600b7ec5cSMichael Ellerman 		mutex_lock(m1);
37700b7ec5cSMichael Ellerman 	}
37800b7ec5cSMichael Ellerman 
37900b7ec5cSMichael Ellerman 	return NULL;
38000b7ec5cSMichael Ellerman }
38100b7ec5cSMichael Ellerman 
38200b7ec5cSMichael Ellerman static struct actions futex_actions = {
38300b7ec5cSMichael Ellerman 	.setup = futex_setup,
38400b7ec5cSMichael Ellerman 	.thread1 = futex_thread1,
38500b7ec5cSMichael Ellerman 	.thread2 = futex_thread2,
38600b7ec5cSMichael Ellerman };
38700b7ec5cSMichael Ellerman 
38800b7ec5cSMichael Ellerman static struct option options[] = {
38900b7ec5cSMichael Ellerman 	{ "test", required_argument, 0, 't' },
39000b7ec5cSMichael Ellerman 	{ "process", no_argument, &processes, 1 },
39100b7ec5cSMichael Ellerman 	{ "timeout", required_argument, 0, 's' },
39200b7ec5cSMichael Ellerman 	{ "vdso", no_argument, &touch_vdso, 1 },
39351c21e72SMichael Ellerman 	{ "no-fp", no_argument, &touch_fp, 0 },
39400b7ec5cSMichael Ellerman #ifdef __powerpc__
39551c21e72SMichael Ellerman 	{ "no-altivec", no_argument, &touch_altivec, 0 },
39600b7ec5cSMichael Ellerman #endif
39751c21e72SMichael Ellerman 	{ "no-vector", no_argument, &touch_vector, 0 },
39800b7ec5cSMichael Ellerman 	{ 0, },
39900b7ec5cSMichael Ellerman };
40000b7ec5cSMichael Ellerman 
usage(void)40100b7ec5cSMichael Ellerman static void usage(void)
40200b7ec5cSMichael Ellerman {
40300b7ec5cSMichael Ellerman 	fprintf(stderr, "Usage: context_switch2 <options> CPU1 CPU2\n\n");
404ea0c3217SMichael Ellerman 	fprintf(stderr, "\t\t--test=X\tpipe, futex or yield (default)\n");
40500b7ec5cSMichael Ellerman 	fprintf(stderr, "\t\t--process\tUse processes (default threads)\n");
406ea0c3217SMichael Ellerman 	fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n");
40700b7ec5cSMichael Ellerman 	fprintf(stderr, "\t\t--vdso\t\ttouch VDSO\n");
40894fa56a9SCyril Bur 	fprintf(stderr, "\t\t--no-fp\t\tDon't touch FP\n");
40900b7ec5cSMichael Ellerman #ifdef __powerpc__
41094fa56a9SCyril Bur 	fprintf(stderr, "\t\t--no-altivec\tDon't touch altivec\n");
41100b7ec5cSMichael Ellerman #endif
41294fa56a9SCyril Bur 	fprintf(stderr, "\t\t--no-vector\tDon't touch vector\n");
41300b7ec5cSMichael Ellerman }
41400b7ec5cSMichael Ellerman 
main(int argc,char * argv[])41500b7ec5cSMichael Ellerman int main(int argc, char *argv[])
41600b7ec5cSMichael Ellerman {
41700b7ec5cSMichael Ellerman 	signed char c;
418ea0c3217SMichael Ellerman 	struct actions *actions = &yield_actions;
41900b7ec5cSMichael Ellerman 	int cpu1;
42000b7ec5cSMichael Ellerman 	int cpu2;
42100b7ec5cSMichael Ellerman 	static void (*start_fn)(void *(*fn)(void *), void *arg, unsigned long cpu);
42200b7ec5cSMichael Ellerman 
42300b7ec5cSMichael Ellerman 	while (1) {
42400b7ec5cSMichael Ellerman 		int option_index = 0;
42500b7ec5cSMichael Ellerman 
42600b7ec5cSMichael Ellerman 		c = getopt_long(argc, argv, "", options, &option_index);
42700b7ec5cSMichael Ellerman 
42800b7ec5cSMichael Ellerman 		if (c == -1)
42900b7ec5cSMichael Ellerman 			break;
43000b7ec5cSMichael Ellerman 
43100b7ec5cSMichael Ellerman 		switch (c) {
43200b7ec5cSMichael Ellerman 		case 0:
43300b7ec5cSMichael Ellerman 			if (options[option_index].flag != 0)
43400b7ec5cSMichael Ellerman 				break;
43500b7ec5cSMichael Ellerman 
43600b7ec5cSMichael Ellerman 			usage();
43700b7ec5cSMichael Ellerman 			exit(1);
43800b7ec5cSMichael Ellerman 			break;
43900b7ec5cSMichael Ellerman 
44000b7ec5cSMichael Ellerman 		case 't':
44100b7ec5cSMichael Ellerman 			if (!strcmp(optarg, "pipe")) {
44200b7ec5cSMichael Ellerman 				actions = &pipe_actions;
44300b7ec5cSMichael Ellerman 			} else if (!strcmp(optarg, "yield")) {
44400b7ec5cSMichael Ellerman 				actions = &yield_actions;
44500b7ec5cSMichael Ellerman 			} else if (!strcmp(optarg, "futex")) {
44600b7ec5cSMichael Ellerman 				actions = &futex_actions;
44700b7ec5cSMichael Ellerman 			} else {
44800b7ec5cSMichael Ellerman 				usage();
44900b7ec5cSMichael Ellerman 				exit(1);
45000b7ec5cSMichael Ellerman 			}
45100b7ec5cSMichael Ellerman 			break;
45200b7ec5cSMichael Ellerman 
45300b7ec5cSMichael Ellerman 		case 's':
45400b7ec5cSMichael Ellerman 			timeout = atoi(optarg);
45500b7ec5cSMichael Ellerman 			break;
45600b7ec5cSMichael Ellerman 
45700b7ec5cSMichael Ellerman 		default:
45800b7ec5cSMichael Ellerman 			usage();
45900b7ec5cSMichael Ellerman 			exit(1);
46000b7ec5cSMichael Ellerman 		}
46100b7ec5cSMichael Ellerman 	}
46200b7ec5cSMichael Ellerman 
46300b7ec5cSMichael Ellerman 	if (processes)
46400b7ec5cSMichael Ellerman 		start_fn = start_process_on;
46500b7ec5cSMichael Ellerman 	else
46600b7ec5cSMichael Ellerman 		start_fn = start_thread_on;
46700b7ec5cSMichael Ellerman 
46800b7ec5cSMichael Ellerman 	if (((argc - optind) != 2)) {
469ea0c3217SMichael Ellerman 		cpu1 = cpu2 = pick_online_cpu();
470ea0c3217SMichael Ellerman 	} else {
471ea0c3217SMichael Ellerman 		cpu1 = atoi(argv[optind++]);
472ea0c3217SMichael Ellerman 		cpu2 = atoi(argv[optind++]);
47300b7ec5cSMichael Ellerman 	}
47400b7ec5cSMichael Ellerman 
475ea0c3217SMichael Ellerman 	printf("Using %s with ", processes ? "processes" : "threads");
476ea0c3217SMichael Ellerman 
477ea0c3217SMichael Ellerman 	if (actions == &pipe_actions)
478ea0c3217SMichael Ellerman 		printf("pipe");
479ea0c3217SMichael Ellerman 	else if (actions == &yield_actions)
480ea0c3217SMichael Ellerman 		printf("yield");
481ea0c3217SMichael Ellerman 	else
482ea0c3217SMichael Ellerman 		printf("futex");
483ea0c3217SMichael Ellerman 
484*09275d71SMichael Ellerman 	if (!have_hwcap(PPC_FEATURE_HAS_ALTIVEC))
485*09275d71SMichael Ellerman 		touch_altivec = 0;
486*09275d71SMichael Ellerman 
487*09275d71SMichael Ellerman 	if (!have_hwcap(PPC_FEATURE_HAS_VSX))
488*09275d71SMichael Ellerman 		touch_vector = 0;
489*09275d71SMichael Ellerman 
490ea0c3217SMichael Ellerman 	printf(" on cpus %d/%d touching FP:%s altivec:%s vector:%s vdso:%s\n",
491ea0c3217SMichael Ellerman 	       cpu1, cpu2, touch_fp ?  "yes" : "no", touch_altivec ? "yes" : "no",
492ea0c3217SMichael Ellerman 	       touch_vector ? "yes" : "no", touch_vdso ? "yes" : "no");
493ea0c3217SMichael Ellerman 
49400b7ec5cSMichael Ellerman 	/* Create a new process group so we can signal everyone for exit */
49500b7ec5cSMichael Ellerman 	setpgid(getpid(), getpid());
49600b7ec5cSMichael Ellerman 
49700b7ec5cSMichael Ellerman 	signal(SIGUSR1, sigusr1_handler);
49800b7ec5cSMichael Ellerman 
49900b7ec5cSMichael Ellerman 	actions->setup(cpu1, cpu2);
50000b7ec5cSMichael Ellerman 
50100b7ec5cSMichael Ellerman 	start_fn(actions->thread1, NULL, cpu1);
50200b7ec5cSMichael Ellerman 	start_fn(actions->thread2, NULL, cpu2);
50300b7ec5cSMichael Ellerman 
50400b7ec5cSMichael Ellerman 	while (1)
50500b7ec5cSMichael Ellerman 		sleep(3600);
50600b7ec5cSMichael Ellerman 
50700b7ec5cSMichael Ellerman 	return 0;
50800b7ec5cSMichael Ellerman }
509