vmm: refactor userspace's emsr_fakewrite()
[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 /* Build on linux from $AKAROS_ROOT:
26  * gcc -static --std=gnu99 tests/interference.c -o lin-interference
27  */
28
29 #include <stdio.h>
30 #include "../user/parlib/include/parlib/tsc-compat.h"
31 #include "misc-compat.h"
32
33 struct sample_stats {
34         int (*get_sample)(void **data, int i, int j, uint64_t *sample);
35         uint64_t                avg_time;
36         uint64_t                var_time;
37         uint64_t                max_time;
38         uint64_t                min_time;
39         unsigned int            lat_50;
40         unsigned int            lat_75;
41         unsigned int            lat_90;
42         unsigned int            lat_99;
43         uint64_t                total_samples;
44 };
45
46 void compute_stats(void **data, int nr_i, int nr_j, struct sample_stats *stats)
47 {
48         /* TODO: could try to link against benchutil. */
49 }
50
51 static void os_init(void)
52 {
53         printf("Linux: If you get a segfault, make sure rdpmc is allowed.\n"
54                "Linux: Set /sys/bus/event_source/devices/cpu/rdpmc = 2 on recent kernels (4.0), or 1 for older kernels.\n");
55 }
56
57 #endif
58
59 static uint64_t *delays;
60
61 static int get_delay(void **data, int i, int j, uint64_t *sample)
62 {
63         uint64_t **delay_array = (uint64_t**)data;
64
65         *sample = delay_array[i][j];
66         return 0;
67 }
68
69 static inline __attribute__((always_inline))
70 uint64_t pmc_cycles(void)
71 {
72         unsigned int a = 0, d = 0;
73         int ecx = (1 << 30) + 1;
74
75         asm volatile("lfence; rdpmc" : "=a"(a), "=d"(d) : "c"(ecx));
76         return ((uint64_t)a) | (((uint64_t)d) << 32);
77 }
78
79 int main(int argc, char **argv)
80 {
81         #define THRESHOLD 200
82         uint64_t start, diff;
83         struct sample_stats stats[1];
84         size_t idx = 0;
85         size_t nr_below_thresh = 0;
86         size_t nr_over_thresh = 0;
87         size_t total = 0;
88         int pcoreid;
89         uint64_t low_samples[THRESHOLD] = {0};
90         int nr_samples = 1000;
91         uint64_t deadline = sec2tsc(5); /* assumes TSC and cycles are close */
92
93         /* Normally we'd use a 2D array, but since we're just one thread, we
94          * just need our first thread's array. */
95         delays = malloc(sizeof(uint64_t) * nr_samples);
96         os_init();
97         pcoreid = get_pcoreid();
98         udelay(1000);
99         deadline += pmc_cycles();
100
101         do {
102                 if (idx >= nr_samples)
103                         break;
104                 total++;
105                 start = pmc_cycles();
106                 diff = pmc_cycles() - start;
107                 if (diff < COUNT_OF(low_samples))
108                         low_samples[diff]++;
109                 if (diff < THRESHOLD) {
110                         nr_below_thresh++;
111                 } else {
112                         nr_over_thresh++;
113                         delays[idx++] = diff;
114                 }
115                 if (!start) {
116                         printf("rdpmc got 0, is perf stat -e cycles running? (aborting)\n");
117                         break;
118                 }
119         } while (start < deadline);
120
121         printf("\n\nStats for interference\n");
122         stats->get_sample = get_delay;
123         compute_stats((void**)&delays, 1, idx, stats);
124
125         printf("\n\nStats for low rdtsc times (tsc ticks for two rdtscs)\n");
126         for (int i = 0; i < COUNT_OF(low_samples); i++) {
127                 if (low_samples[i])
128                         printf("\t[ %2d ] : %lu\n", i, low_samples[i]);
129         }
130
131         printf("Pcoreid was %d (and is now %d)\n\n", pcoreid, get_pcoreid());
132         printf("Total loops %lu, threshold %u\n", total, THRESHOLD);
133         printf("Nr over thresh %lu (%f%% total)\n", nr_over_thresh,
134                nr_over_thresh * 100.0 / total);
135         printf("Nr below thresh %lu (%f%% total)\n", nr_below_thresh,
136                nr_below_thresh * 100.0 / total);
137         return 0;
138 }