Add dedicated trace events for benchmarking.
[barrelfish] / usr / bench / mem_bench / memeasy.c
1 /**
2  * \file
3  * \brief Simple Memory Benchmark to test kernel infrastructure
4  */
5 /*
6  * Copyright (c) 2013, ETH Zurich.
7  * All rights reserved.
8  *
9  * This file is distributed under the terms in the attached LICENSE file.
10  * If you do not find this file, copies can be found by writing to:
11  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
12  */
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <assert.h>
18
19 #include <barrelfish/barrelfish.h>
20 #include <barrelfish/deferred.h>
21 #include <bench/bench.h>
22 #include <trace/trace.h>
23
24 #define MAX_ITERATION 1000
25 #define TRACE(s, e, a) trace_event(TRACE_SUBSYS_##s, TRACE_EVENT_##s##_##e, a)
26
27 static volatile bool finished;
28
29 static void set_true(void* arg) {
30     *(bool*)arg = true;
31 }
32
33 static void sleep_until(delayus_t delay) {
34     struct deferred_event de;
35     deferred_event_init(&de);
36
37     bool can_continue = false;
38
39     struct event_closure ec;
40     ec.handler = set_true;
41     ec.arg = &can_continue;
42
43     errval_t err = deferred_event_register(&de, get_default_waitset(),
44                                            delay, ec);
45     if (err_is_fail(err)) {
46         USER_PANIC_ERR(err, "deferred event register failed.");
47     }
48
49     //printf("%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
50     while(!can_continue) {
51         messages_wait_and_handle_next();
52     }
53     //printf("%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
54 }
55
56 static void after_prepare(void *arg)
57 {
58     debug_printf("after_prepare starts");
59     finished = true;
60 }
61
62 static errval_t init_tracing(void)
63 {
64     trace_reset_all();
65     debug_printf("after trace reset\n");
66
67     // Tell the trace system when to start and stop.  We can also
68     // provide an overriding maximum duration (in cycles) as the last parameter.
69     return trace_control(TRACE_EVENT(TRACE_SUBSYS_BENCH,
70                                     TRACE_EVENT_BENCH_START, 0),
71                         TRACE_EVENT(TRACE_SUBSYS_BENCH,
72                                     TRACE_EVENT_BENCH_STOP, 0),
73                         0);
74 }
75
76 static void start_tracing(void)
77 {
78     // start the trace going by providing the start event
79     TRACE(BENCH, START, 0);
80 }
81
82 static void stop_tracing(void)
83 {
84     // stop the trace by providing the stop event
85     TRACE(BENCH, STOP, 0);
86 }
87
88 static void callback(void *arg)
89 {
90     debug_printf("callback invoked\n");
91
92     finished = true;
93 }
94
95 static void dump_trace(void)
96 {
97     // dump the trace on the output.  We can copy and paste it
98     // to use in Aquarium.
99
100     debug_printf("the trace dump\n");
101
102     // Let the trace framework decide where to flush to
103     trace_flush(MKCLOSURE(callback, NULL));
104
105     debug_printf("finished trace dump\n");
106
107 }
108
109
110 int main(int argc, char** argv)
111 {
112     uint64_t sleep = 0;
113     uint64_t ram_bits = 20;
114     errval_t err;
115
116     printf("%s:%s:%d: argc = %d\n", __FILE__, __FUNCTION__, __LINE__, argc);
117     if (argc > 3) {
118         printf("%s:%s:%d: Usage: %s <ram bits> <sleep ms>\n",
119                __FILE__, __FUNCTION__, __LINE__, argv[0]);
120     } else if (argc == 3) {
121         sleep = atoll(argv[2]);
122         ram_bits = atoll(argv[1]);
123     } else if (argc == 2) {
124         ram_bits = atoll(argv[1]);
125     }
126     printf("%s:%s:%d: Use ram_bits = %"PRIu64"\n",
127        __FILE__, __FUNCTION__, __LINE__, ram_bits);
128     printf("%s:%s:%d: Use sleep = %"PRIu64"\n",
129         __FILE__, __FUNCTION__, __LINE__, sleep);
130
131
132     finished = false;
133
134     err = init_tracing();
135     if (err_is_fail(err)) {
136         DEBUG_ERR(err, "initialising tracing");
137         return EXIT_FAILURE;
138     }
139
140     // Make sure all subsystems get logged.
141     trace_set_all_subsys_enabled(true);
142
143     debug_printf("after init tracing\n");
144
145     // Prepare the tracing framework. This is optional.
146     trace_prepare(MKCLOSURE(after_prepare, NULL));
147
148     while(!finished) {
149         // Make sure this program is not exited before everything
150         // is completed.
151         event_dispatch_non_block(get_default_waitset());
152         thread_yield_dispatcher(NULL_CAP);
153     }
154
155
156     bench_init();
157     cycles_t runs[MAX_ITERATION];
158
159     start_tracing();
160
161     uint64_t start, end;
162
163     struct capref ram;
164     err = ram_alloc(&ram, ram_bits);
165     if (err_is_fail(err)) {
166         USER_PANIC_ERR(err, "ram_alloc failed.");
167     }
168
169     struct capref frame;
170     err = slot_alloc(&frame);
171     if (err_is_fail(err)) {
172         USER_PANIC_ERR(err, "slot_alloc failed.");
173     }
174
175     for (size_t i=0; i<MAX_ITERATION; i++) {
176         TRACE(BENCH, ROUND_START, 0);
177         //printf("%s:%s:%d: i=%"PRIu64"\n",
178         //       __FILE__, __FUNCTION__, __LINE__, i);
179         start = bench_tsc();
180         //printf("%s:%s:%d: \n", __FILE__, __FUNCTION__, __LINE__);
181         err = cap_retype(frame, ram, ObjType_Frame, ram_bits);
182         if (err_is_fail(err)) {
183             USER_PANIC_ERR(err, "cap_retype failed.");
184         }
185         end = bench_tsc();
186
187         err = cap_delete(frame);
188         if (err_is_fail(err)) {
189             USER_PANIC_ERR(err, "cap_delete failed.");
190         }
191
192         if (sleep > 0) {
193             sleep_until(sleep);
194         }
195         TRACE(BENCH, ROUND_END, 0);
196
197         runs[i] = end - start;
198     }
199
200     runs[0] = BENCH_IGNORE_WATERMARK;
201
202     printf("Average cycles %"PRIuCYCLES", Variance %"PRIuCYCLES"\n" \
203            "Average ms %"PRIu64" Variance ms %"PRIu64"\n",
204             bench_avg(runs, MAX_ITERATION),
205             bench_variance(runs, MAX_ITERATION),
206             bench_tsc_to_ms(bench_avg(runs, MAX_ITERATION)),
207             bench_tsc_to_ms(bench_variance(runs, MAX_ITERATION)));
208
209     finished = false;
210     stop_tracing();
211     // flush the trace buffer
212     dump_trace();
213
214     while(!finished) {
215         // Make sure this program is not exited before everything
216         // is completed.
217         event_dispatch_non_block(get_default_waitset());
218         thread_yield_dispatcher(NULL_CAP);
219     }
220
221
222     return 0;
223 }