Add SIGPROF based pvcalarms to pthreads
[akaros.git] / user / utest / pvcalarm.c
1 #include <utest.h>
2 #include <pthread.h>
3 #include <pvcalarm.h>
4 #include <profalarm.h>
5
6 TEST_SUITE("PVCALARMS");
7
8 /* <--- Begin definition of test cases ---> */
9 bool test_pvcalarms(void) {
10         const int INTERVAL = 10000;
11         const int ITERATIONS = 100;
12         int count[max_vcores()];
13         void pvcalarm_callback()
14         {
15                 __sync_fetch_and_add(&count[vcore_id()], 1);
16         }
17
18         pthread_lib_init();
19         pthread_can_vcore_request(FALSE);
20         vcore_request(max_vcores() - num_vcores());
21         for (int i=0; i<max_vcores(); i++)
22                 count[i] = 0;
23         
24         uint64_t now, then;
25         now = tsc2usec(read_tsc());
26         enable_pvcalarms(PVCALARM_PROF, INTERVAL, pvcalarm_callback);
27         for (int i=0; i<max_vcores(); i++)
28                 while(count[i] < ITERATIONS)
29                         cpu_relax();
30         then = tsc2usec(read_tsc());
31         disable_pvcalarms();
32
33         UT_ASSERT_M("Alarms finished too soon", then > (now + INTERVAL*count[0]));
34         UT_ASSERT_M("Alarms finished too late", then < (now + 2*INTERVAL*count[0]));
35         return true;
36 }
37
38 bool test_sigperf(void)
39 {
40         const int INTERVAL = 10000;
41         const int ITERATIONS = 100;
42         const int NUM_PTHREADS = 10;
43         int count[NUM_PTHREADS];
44         pthread_t threads[NUM_PTHREADS];
45         static __thread int *__count;
46
47         void *thread_handler(void *arg)
48         {
49                 __count = (int*)arg;
50                 sigset_t s;
51                 sigemptyset(&s);
52                 sigaddset(&s, SIGPROF);
53                 pthread_sigmask(SIG_UNBLOCK, &s, NULL);
54                 int old_count = 0, new_count = 0;
55                 while(1) {
56                         while((new_count = atomic_read((atomic_t)__count)) <= old_count);
57                         if (new_count >= ITERATIONS) break;
58                         old_count = new_count;
59                         pthread_yield();
60                 }
61         }
62         void signal_handler(int signo)
63         {
64                 assert(signo == SIGPROF);
65                 __sync_fetch_and_add(__count, 1);
66         }
67
68         pthread_lib_init();
69         pthread_can_vcore_request(TRUE);
70
71         sigset_t s;
72         sigemptyset(&s);
73         sigaddset(&s, SIGPROF);
74         pthread_sigmask(SIG_BLOCK, &s, NULL);
75         struct sigaction sigact = {.sa_handler = signal_handler, 0};
76         sigaction(SIGPROF, &sigact, 0);
77         for (int i=0; i<NUM_PTHREADS; i++)
78                 count[i] = 0;
79
80         enable_profalarm(INTERVAL);
81         for (int i=0; i<NUM_PTHREADS; i++)
82                 pthread_create(&threads[i], NULL, thread_handler, &count[i]);
83
84         for (int i=0; i<NUM_PTHREADS; i++)
85                 while(count[i] < ITERATIONS)
86                         cpu_relax();
87
88         disable_pvcalarms();
89         return true;
90 }
91
92 /* <--- End definition of test cases ---> */
93
94 struct utest utests[] = {
95         UTEST_REG(pvcalarms),
96         UTEST_REG(sigperf),
97 };
98 int num_utests = sizeof(utests) / sizeof(struct utest);
99
100 int main(int argc, char *argv[]) {
101         // Run test suite passing it all the args as whitelist of what tests to run.
102         char **whitelist = &argv[1];
103         int whitelist_len = argc - 1;
104         RUN_TEST_SUITE(utests, num_utests, whitelist, whitelist_len);
105 }