VMM: Make new virtio implementation work with new vmm 2LS
[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 bool ready = FALSE;
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 when
23          * we pop back out of the 2LS, we'll check notif pending.  think about this
24          * 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         while (!ready)
40                 cpu_relax();
41         for (int i = 0; i < nr_switch_loops; i++) {
42                 cmb();
43                 if (should_exit)
44                         return 0;
45                 pth_switch_to(other_thr);
46         }
47         if (pthread_self() == th1) {
48                 /* we need to break out of the switching cycle.  when th2 runs again,
49                  * it'll know to stop.  but th1 needs to both exit and switch to th2.
50                  * we do this by making th2 runnable by the pth schedop, then exiting */
51                 should_exit = TRUE;
52                 /* we also need to do this to th2 before it tries to exit, o/w we'll PF
53                  * 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         /* each is passed the other's pthread_t.  th1 starts the switching. */
77         if (pthread_create(&th1, NULL, &switch_thread, &th2))
78                 perror("pth_create 1 failed");
79         /* thread 2 is created, but not put on the runnable list */
80         if (__pthread_create(&th2, NULL, &switch_thread, &th1))
81                 perror("pth_create 2 failed");
82
83         if (gettimeofday(&start_tv, 0))
84                 perror("Start time error...");
85
86         ready = TRUE;                   /* signal to any spinning uthreads to start */
87
88         pthread_join(th1, &join_ret);
89         pthread_join(th2, &join_ret);
90
91         if (gettimeofday(&end_tv, 0))
92                 perror("End time error...");
93         nr_ctx_switches = 2 * nr_switch_loops;
94         usec_diff = (end_tv.tv_sec - start_tv.tv_sec) * 1000000 +
95                     (end_tv.tv_usec - start_tv.tv_usec);
96         printf("Done: %d loops\n", nr_switch_loops);
97         printf("Nr context switches: %ld\n", nr_ctx_switches);
98         printf("Time to run: %ld usec\n", usec_diff);
99         printf("Context switch latency: %d nsec\n",
100                (int)(1000LL*usec_diff / nr_ctx_switches));
101         printf("Context switches / sec: %d\n\n",
102                (int)(1000000LL*nr_ctx_switches / usec_diff));
103