]>
git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blob - tools/testing/selftests/powerpc/benchmarks/context_switch.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Context switch microbenchmark.
5 * Copyright (C) 2015 Anton Blanchard <anton@au.ibm.com>, IBM
21 #include <sys/syscall.h>
22 #include <sys/types.h>
24 #include <linux/futex.h>
30 static unsigned int timeout
= 30;
32 static int touch_vdso
;
35 static int touch_fp
= 1;
38 static int touch_vector
= 1;
42 static int touch_altivec
= 1;
45 * Note: LTO (Link Time Optimisation) doesn't play well with this function
46 * attribute. Be very careful enabling LTO for this test.
48 static void __attribute__((__target__("no-vsx"))) altivec_touch_fn(void)
54 static void touch(void)
57 gettimeofday(&tv
, NULL
);
70 asm volatile("# %0 %1 %2": : "r"(&tv
), "r"(&fp
), "r"(&c
));
73 static void start_thread_on(void *(*fn
)(void *), void *arg
, unsigned long cpu
)
81 CPU_SET(cpu
, &cpuset
);
83 rc
= pthread_attr_init(&attr
);
86 perror("pthread_attr_init");
90 rc
= pthread_attr_setaffinity_np(&attr
, sizeof(cpu_set_t
), &cpuset
);
93 perror("pthread_attr_setaffinity_np");
97 rc
= pthread_create(&tid
, &attr
, fn
, arg
);
100 perror("pthread_create");
105 static void start_process_on(void *(*fn
)(void *), void *arg
, unsigned long cpu
)
120 CPU_SET(cpu
, &cpuset
);
122 if (sched_setaffinity(0, sizeof(cpuset
), &cpuset
)) {
123 perror("sched_setaffinity");
132 static unsigned long iterations
;
133 static unsigned long iterations_prev
;
135 static void sigalrm_handler(int junk
)
137 unsigned long i
= iterations
;
139 printf("%ld\n", i
- iterations_prev
);
148 static void sigusr1_handler(int junk
)
154 void (*setup
)(int, int);
155 void *(*thread1
)(void *);
156 void *(*thread2
)(void *);
162 static int pipe_fd1
[2];
163 static int pipe_fd2
[2];
165 static void pipe_setup(int cpu1
, int cpu2
)
167 if (pipe(pipe_fd1
) || pipe(pipe_fd2
))
171 static void *pipe_thread1(void *arg
)
173 signal(SIGALRM
, sigalrm_handler
);
177 assert(read(pipe_fd1
[READ
], &c
, 1) == 1);
180 assert(write(pipe_fd2
[WRITE
], &c
, 1) == 1);
189 static void *pipe_thread2(void *arg
)
192 assert(write(pipe_fd1
[WRITE
], &c
, 1) == 1);
195 assert(read(pipe_fd2
[READ
], &c
, 1) == 1);
202 static struct actions pipe_actions
= {
204 .thread1
= pipe_thread1
,
205 .thread2
= pipe_thread2
,
208 static void yield_setup(int cpu1
, int cpu2
)
211 fprintf(stderr
, "Both threads must be on the same CPU for yield test\n");
216 static void *yield_thread1(void *arg
)
218 signal(SIGALRM
, sigalrm_handler
);
231 static void *yield_thread2(void *arg
)
241 static struct actions yield_actions
= {
242 .setup
= yield_setup
,
243 .thread1
= yield_thread1
,
244 .thread2
= yield_thread2
,
247 static long sys_futex(void *addr1
, int op
, int val1
, struct timespec
*timeout
,
248 void *addr2
, int val3
)
250 return syscall(SYS_futex
, addr1
, op
, val1
, timeout
, addr2
, val3
);
253 static unsigned long cmpxchg(unsigned long *p
, unsigned long expected
,
254 unsigned long desired
)
256 unsigned long exp
= expected
;
258 __atomic_compare_exchange_n(p
, &exp
, desired
, 0,
259 __ATOMIC_SEQ_CST
, __ATOMIC_SEQ_CST
);
263 static unsigned long xchg(unsigned long *p
, unsigned long val
)
265 return __atomic_exchange_n(p
, val
, __ATOMIC_SEQ_CST
);
268 static int processes
;
270 static int mutex_lock(unsigned long *m
)
273 int flags
= FUTEX_WAIT
;
275 flags
|= FUTEX_PRIVATE_FLAG
;
277 c
= cmpxchg(m
, 0, 1);
285 sys_futex(m
, flags
, 2, NULL
, NULL
, 0);
292 static int mutex_unlock(unsigned long *m
)
294 int flags
= FUTEX_WAKE
;
296 flags
|= FUTEX_PRIVATE_FLAG
;
300 else if (xchg(m
, 0) == 1)
303 sys_futex(m
, flags
, 1, NULL
, NULL
, 0);
308 static unsigned long *m1
, *m2
;
310 static void futex_setup(int cpu1
, int cpu2
)
313 static unsigned long _m1
, _m2
;
320 shmid
= shmget(IPC_PRIVATE
, getpagesize(), SHM_R
| SHM_W
);
326 shmaddr
= shmat(shmid
, NULL
, 0);
327 if (shmaddr
== (char *)-1) {
329 shmctl(shmid
, IPC_RMID
, NULL
);
333 shmctl(shmid
, IPC_RMID
, NULL
);
336 m2
= shmaddr
+ sizeof(*m1
);
346 static void *futex_thread1(void *arg
)
348 signal(SIGALRM
, sigalrm_handler
);
361 static void *futex_thread2(void *arg
)
371 static struct actions futex_actions
= {
372 .setup
= futex_setup
,
373 .thread1
= futex_thread1
,
374 .thread2
= futex_thread2
,
377 static struct option options
[] = {
378 { "test", required_argument
, 0, 't' },
379 { "process", no_argument
, &processes
, 1 },
380 { "timeout", required_argument
, 0, 's' },
381 { "vdso", no_argument
, &touch_vdso
, 1 },
382 { "no-fp", no_argument
, &touch_fp
, 0 },
384 { "no-altivec", no_argument
, &touch_altivec
, 0 },
386 { "no-vector", no_argument
, &touch_vector
, 0 },
390 static void usage(void)
392 fprintf(stderr
, "Usage: context_switch2 <options> CPU1 CPU2\n\n");
393 fprintf(stderr
, "\t\t--test=X\tpipe, futex or yield (default)\n");
394 fprintf(stderr
, "\t\t--process\tUse processes (default threads)\n");
395 fprintf(stderr
, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n");
396 fprintf(stderr
, "\t\t--vdso\t\ttouch VDSO\n");
397 fprintf(stderr
, "\t\t--no-fp\t\tDon't touch FP\n");
399 fprintf(stderr
, "\t\t--no-altivec\tDon't touch altivec\n");
401 fprintf(stderr
, "\t\t--no-vector\tDon't touch vector\n");
404 int main(int argc
, char *argv
[])
407 struct actions
*actions
= &yield_actions
;
410 static void (*start_fn
)(void *(*fn
)(void *), void *arg
, unsigned long cpu
);
413 int option_index
= 0;
415 c
= getopt_long(argc
, argv
, "", options
, &option_index
);
422 if (options
[option_index
].flag
!= 0)
430 if (!strcmp(optarg
, "pipe")) {
431 actions
= &pipe_actions
;
432 } else if (!strcmp(optarg
, "yield")) {
433 actions
= &yield_actions
;
434 } else if (!strcmp(optarg
, "futex")) {
435 actions
= &futex_actions
;
443 timeout
= atoi(optarg
);
453 start_fn
= start_process_on
;
455 start_fn
= start_thread_on
;
457 if (((argc
- optind
) != 2)) {
458 cpu1
= cpu2
= pick_online_cpu();
460 cpu1
= atoi(argv
[optind
++]);
461 cpu2
= atoi(argv
[optind
++]);
464 printf("Using %s with ", processes
? "processes" : "threads");
466 if (actions
== &pipe_actions
)
468 else if (actions
== &yield_actions
)
473 printf(" on cpus %d/%d touching FP:%s altivec:%s vector:%s vdso:%s\n",
474 cpu1
, cpu2
, touch_fp
? "yes" : "no", touch_altivec
? "yes" : "no",
475 touch_vector
? "yes" : "no", touch_vdso
? "yes" : "no");
477 /* Create a new process group so we can signal everyone for exit */
478 setpgid(getpid(), getpid());
480 signal(SIGUSR1
, sigusr1_handler
);
482 actions
->setup(cpu1
, cpu2
);
484 start_fn(actions
->thread1
, NULL
, cpu1
);
485 start_fn(actions
->thread2
, NULL
, cpu2
);