Adds test program to fetch a web page
[akaros.git] / tests / pthread_test.c
1 #include <stdio.h>
2 #include <pthread.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <sys/time.h>
6
7 /* OS dependent #incs */
8 #include <parlib.h>
9 #include <vcore.h>
10 #include <timing.h>
11
12 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
13 #define printf_safe(...) {}
14 //#define printf_safe(...) \
15         pthread_mutex_lock(&lock); \
16         printf(__VA_ARGS__); \
17         pthread_mutex_unlock(&lock);
18
19 #define MAX_NR_TEST_THREADS 100000
20 int nr_yield_threads = 100;
21 int nr_yield_loops = 100;
22 int nr_vcores = 0;
23 int amt_fake_work = 0;
24
25 pthread_t my_threads[MAX_NR_TEST_THREADS];
26 void *my_retvals[MAX_NR_TEST_THREADS];
27
28 bool ready = FALSE;
29
30 void *yield_thread(void* arg)
31 {       
32         /* Wait til all threads are created */
33         while (!ready)
34                 cpu_relax();
35         for (int i = 0; i < nr_yield_loops; i++) {
36                 printf_safe("[A] pthread %d %p on vcore %d, itr: %d\n", pthread_self()->id,
37                        pthread_self(), vcore_id(), i);
38                 /* Fakes some work by spinning a bit.  Amount varies per uth/vcore,
39                  * scaled by fake_work */
40                 if (amt_fake_work)
41                         udelay(amt_fake_work * (pthread_self()->id * (vcore_id() + 1)));
42                 pthread_yield();
43                 printf_safe("[A] pthread %p returned from yield on vcore %d, itr: %d\n",
44                             pthread_self(), vcore_id(), i);
45         }
46         return (void*)(pthread_self());
47 }
48
49 int main(int argc, char** argv) 
50 {
51         struct timeval start_tv = {0};
52         struct timeval end_tv = {0};
53         long usec_diff;
54         long nr_ctx_switches;
55
56         if (argc > 1)
57                 nr_yield_threads = strtol(argv[1], 0, 10);
58         if (argc > 2)
59                 nr_yield_loops = strtol(argv[2], 0, 10);
60         if (argc > 3)
61                 nr_vcores = strtol(argv[3], 0, 10);
62         if (argc > 4)
63                 amt_fake_work = strtol(argv[4], 0, 10);
64         nr_yield_threads = MIN(nr_yield_threads, MAX_NR_TEST_THREADS);
65         printf("Making %d threads of %d loops each, on %d vcore(s), %d work\n",
66                nr_yield_threads, nr_yield_loops, nr_vcores, amt_fake_work);
67
68         /* OS dependent prep work */
69         if (nr_vcores) {
70                 /* Only do the vcore trickery if requested */
71                 pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
72                 pthread_need_tls(FALSE);
73                 pthread_lib_init();                                     /* gives us one vcore */
74                 vcore_request(nr_vcores - 1);           /* ghetto incremental interface */
75                 for (int i = 0; i < nr_vcores; i++) {
76                         printd("Vcore %d mapped to pcore %d\n", i,
77                                __procinfo.vcoremap[i].pcoreid);
78                 }
79         }
80
81         /* create and join on yield */
82         for (int i = 0; i < nr_yield_threads; i++) {
83                 printf_safe("[A] About to create thread %d\n", i);
84                 if (pthread_create(&my_threads[i], NULL, &yield_thread, NULL))
85                         perror("pth_create failed");
86         }
87         if (gettimeofday(&start_tv, 0))
88                 perror("Start time error...");
89         ready = TRUE;                   /* signal to any spinning uthreads to start */
90         for (int i = 0; i < nr_yield_threads; i++) {
91                 printf_safe("[A] About to join on thread %d(%p)\n", i, my_threads[i]);
92                 pthread_join(my_threads[i], &my_retvals[i]);
93                 printf_safe("[A] Successfully joined on thread %d (retval: %p)\n", i,
94                             my_retvals[i]);
95         }
96         if (gettimeofday(&end_tv, 0))
97                 perror("End time error...");
98         nr_ctx_switches = nr_yield_threads * nr_yield_loops;
99         usec_diff = (end_tv.tv_sec - start_tv.tv_sec) * 1000000 +
100                     (end_tv.tv_usec - start_tv.tv_usec);
101         printf("Done: %d uthreads, %d loops, %d vcores, %d work\n",
102                nr_yield_threads, nr_yield_loops, nr_vcores, amt_fake_work);
103         printf("Nr context switches: %d\n", nr_ctx_switches);
104         printf("Time to run: %d usec\n", usec_diff);
105         if (nr_vcores == 1)
106                 printf("Context switch latency: %d nsec\n",
107                        (int)(1000LL*usec_diff / nr_ctx_switches));
108         printf("Context switches / sec: %d\n\n",
109                (int)(1000000LL*nr_ctx_switches / usec_diff));
110