2 * Context switch microbenchmark.
4 * Copyright (C) 2015 Anton Blanchard <anton@au.ibm.com>, IBM
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
24 #include <sys/syscall.h>
25 #include <sys/types.h>
27 #include <linux/futex.h>
31 static unsigned int timeout
= 30;
33 static int touch_vdso
;
36 static int touch_fp
= 1;
39 static int touch_vector
= 1;
40 typedef int v4si
__attribute__ ((vector_size (16)));
44 static int touch_altivec
= 1;
46 static void __attribute__((__target__("no-vsx"))) altivec_touch_fn(void)
52 static void touch(void)
55 gettimeofday(&tv
, NULL
);
68 asm volatile("# %0 %1 %2": : "r"(&tv
), "r"(&fp
), "r"(&c
));
71 static void start_thread_on(void *(*fn
)(void *), void *arg
, unsigned long cpu
)
78 CPU_SET(cpu
, &cpuset
);
80 pthread_attr_init(&attr
);
82 if (pthread_attr_setaffinity_np(&attr
, sizeof(cpu_set_t
), &cpuset
)) {
83 perror("pthread_attr_setaffinity_np");
87 if (pthread_create(&tid
, &attr
, fn
, arg
)) {
88 perror("pthread_create");
93 static void start_process_on(void *(*fn
)(void *), void *arg
, unsigned long cpu
)
108 CPU_SET(cpu
, &cpuset
);
110 if (sched_setaffinity(0, sizeof(cpuset
), &cpuset
)) {
111 perror("sched_setaffinity");
120 static unsigned long iterations
;
121 static unsigned long iterations_prev
;
123 static void sigalrm_handler(int junk
)
125 unsigned long i
= iterations
;
127 printf("%ld\n", i
- iterations_prev
);
136 static void sigusr1_handler(int junk
)
142 void (*setup
)(int, int);
143 void *(*thread1
)(void *);
144 void *(*thread2
)(void *);
150 static int pipe_fd1
[2];
151 static int pipe_fd2
[2];
153 static void pipe_setup(int cpu1
, int cpu2
)
155 if (pipe(pipe_fd1
) || pipe(pipe_fd2
))
159 static void *pipe_thread1(void *arg
)
161 signal(SIGALRM
, sigalrm_handler
);
165 assert(read(pipe_fd1
[READ
], &c
, 1) == 1);
168 assert(write(pipe_fd2
[WRITE
], &c
, 1) == 1);
177 static void *pipe_thread2(void *arg
)
180 assert(write(pipe_fd1
[WRITE
], &c
, 1) == 1);
183 assert(read(pipe_fd2
[READ
], &c
, 1) == 1);
190 static struct actions pipe_actions
= {
192 .thread1
= pipe_thread1
,
193 .thread2
= pipe_thread2
,
196 static void yield_setup(int cpu1
, int cpu2
)
199 fprintf(stderr
, "Both threads must be on the same CPU for yield test\n");
204 static void *yield_thread1(void *arg
)
206 signal(SIGALRM
, sigalrm_handler
);
219 static void *yield_thread2(void *arg
)
229 static struct actions yield_actions
= {
230 .setup
= yield_setup
,
231 .thread1
= yield_thread1
,
232 .thread2
= yield_thread2
,
235 static long sys_futex(void *addr1
, int op
, int val1
, struct timespec
*timeout
,
236 void *addr2
, int val3
)
238 return syscall(SYS_futex
, addr1
, op
, val1
, timeout
, addr2
, val3
);
241 static unsigned long cmpxchg(unsigned long *p
, unsigned long expected
,
242 unsigned long desired
)
244 unsigned long exp
= expected
;
246 __atomic_compare_exchange_n(p
, &exp
, desired
, 0,
247 __ATOMIC_SEQ_CST
, __ATOMIC_SEQ_CST
);
251 static unsigned long xchg(unsigned long *p
, unsigned long val
)
253 return __atomic_exchange_n(p
, val
, __ATOMIC_SEQ_CST
);
256 static int mutex_lock(unsigned long *m
)
260 c
= cmpxchg(m
, 0, 1);
268 sys_futex(m
, FUTEX_WAIT
, 2, NULL
, NULL
, 0);
275 static int mutex_unlock(unsigned long *m
)
279 else if (xchg(m
, 0) == 1)
282 sys_futex(m
, FUTEX_WAKE
, 1, NULL
, NULL
, 0);
287 static unsigned long *m1
, *m2
;
289 static void futex_setup(int cpu1
, int cpu2
)
294 shmid
= shmget(IPC_PRIVATE
, getpagesize(), SHM_R
| SHM_W
);
300 shmaddr
= shmat(shmid
, NULL
, 0);
301 if (shmaddr
== (char *)-1) {
303 shmctl(shmid
, IPC_RMID
, NULL
);
307 shmctl(shmid
, IPC_RMID
, NULL
);
310 m2
= shmaddr
+ sizeof(*m1
);
319 static void *futex_thread1(void *arg
)
321 signal(SIGALRM
, sigalrm_handler
);
334 static void *futex_thread2(void *arg
)
344 static struct actions futex_actions
= {
345 .setup
= futex_setup
,
346 .thread1
= futex_thread1
,
347 .thread2
= futex_thread2
,
350 static int processes
;
352 static struct option options
[] = {
353 { "test", required_argument
, 0, 't' },
354 { "process", no_argument
, &processes
, 1 },
355 { "timeout", required_argument
, 0, 's' },
356 { "vdso", no_argument
, &touch_vdso
, 1 },
357 { "no-fp", no_argument
, &touch_fp
, 0 },
359 { "no-altivec", no_argument
, &touch_altivec
, 0 },
361 { "no-vector", no_argument
, &touch_vector
, 0 },
365 static void usage(void)
367 fprintf(stderr
, "Usage: context_switch2 <options> CPU1 CPU2\n\n");
368 fprintf(stderr
, "\t\t--test=X\tpipe, futex or yield (default)\n");
369 fprintf(stderr
, "\t\t--process\tUse processes (default threads)\n");
370 fprintf(stderr
, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n");
371 fprintf(stderr
, "\t\t--vdso\t\ttouch VDSO\n");
372 fprintf(stderr
, "\t\t--fp\t\ttouch FP\n");
374 fprintf(stderr
, "\t\t--altivec\ttouch altivec\n");
376 fprintf(stderr
, "\t\t--vector\ttouch vector\n");
379 int main(int argc
, char *argv
[])
382 struct actions
*actions
= &yield_actions
;
385 static void (*start_fn
)(void *(*fn
)(void *), void *arg
, unsigned long cpu
);
388 int option_index
= 0;
390 c
= getopt_long(argc
, argv
, "", options
, &option_index
);
397 if (options
[option_index
].flag
!= 0)
405 if (!strcmp(optarg
, "pipe")) {
406 actions
= &pipe_actions
;
407 } else if (!strcmp(optarg
, "yield")) {
408 actions
= &yield_actions
;
409 } else if (!strcmp(optarg
, "futex")) {
410 actions
= &futex_actions
;
418 timeout
= atoi(optarg
);
428 start_fn
= start_process_on
;
430 start_fn
= start_thread_on
;
432 if (((argc
- optind
) != 2)) {
433 cpu1
= cpu2
= pick_online_cpu();
435 cpu1
= atoi(argv
[optind
++]);
436 cpu2
= atoi(argv
[optind
++]);
439 printf("Using %s with ", processes
? "processes" : "threads");
441 if (actions
== &pipe_actions
)
443 else if (actions
== &yield_actions
)
448 printf(" on cpus %d/%d touching FP:%s altivec:%s vector:%s vdso:%s\n",
449 cpu1
, cpu2
, touch_fp
? "yes" : "no", touch_altivec
? "yes" : "no",
450 touch_vector
? "yes" : "no", touch_vdso
? "yes" : "no");
452 /* Create a new process group so we can signal everyone for exit */
453 setpgid(getpid(), getpid());
455 signal(SIGUSR1
, sigusr1_handler
);
457 actions
->setup(cpu1
, cpu2
);
459 start_fn(actions
->thread1
, NULL
, cpu1
);
460 start_fn(actions
->thread2
, NULL
, cpu2
);
This page took 0.04206 seconds and 5 git commands to generate.