18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Context switch microbenchmark.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Anton Blanchard <anton@au.ibm.com>, IBM
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define _GNU_SOURCE
98c2ecf20Sopenharmony_ci#include <errno.h>
108c2ecf20Sopenharmony_ci#include <sched.h>
118c2ecf20Sopenharmony_ci#include <string.h>
128c2ecf20Sopenharmony_ci#include <stdio.h>
138c2ecf20Sopenharmony_ci#include <unistd.h>
148c2ecf20Sopenharmony_ci#include <stdlib.h>
158c2ecf20Sopenharmony_ci#include <getopt.h>
168c2ecf20Sopenharmony_ci#include <signal.h>
178c2ecf20Sopenharmony_ci#include <assert.h>
188c2ecf20Sopenharmony_ci#include <pthread.h>
198c2ecf20Sopenharmony_ci#include <limits.h>
208c2ecf20Sopenharmony_ci#include <sys/time.h>
218c2ecf20Sopenharmony_ci#include <sys/syscall.h>
228c2ecf20Sopenharmony_ci#include <sys/sysinfo.h>
238c2ecf20Sopenharmony_ci#include <sys/types.h>
248c2ecf20Sopenharmony_ci#include <sys/shm.h>
258c2ecf20Sopenharmony_ci#include <linux/futex.h>
268c2ecf20Sopenharmony_ci#ifdef __powerpc__
278c2ecf20Sopenharmony_ci#include <altivec.h>
288c2ecf20Sopenharmony_ci#endif
298c2ecf20Sopenharmony_ci#include "utils.h"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic unsigned int timeout = 30;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic int touch_vdso;
348c2ecf20Sopenharmony_cistruct timeval tv;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int touch_fp = 1;
378c2ecf20Sopenharmony_cidouble fp;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic int touch_vector = 1;
408c2ecf20Sopenharmony_civector int a, b, c;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#ifdef __powerpc__
438c2ecf20Sopenharmony_cistatic int touch_altivec = 1;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/*
468c2ecf20Sopenharmony_ci * Note: LTO (Link Time Optimisation) doesn't play well with this function
478c2ecf20Sopenharmony_ci * attribute. Be very careful enabling LTO for this test.
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_cistatic void __attribute__((__target__("no-vsx"))) altivec_touch_fn(void)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	c = a + b;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci#endif
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic void touch(void)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	if (touch_vdso)
588c2ecf20Sopenharmony_ci		gettimeofday(&tv, NULL);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (touch_fp)
618c2ecf20Sopenharmony_ci		fp += 0.1;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#ifdef __powerpc__
648c2ecf20Sopenharmony_ci	if (touch_altivec)
658c2ecf20Sopenharmony_ci		altivec_touch_fn();
668c2ecf20Sopenharmony_ci#endif
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (touch_vector)
698c2ecf20Sopenharmony_ci		c = a + b;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	asm volatile("# %0 %1 %2": : "r"(&tv), "r"(&fp), "r"(&c));
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic void start_thread_on(void *(*fn)(void *), void *arg, unsigned long cpu)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	int rc;
778c2ecf20Sopenharmony_ci	pthread_t tid;
788c2ecf20Sopenharmony_ci	cpu_set_t cpuset;
798c2ecf20Sopenharmony_ci	pthread_attr_t attr;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	CPU_ZERO(&cpuset);
828c2ecf20Sopenharmony_ci	CPU_SET(cpu, &cpuset);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	rc = pthread_attr_init(&attr);
858c2ecf20Sopenharmony_ci	if (rc) {
868c2ecf20Sopenharmony_ci		errno = rc;
878c2ecf20Sopenharmony_ci		perror("pthread_attr_init");
888c2ecf20Sopenharmony_ci		exit(1);
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
928c2ecf20Sopenharmony_ci	if (rc)	{
938c2ecf20Sopenharmony_ci		errno = rc;
948c2ecf20Sopenharmony_ci		perror("pthread_attr_setaffinity_np");
958c2ecf20Sopenharmony_ci		exit(1);
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	rc = pthread_create(&tid, &attr, fn, arg);
998c2ecf20Sopenharmony_ci	if (rc) {
1008c2ecf20Sopenharmony_ci		errno = rc;
1018c2ecf20Sopenharmony_ci		perror("pthread_create");
1028c2ecf20Sopenharmony_ci		exit(1);
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic void start_process_on(void *(*fn)(void *), void *arg, unsigned long cpu)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	int pid, ncpus;
1098c2ecf20Sopenharmony_ci	cpu_set_t *cpuset;
1108c2ecf20Sopenharmony_ci	size_t size;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	pid = fork();
1138c2ecf20Sopenharmony_ci	if (pid == -1) {
1148c2ecf20Sopenharmony_ci		perror("fork");
1158c2ecf20Sopenharmony_ci		exit(1);
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (pid)
1198c2ecf20Sopenharmony_ci		return;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	ncpus = get_nprocs();
1228c2ecf20Sopenharmony_ci	size = CPU_ALLOC_SIZE(ncpus);
1238c2ecf20Sopenharmony_ci	cpuset = CPU_ALLOC(ncpus);
1248c2ecf20Sopenharmony_ci	if (!cpuset) {
1258c2ecf20Sopenharmony_ci		perror("malloc");
1268c2ecf20Sopenharmony_ci		exit(1);
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci	CPU_ZERO_S(size, cpuset);
1298c2ecf20Sopenharmony_ci	CPU_SET_S(cpu, size, cpuset);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (sched_setaffinity(0, size, cpuset)) {
1328c2ecf20Sopenharmony_ci		perror("sched_setaffinity");
1338c2ecf20Sopenharmony_ci		CPU_FREE(cpuset);
1348c2ecf20Sopenharmony_ci		exit(1);
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	CPU_FREE(cpuset);
1388c2ecf20Sopenharmony_ci	fn(arg);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	exit(0);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic unsigned long iterations;
1448c2ecf20Sopenharmony_cistatic unsigned long iterations_prev;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic void sigalrm_handler(int junk)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	unsigned long i = iterations;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	printf("%ld\n", i - iterations_prev);
1518c2ecf20Sopenharmony_ci	iterations_prev = i;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (--timeout == 0)
1548c2ecf20Sopenharmony_ci		kill(0, SIGUSR1);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	alarm(1);
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic void sigusr1_handler(int junk)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	exit(0);
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistruct actions {
1658c2ecf20Sopenharmony_ci	void (*setup)(int, int);
1668c2ecf20Sopenharmony_ci	void *(*thread1)(void *);
1678c2ecf20Sopenharmony_ci	void *(*thread2)(void *);
1688c2ecf20Sopenharmony_ci};
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci#define READ 0
1718c2ecf20Sopenharmony_ci#define WRITE 1
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic int pipe_fd1[2];
1748c2ecf20Sopenharmony_cistatic int pipe_fd2[2];
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic void pipe_setup(int cpu1, int cpu2)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	if (pipe(pipe_fd1) || pipe(pipe_fd2))
1798c2ecf20Sopenharmony_ci		exit(1);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic void *pipe_thread1(void *arg)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	signal(SIGALRM, sigalrm_handler);
1858c2ecf20Sopenharmony_ci	alarm(1);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	while (1) {
1888c2ecf20Sopenharmony_ci		assert(read(pipe_fd1[READ], &c, 1) == 1);
1898c2ecf20Sopenharmony_ci		touch();
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		assert(write(pipe_fd2[WRITE], &c, 1) == 1);
1928c2ecf20Sopenharmony_ci		touch();
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		iterations += 2;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return NULL;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic void *pipe_thread2(void *arg)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	while (1) {
2038c2ecf20Sopenharmony_ci		assert(write(pipe_fd1[WRITE], &c, 1) == 1);
2048c2ecf20Sopenharmony_ci		touch();
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci		assert(read(pipe_fd2[READ], &c, 1) == 1);
2078c2ecf20Sopenharmony_ci		touch();
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	return NULL;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic struct actions pipe_actions = {
2148c2ecf20Sopenharmony_ci	.setup = pipe_setup,
2158c2ecf20Sopenharmony_ci	.thread1 = pipe_thread1,
2168c2ecf20Sopenharmony_ci	.thread2 = pipe_thread2,
2178c2ecf20Sopenharmony_ci};
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic void yield_setup(int cpu1, int cpu2)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	if (cpu1 != cpu2) {
2228c2ecf20Sopenharmony_ci		fprintf(stderr, "Both threads must be on the same CPU for yield test\n");
2238c2ecf20Sopenharmony_ci		exit(1);
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic void *yield_thread1(void *arg)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	signal(SIGALRM, sigalrm_handler);
2308c2ecf20Sopenharmony_ci	alarm(1);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	while (1) {
2338c2ecf20Sopenharmony_ci		sched_yield();
2348c2ecf20Sopenharmony_ci		touch();
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		iterations += 2;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	return NULL;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic void *yield_thread2(void *arg)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	while (1) {
2458c2ecf20Sopenharmony_ci		sched_yield();
2468c2ecf20Sopenharmony_ci		touch();
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return NULL;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic struct actions yield_actions = {
2538c2ecf20Sopenharmony_ci	.setup = yield_setup,
2548c2ecf20Sopenharmony_ci	.thread1 = yield_thread1,
2558c2ecf20Sopenharmony_ci	.thread2 = yield_thread2,
2568c2ecf20Sopenharmony_ci};
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic long sys_futex(void *addr1, int op, int val1, struct timespec *timeout,
2598c2ecf20Sopenharmony_ci		      void *addr2, int val3)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic unsigned long cmpxchg(unsigned long *p, unsigned long expected,
2658c2ecf20Sopenharmony_ci			     unsigned long desired)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	unsigned long exp = expected;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	__atomic_compare_exchange_n(p, &exp, desired, 0,
2708c2ecf20Sopenharmony_ci				    __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
2718c2ecf20Sopenharmony_ci	return exp;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic unsigned long xchg(unsigned long *p, unsigned long val)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	return __atomic_exchange_n(p, val, __ATOMIC_SEQ_CST);
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic int processes;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic int mutex_lock(unsigned long *m)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	int c;
2848c2ecf20Sopenharmony_ci	int flags = FUTEX_WAIT;
2858c2ecf20Sopenharmony_ci	if (!processes)
2868c2ecf20Sopenharmony_ci		flags |= FUTEX_PRIVATE_FLAG;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	c = cmpxchg(m, 0, 1);
2898c2ecf20Sopenharmony_ci	if (!c)
2908c2ecf20Sopenharmony_ci		return 0;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (c == 1)
2938c2ecf20Sopenharmony_ci		c = xchg(m, 2);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	while (c) {
2968c2ecf20Sopenharmony_ci		sys_futex(m, flags, 2, NULL, NULL, 0);
2978c2ecf20Sopenharmony_ci		c = xchg(m, 2);
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	return 0;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic int mutex_unlock(unsigned long *m)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	int flags = FUTEX_WAKE;
3068c2ecf20Sopenharmony_ci	if (!processes)
3078c2ecf20Sopenharmony_ci		flags |= FUTEX_PRIVATE_FLAG;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (*m == 2)
3108c2ecf20Sopenharmony_ci		*m = 0;
3118c2ecf20Sopenharmony_ci	else if (xchg(m, 0) == 1)
3128c2ecf20Sopenharmony_ci		return 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	sys_futex(m, flags, 1, NULL, NULL, 0);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	return 0;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic unsigned long *m1, *m2;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic void futex_setup(int cpu1, int cpu2)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	if (!processes) {
3248c2ecf20Sopenharmony_ci		static unsigned long _m1, _m2;
3258c2ecf20Sopenharmony_ci		m1 = &_m1;
3268c2ecf20Sopenharmony_ci		m2 = &_m2;
3278c2ecf20Sopenharmony_ci	} else {
3288c2ecf20Sopenharmony_ci		int shmid;
3298c2ecf20Sopenharmony_ci		void *shmaddr;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci		shmid = shmget(IPC_PRIVATE, getpagesize(), SHM_R | SHM_W);
3328c2ecf20Sopenharmony_ci		if (shmid < 0) {
3338c2ecf20Sopenharmony_ci			perror("shmget");
3348c2ecf20Sopenharmony_ci			exit(1);
3358c2ecf20Sopenharmony_ci		}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		shmaddr = shmat(shmid, NULL, 0);
3388c2ecf20Sopenharmony_ci		if (shmaddr == (char *)-1) {
3398c2ecf20Sopenharmony_ci			perror("shmat");
3408c2ecf20Sopenharmony_ci			shmctl(shmid, IPC_RMID, NULL);
3418c2ecf20Sopenharmony_ci			exit(1);
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci		shmctl(shmid, IPC_RMID, NULL);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		m1 = shmaddr;
3478c2ecf20Sopenharmony_ci		m2 = shmaddr + sizeof(*m1);
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	*m1 = 0;
3518c2ecf20Sopenharmony_ci	*m2 = 0;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	mutex_lock(m1);
3548c2ecf20Sopenharmony_ci	mutex_lock(m2);
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic void *futex_thread1(void *arg)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	signal(SIGALRM, sigalrm_handler);
3608c2ecf20Sopenharmony_ci	alarm(1);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	while (1) {
3638c2ecf20Sopenharmony_ci		mutex_lock(m2);
3648c2ecf20Sopenharmony_ci		mutex_unlock(m1);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci		iterations += 2;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	return NULL;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic void *futex_thread2(void *arg)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	while (1) {
3758c2ecf20Sopenharmony_ci		mutex_unlock(m2);
3768c2ecf20Sopenharmony_ci		mutex_lock(m1);
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	return NULL;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic struct actions futex_actions = {
3838c2ecf20Sopenharmony_ci	.setup = futex_setup,
3848c2ecf20Sopenharmony_ci	.thread1 = futex_thread1,
3858c2ecf20Sopenharmony_ci	.thread2 = futex_thread2,
3868c2ecf20Sopenharmony_ci};
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_cistatic struct option options[] = {
3898c2ecf20Sopenharmony_ci	{ "test", required_argument, 0, 't' },
3908c2ecf20Sopenharmony_ci	{ "process", no_argument, &processes, 1 },
3918c2ecf20Sopenharmony_ci	{ "timeout", required_argument, 0, 's' },
3928c2ecf20Sopenharmony_ci	{ "vdso", no_argument, &touch_vdso, 1 },
3938c2ecf20Sopenharmony_ci	{ "no-fp", no_argument, &touch_fp, 0 },
3948c2ecf20Sopenharmony_ci#ifdef __powerpc__
3958c2ecf20Sopenharmony_ci	{ "no-altivec", no_argument, &touch_altivec, 0 },
3968c2ecf20Sopenharmony_ci#endif
3978c2ecf20Sopenharmony_ci	{ "no-vector", no_argument, &touch_vector, 0 },
3988c2ecf20Sopenharmony_ci	{ 0, },
3998c2ecf20Sopenharmony_ci};
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic void usage(void)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	fprintf(stderr, "Usage: context_switch2 <options> CPU1 CPU2\n\n");
4048c2ecf20Sopenharmony_ci	fprintf(stderr, "\t\t--test=X\tpipe, futex or yield (default)\n");
4058c2ecf20Sopenharmony_ci	fprintf(stderr, "\t\t--process\tUse processes (default threads)\n");
4068c2ecf20Sopenharmony_ci	fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n");
4078c2ecf20Sopenharmony_ci	fprintf(stderr, "\t\t--vdso\t\ttouch VDSO\n");
4088c2ecf20Sopenharmony_ci	fprintf(stderr, "\t\t--no-fp\t\tDon't touch FP\n");
4098c2ecf20Sopenharmony_ci#ifdef __powerpc__
4108c2ecf20Sopenharmony_ci	fprintf(stderr, "\t\t--no-altivec\tDon't touch altivec\n");
4118c2ecf20Sopenharmony_ci#endif
4128c2ecf20Sopenharmony_ci	fprintf(stderr, "\t\t--no-vector\tDon't touch vector\n");
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ciint main(int argc, char *argv[])
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	signed char c;
4188c2ecf20Sopenharmony_ci	struct actions *actions = &yield_actions;
4198c2ecf20Sopenharmony_ci	int cpu1;
4208c2ecf20Sopenharmony_ci	int cpu2;
4218c2ecf20Sopenharmony_ci	static void (*start_fn)(void *(*fn)(void *), void *arg, unsigned long cpu);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	while (1) {
4248c2ecf20Sopenharmony_ci		int option_index = 0;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		c = getopt_long(argc, argv, "", options, &option_index);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci		if (c == -1)
4298c2ecf20Sopenharmony_ci			break;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		switch (c) {
4328c2ecf20Sopenharmony_ci		case 0:
4338c2ecf20Sopenharmony_ci			if (options[option_index].flag != 0)
4348c2ecf20Sopenharmony_ci				break;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci			usage();
4378c2ecf20Sopenharmony_ci			exit(1);
4388c2ecf20Sopenharmony_ci			break;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci		case 't':
4418c2ecf20Sopenharmony_ci			if (!strcmp(optarg, "pipe")) {
4428c2ecf20Sopenharmony_ci				actions = &pipe_actions;
4438c2ecf20Sopenharmony_ci			} else if (!strcmp(optarg, "yield")) {
4448c2ecf20Sopenharmony_ci				actions = &yield_actions;
4458c2ecf20Sopenharmony_ci			} else if (!strcmp(optarg, "futex")) {
4468c2ecf20Sopenharmony_ci				actions = &futex_actions;
4478c2ecf20Sopenharmony_ci			} else {
4488c2ecf20Sopenharmony_ci				usage();
4498c2ecf20Sopenharmony_ci				exit(1);
4508c2ecf20Sopenharmony_ci			}
4518c2ecf20Sopenharmony_ci			break;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci		case 's':
4548c2ecf20Sopenharmony_ci			timeout = atoi(optarg);
4558c2ecf20Sopenharmony_ci			break;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci		default:
4588c2ecf20Sopenharmony_ci			usage();
4598c2ecf20Sopenharmony_ci			exit(1);
4608c2ecf20Sopenharmony_ci		}
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if (processes)
4648c2ecf20Sopenharmony_ci		start_fn = start_process_on;
4658c2ecf20Sopenharmony_ci	else
4668c2ecf20Sopenharmony_ci		start_fn = start_thread_on;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	if (((argc - optind) != 2)) {
4698c2ecf20Sopenharmony_ci		cpu1 = cpu2 = pick_online_cpu();
4708c2ecf20Sopenharmony_ci	} else {
4718c2ecf20Sopenharmony_ci		cpu1 = atoi(argv[optind++]);
4728c2ecf20Sopenharmony_ci		cpu2 = atoi(argv[optind++]);
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	printf("Using %s with ", processes ? "processes" : "threads");
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	if (actions == &pipe_actions)
4788c2ecf20Sopenharmony_ci		printf("pipe");
4798c2ecf20Sopenharmony_ci	else if (actions == &yield_actions)
4808c2ecf20Sopenharmony_ci		printf("yield");
4818c2ecf20Sopenharmony_ci	else
4828c2ecf20Sopenharmony_ci		printf("futex");
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	if (!have_hwcap(PPC_FEATURE_HAS_ALTIVEC))
4858c2ecf20Sopenharmony_ci		touch_altivec = 0;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	if (!have_hwcap(PPC_FEATURE_HAS_VSX))
4888c2ecf20Sopenharmony_ci		touch_vector = 0;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	printf(" on cpus %d/%d touching FP:%s altivec:%s vector:%s vdso:%s\n",
4918c2ecf20Sopenharmony_ci	       cpu1, cpu2, touch_fp ?  "yes" : "no", touch_altivec ? "yes" : "no",
4928c2ecf20Sopenharmony_ci	       touch_vector ? "yes" : "no", touch_vdso ? "yes" : "no");
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	/* Create a new process group so we can signal everyone for exit */
4958c2ecf20Sopenharmony_ci	setpgid(getpid(), getpid());
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	signal(SIGUSR1, sigusr1_handler);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	actions->setup(cpu1, cpu2);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	start_fn(actions->thread1, NULL, cpu1);
5028c2ecf20Sopenharmony_ci	start_fn(actions->thread2, NULL, cpu2);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	while (1)
5058c2ecf20Sopenharmony_ci		sleep(3600);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	return 0;
5088c2ecf20Sopenharmony_ci}
509