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