Overhaul lock_test.R
[akaros.git] / tests / interference.c
1 #include <stdint.h>
2 #include <stdlib.h>
3
4 #ifdef __akaros__
5
6 #include <parlib/stdio.h>
7 #include <parlib/uthread.h>
8 #include <parlib/timing.h>
9 #include <parlib/event.h>
10 #include <benchutil/measure.h>
11
12 static void ev_handle_null(struct event_msg *ev_msg, unsigned int ev_type,
13                            void *data)
14 {
15 }
16
17 static void os_init(void)
18 {
19         uthread_mcp_init();
20         register_ev_handler(EV_FREE_APPLE_PIE, ev_handle_null, NULL);
21 }
22
23 #else
24
25 #include <stdio.h>
26 #include "../user/parlib/include/parlib/tsc-compat.h"
27 #include "../user/benchutil/include/benchutil/measure.h"
28 #include "linux/misc-compat.h"
29
30 static void os_init(void)
31 {
32         printf("Linux: If you get a segfault, make sure rdpmc is allowed.\n"
33                "Linux: Set /sys/bus/event_source/devices/cpu/rdpmc = 2 on recent kernels (4.0), or 1 for older kernels.\n");
34 }
35
36 #endif
37
38 static uint64_t *delays;
39
40 static int get_delay(void **data, int i, int j, uint64_t *sample)
41 {
42         uint64_t **delay_array = (uint64_t**)data;
43
44         *sample = delay_array[i][j];
45         return 0;
46 }
47
48 static inline __attribute__((always_inline))
49 uint64_t pmc_cycles(void)
50 {
51         unsigned int a = 0, d = 0;
52         int ecx = (1 << 30) + 1;
53
54         asm volatile("lfence; rdpmc" : "=a"(a), "=d"(d) : "c"(ecx));
55         return ((uint64_t)a) | (((uint64_t)d) << 32);
56 }
57
58 int main(int argc, char **argv)
59 {
60         #define THRESHOLD 200
61         uint64_t start, diff;
62         struct sample_stats stats[1];
63         size_t idx = 0;
64         size_t nr_below_thresh = 0;
65         size_t nr_over_thresh = 0;
66         size_t total = 0;
67         int pcoreid;
68         uint64_t low_samples[THRESHOLD] = {0};
69         int nr_samples = 1000;
70         uint64_t deadline = sec2tsc(5); /* assumes TSC and cycles are close */
71
72         /* Normally we'd use a 2D array, but since we're just one thread, we
73          * just need our first thread's array. */
74         delays = malloc(sizeof(uint64_t) * nr_samples);
75         os_init();
76         pcoreid = get_pcoreid();
77         udelay(1000);
78         deadline += pmc_cycles();
79
80         do {
81                 if (idx >= nr_samples)
82                         break;
83                 total++;
84                 start = pmc_cycles();
85                 diff = pmc_cycles() - start;
86                 if (diff < COUNT_OF(low_samples))
87                         low_samples[diff]++;
88                 if (diff < THRESHOLD) {
89                         nr_below_thresh++;
90                 } else {
91                         nr_over_thresh++;
92                         delays[idx++] = diff;
93                 }
94                 if (!start) {
95                         printf("rdpmc got 0, is perf stat -e cycles running? (aborting)\n");
96                         break;
97                 }
98         } while (start < deadline);
99
100         printf("\n\nStats for interference\n");
101         stats->get_sample = get_delay;
102         compute_stats((void**)&delays, 1, idx, stats);
103
104         printf("\n\nStats for low rdtsc times (tsc ticks for two rdtscs)\n");
105         for (int i = 0; i < COUNT_OF(low_samples); i++) {
106                 if (low_samples[i])
107                         printf("\t[ %2d ] : %lu\n", i, low_samples[i]);
108         }
109
110         printf("Pcoreid was %d (and is now %d)\n\n", pcoreid, get_pcoreid());
111         printf("Total loops %lu, threshold %u\n", total, THRESHOLD);
112         printf("Nr over thresh %lu (%f%% total)\n", nr_over_thresh,
113                nr_over_thresh * 100.0 / total);
114         printf("Nr below thresh %lu (%f%% total)\n", nr_below_thresh,
115                nr_below_thresh * 100.0 / total);
116         return 0;
117 }