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