Treat tabs as having eight spaces instead of four
[akaros.git] / tests / pthread_switch.c
1 /* Copyright (c) 2014 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Basic pthread switcher, bypassing the 2LS.  Use for benchmarking and
6  * 2LS-inspiration. */
7
8 #include <stdio.h>
9 #include <pthread.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <sys/time.h>
13 #include "misc-compat.h"
14
15 pthread_t th1, th2;
16 int nr_switch_loops = 100;
17 pthread_barrier_t barrier;
18 bool should_exit = FALSE;
19
20 static void __pth_switch_cb(struct uthread *uthread, void *target)
21 {
22         /* by not returning, this bypasses vcore entry and event checks, though
23          * when we pop back out of the 2LS, we'll check notif pending.  think
24          * about this if you put this into your 2LS. */
25         current_uthread = NULL;
26         run_uthread((struct uthread*)target);
27         assert(0);
28 }
29
30 static void pth_switch_to(struct pthread_tcb *target)
31 {
32         uthread_yield(TRUE, __pth_switch_cb, target);
33 }
34
35 void *switch_thread(void *arg)
36 {       
37         pthread_t other_thr = *(pthread_t*)arg;
38
39         pthread_barrier_wait(&barrier);
40         for (int i = 0; i < nr_switch_loops; i++) {
41                 cmb();
42                 if (should_exit)
43                         return 0;
44                 pth_switch_to(other_thr);
45         }
46         if (pthread_self() == th1) {
47                 /* we need to break out of the switching cycle.  when th2 runs
48                  * again, it'll know to stop.  but th1 needs to both exit and
49                  * switch to th2.  we do this by making th2 runnable by the pth
50                  * schedop, then exiting */
51                 should_exit = TRUE;
52                 /* we also need to do this to th2 before it tries to exit, o/w
53                  * we'll PF in __pthread_generic_yield. */
54                 sched_ops->thread_runnable((struct uthread*)th2);
55         }
56         return 0;
57 }
58
59 int main(int argc, char** argv) 
60 {
61         struct timeval start_tv = {0};
62         struct timeval end_tv = {0};
63         long usec_diff;
64         long nr_ctx_switches;
65         void *join_ret;
66
67         if (argc > 1)
68                 nr_switch_loops = strtol(argv[1], 0, 10);
69         printf("Making 2 threads of %d switches each\n", nr_switch_loops);
70
71         parlib_never_yield = TRUE;
72         parlib_never_vc_request = TRUE;
73         pthread_need_tls(FALSE);
74         pthread_mcp_init();             /* gives us one vcore */
75
76         pthread_barrier_init(&barrier, NULL, 2);
77         /* each is passed the other's pthread_t.  th1 starts the switching. */
78         if (pthread_create(&th1, NULL, &switch_thread, &th2))
79                 perror("pth_create 1 failed");
80         /* thread 2 is created, but not put on the runnable list */
81         if (__pthread_create(&th2, NULL, &switch_thread, &th1))
82                 perror("pth_create 2 failed");
83
84         if (gettimeofday(&start_tv, 0))
85                 perror("Start time error...");
86
87         pthread_join(th1, &join_ret);
88         pthread_join(th2, &join_ret);
89
90         if (gettimeofday(&end_tv, 0))
91                 perror("End time error...");
92         nr_ctx_switches = 2 * nr_switch_loops;
93         usec_diff = (end_tv.tv_sec - start_tv.tv_sec) * 1000000 +
94                     (end_tv.tv_usec - start_tv.tv_usec);
95         printf("Done: %d loops\n", nr_switch_loops);
96         printf("Nr context switches: %ld\n", nr_ctx_switches);
97         printf("Time to run: %ld usec\n", usec_diff);
98         printf("Context switch latency: %d nsec\n",
99                (int)(1000LL*usec_diff / nr_ctx_switches));
100         printf("Context switches / sec: %d\n\n",
101                (int)(1000000LL*nr_ctx_switches / usec_diff));
102