net: Add a function to dump TCP's hash table
[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 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         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 again,
48                  * it'll know to stop.  but th1 needs to both exit and switch to th2.
49                  * we do this by making th2 runnable by the pth schedop, then exiting */
50                 should_exit = TRUE;
51                 /* we also need to do this to th2 before it tries to exit, o/w we'll PF
52                  * in __pthread_generic_yield. */
53                 sched_ops->thread_runnable((struct uthread*)th2);
54         }
55         return 0;
56 }
57
58 int main(int argc, char** argv) 
59 {
60         struct timeval start_tv = {0};
61         struct timeval end_tv = {0};
62         long usec_diff;
63         long nr_ctx_switches;
64         void *join_ret;
65
66         if (argc > 1)
67                 nr_switch_loops = strtol(argv[1], 0, 10);
68         printf("Making 2 threads of %d switches each\n", nr_switch_loops);
69
70         parlib_never_yield = TRUE;
71         parlib_never_vc_request = TRUE;
72         pthread_need_tls(FALSE);
73         pthread_mcp_init();                                     /* gives us one vcore */
74
75         pthread_barrier_init(&barrier, NULL, 2);
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         pthread_join(th1, &join_ret);
87         pthread_join(th2, &join_ret);
88
89         if (gettimeofday(&end_tv, 0))
90                 perror("End time error...");
91         nr_ctx_switches = 2 * nr_switch_loops;
92         usec_diff = (end_tv.tv_sec - start_tv.tv_sec) * 1000000 +
93                     (end_tv.tv_usec - start_tv.tv_usec);
94         printf("Done: %d loops\n", nr_switch_loops);
95         printf("Nr context switches: %ld\n", nr_ctx_switches);
96         printf("Time to run: %ld usec\n", usec_diff);
97         printf("Context switch latency: %d nsec\n",
98                (int)(1000LL*usec_diff / nr_ctx_switches));
99         printf("Context switches / sec: %d\n\n",
100                (int)(1000000LL*nr_ctx_switches / usec_diff));
101