cons: disable dangerous conswrites()
[akaros.git] / tests / pthread_test.c
1 /* Copyright (c) 2010-14 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Basic test for pthreading.  Spawns a bunch of threads that yield.
6  *
7  * To build on linux, cd into tests and run:
8  * $ gcc -O2 -std=gnu99 -fno-stack-protector -g pthread_test.c -lpthread
9  *
10  * Make sure you run it with taskset to fix the number of vcores/cpus. */
11
12 #define _GNU_SOURCE /* for pth_yield on linux */
13
14 #include <stdio.h>
15 #include <pthread.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <sys/time.h>
19 #include "misc-compat.h" /* OS dependent #incs */
20
21 /* These are here just to have the compiler test the _INITIALIZERS */
22 pthread_cond_t dummy_cond = PTHREAD_COND_INITIALIZER;
23 pthread_mutex_t dummy_mutex = PTHREAD_MUTEX_INITIALIZER;
24
25 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
26 #define printf_safe(...) {}
27 //#define printf_safe(...) \
28         pthread_mutex_lock(&lock); \
29         printf(__VA_ARGS__); \
30         pthread_mutex_unlock(&lock);
31
32 #define MAX_NR_TEST_THREADS 100000
33 int nr_yield_threads = 100;
34 int nr_yield_loops = 100;
35 int nr_vcores = 0;
36 int amt_fake_work = 0;
37
38 pthread_t my_threads[MAX_NR_TEST_THREADS];
39 void *my_retvals[MAX_NR_TEST_THREADS];
40
41 pthread_barrier_t barrier;
42
43 void *yield_thread(void* arg)
44 {       
45         /* Wait til all threads are created */
46         pthread_barrier_wait(&barrier);
47         for (int i = 0; i < nr_yield_loops; i++) {
48                 printf_safe("[A] pthread %d %p on vcore %d, itr: %d\n",
49                             pthread_id(), pthread_self(), vcore_id(), i);
50                 /* Fakes some work by spinning a bit.  Amount varies per
51                  * uth/vcore, scaled by fake_work */
52                 if (amt_fake_work)
53                         udelay(amt_fake_work * (pthread_id() * (vcore_id() +
54                                                                 2)));
55                 pthread_yield();
56                 printf_safe("[A] pthread %p returned from yield on vcore %d, itr: %d\n",
57                             pthread_self(), vcore_id(), i);
58         }
59         return (void*)(pthread_self());
60 }
61
62 int main(int argc, char** argv) 
63 {
64         struct timeval start_tv = {0};
65         struct timeval end_tv = {0};
66         long usec_diff;
67         long nr_ctx_switches;
68
69         if (argc > 1)
70                 nr_yield_threads = strtol(argv[1], 0, 10);
71         if (argc > 2)
72                 nr_yield_loops = strtol(argv[2], 0, 10);
73         if (argc > 3)
74                 nr_vcores = strtol(argv[3], 0, 10);
75         if (argc > 4)
76                 amt_fake_work = strtol(argv[4], 0, 10);
77         nr_yield_threads = MIN(nr_yield_threads, MAX_NR_TEST_THREADS);
78         printf("Making %d threads of %d loops each, on %d vcore(s), %d work\n",
79                nr_yield_threads, nr_yield_loops, nr_vcores, amt_fake_work);
80
81         /* OS dependent prep work */
82 #ifdef __ros__
83         if (nr_vcores) {
84                 /* Only do the vcore trickery if requested */
85                 parlib_never_yield = TRUE;
86                 pthread_need_tls(FALSE);
87                 pthread_mcp_init();             /* gives us one vcore */
88                 vcore_request_total(nr_vcores);
89                 parlib_never_vc_request = TRUE;
90                 for (int i = 0; i < nr_vcores; i++) {
91                         printf_safe("Vcore %d mapped to pcore %d\n", i,
92                                     __procinfo.vcoremap[i].pcoreid);
93                 }
94         }
95         struct uth_join_request *join_reqs;
96
97         join_reqs = malloc(nr_yield_threads * sizeof(struct uth_join_request));
98         for (int i = 0; i < nr_yield_threads; i++)
99                 join_reqs[i].retval_loc = &my_retvals[i];
100         assert(join_reqs);
101 #endif /* __ros__ */
102
103         pthread_barrier_init(&barrier, NULL, nr_yield_threads);
104         /* create and join on yield */
105         for (int i = 0; i < nr_yield_threads; i++) {
106                 printf_safe("[A] About to create thread %d\n", i);
107                 if (pthread_create(&my_threads[i], NULL, &yield_thread, NULL))
108                         perror("pth_create failed");
109         }
110         if (gettimeofday(&start_tv, 0))
111                 perror("Start time error...");
112         /* Akaros supports parallel join */
113 #ifdef __ros__
114         for (int i = 0; i < nr_yield_threads; i++)
115                 join_reqs[i].uth = (struct uthread*)my_threads[i];
116         uthread_join_arr(join_reqs, nr_yield_threads);
117 #else
118         for (int i = 0; i < nr_yield_threads; i++) {
119                 printf_safe("[A] About to join on thread %d(%p)\n",
120                             i, my_threads[i]);
121                 pthread_join(my_threads[i], &my_retvals[i]);
122                 printf_safe("[A] Successful join on thread %d (retval: %p)\n",
123                             i, my_retvals[i]);
124         }
125 #endif
126         if (gettimeofday(&end_tv, 0))
127                 perror("End time error...");
128         nr_ctx_switches = nr_yield_threads * nr_yield_loops;
129         usec_diff = (end_tv.tv_sec - start_tv.tv_sec) * 1000000 +
130                     (end_tv.tv_usec - start_tv.tv_usec);
131         printf("Done: %d uthreads, %d loops, %d vcores, %d work\n",
132                nr_yield_threads, nr_yield_loops, nr_vcores, amt_fake_work);
133         printf("Nr context switches: %ld\n", nr_ctx_switches);
134         printf("Time to run: %ld usec\n", usec_diff);
135         if (nr_vcores == 1)
136                 printf("Context switch latency: %d nsec\n",
137                        (int)(1000LL*usec_diff / nr_ctx_switches));
138         printf("Context switches / sec: %d\n\n",
139                (int)(1000000LL*nr_ctx_switches / usec_diff));
140