1#include <stdlib.h>
2#include <stdbool.h>
3#include <stdio.h>
4#include <string.h>
5#include <barrelfish/barrelfish.h>
6#include <barrelfish/types.h>
7#include <barrelfish/cap_predicates.h>
8#include <bench/bench.h>
9
10#include "mdb_bench.h"
11
12const char *progname = NULL;
13
14static void test(char *base, size_t size, size_t runs, reset_fn reset, measure_fn measure, const char *name)
15{
16    assert(size % sizeof(struct cte) == 0);
17    struct cte *ctes = (struct cte*)base;
18    size_t num_caps = size/sizeof(struct cte);
19
20    int run, skipped;
21    for (run = skipped = 0;
22         run < runs && (skipped < runs/10 || skipped < run*2);
23         run++)
24    {
25        // reset MDB
26        reset(base, size);
27
28        // perform measurement
29        cycles_t val = measure(ctes, num_caps);
30
31        if (!val) {
32            // measurement skipped
33            printf("%s: skipping\n", name);
34            skipped++;
35            run--;
36            continue;
37        }
38
39        // output
40        printf("%s:%s: %"PRIu64"/%zu\n", progname, name, val - bench_tscoverhead(), num_caps);
41    }
42
43    if (run < runs) {
44        printf("%s: skipped too many, aborting\n", name);
45    }
46}
47
48static void
49reset_and_dump(char *base, size_t size, size_t runs, reset_fn reset, const char *name)
50{
51    assert(size % sizeof(struct cte) == 0);
52    struct cte *ctes = (struct cte*)base;
53    size_t num_caps = size/sizeof(struct cte);
54
55    for (size_t run = 0; run < runs; run++) {
56        // reset MDB
57        reset(base, size);
58
59        for (size_t i = 0; i < num_caps; i++) {
60            INS(&ctes[i]);
61        }
62
63        // dump entries
64        for (size_t i = 0; i < num_caps; i++) {
65            struct cte *cte = &ctes[i];
66            struct capability *curr = &cte->cap;
67            assert(curr->type == ObjType_RAM);
68            printf("%s/%zu:dump:%zu: 0x%08"PRIxGENPADDR"/0x%"PRIxGENSIZE" %c%c%c\n",
69                   name, num_caps, run, curr->u.ram.base, curr->u.ram.bytes,
70                   (HASCOP(cte) ? 'c' : '.'), (HASANC(cte) ? 'a' : '.'),
71                   (HASDESC(cte) ? 'd' : '.'));
72        }
73    }
74}
75
76static void usage(const char *program)
77{
78    printf("usage: %s [runs=NUM]"
79           " [size=NUM] [count=NUM]"
80           " [logsize=NUM] [logcount=NUM]"
81           " [reset=NAME] [measure=NAME]\n\n", program);
82    printf("\truns defaults to 100\n");
83    printf("\tlogsize defaults to 20\n");
84    printf("\tcount = size/sizeof(struct cte)\n\n");
85    printf("resetters:\n");
86    for (int i = 0; reset_opts[i].name; i++) {
87        printf("\t%s\n", reset_opts[i].name);
88    }
89    printf("\n");
90    printf("measures:\n");
91    for (int i = 0; measure_opts[i].name; i++) {
92        printf("\t%s\n", measure_opts[i].name);
93    }
94    printf("\tdump\n");
95    printf("\n");
96}
97
98int main(int argc, char* argv[])
99{
100    progname = argv[0];
101
102    size_t size_wanted = 1<<20;
103    size_t runs = 100;
104    struct reset_opt *reset = NULL;
105    struct measure_opt *measure = NULL;
106    bool dump = false;
107
108    assert(argc>0);
109    if (argc == 1) {
110        usage(argv[0]);
111        return 0;
112    }
113
114    bool args_ok = true;
115
116    for (int arg = 1; arg < argc; arg++) {
117        if (strcmp(argv[arg], "help") == 0
118            || strcmp(argv[arg], "--help") == 0
119            || strcmp(argv[arg], "-h") == 0)
120        {
121            usage(argv[0]);
122            return 0;
123        }
124        if (strncmp(argv[arg], "size=", 5) == 0) {
125            size_wanted = atol(argv[arg]+5);
126        }
127        if (strncmp(argv[arg], "logsize=", 8) == 0) {
128            size_t logsize = atol(argv[arg]+8);
129            if (logsize > 31) {
130                printf("ERROR: logsize too big\n");
131                args_ok = false;
132            }
133            else {
134                size_wanted = 1 << logsize;
135            }
136        }
137        else if (strncmp(argv[arg], "count=", 6) == 0) {
138            size_wanted = atol(argv[arg]+6)*sizeof(struct cte);
139        }
140        else if (strncmp(argv[arg], "logcount=", 9) == 0) {
141            size_t logcount = atol(argv[arg]+9);
142            if (logcount > (31-OBJBITS_CTE)) {
143                printf("ERROR: logcount too big\n");
144                args_ok = false;
145            }
146            else {
147                size_wanted = (1 << logcount)*sizeof(struct cte);
148            }
149        }
150        else if (strncmp(argv[arg], "runs=", 5) == 0) {
151            runs = atol(argv[arg]+5);
152        }
153        else if (strncmp(argv[arg], "reset=", 6) == 0) {
154            char *name = argv[arg]+6;
155            int i;
156            for (i = 0; reset_opts[i].name; i++) {
157                if (strcmp(reset_opts[i].name, name) == 0) {
158                    reset = &reset_opts[i];
159                    break;
160                }
161            }
162            if (!reset_opts[i].name) {
163                args_ok = false;
164                printf("ERROR: unkown reset \"%s\"\n", name);
165            }
166        }
167        else if (strncmp(argv[arg], "measure=", 8) == 0) {
168            char *name = argv[arg]+8;
169            if (strcmp(name, "dump") == 0) {
170                measure = NULL;
171                dump = true;
172            }
173            else {
174                int i;
175                for (i = 0; measure_opts[i].name; i++) {
176                    if (strcmp(measure_opts[i].name, name) == 0) {
177                        measure = &measure_opts[i];
178                        break;
179                    }
180                }
181
182                if (measure_opts[i].name) {
183                    dump = false;
184                }
185                else {
186                    args_ok = false;
187                    printf("ERROR: unkown measure \"%s\"\n", name);
188                }
189            }
190        }
191        else if (strncmp(argv[arg], "seed=", 5) == 0) {
192            char *seedarg = argv[arg]+5;
193            unsigned long seed = strtoul(seedarg, NULL, 10);
194            srand(seed);
195        }
196        else {
197            args_ok = false;
198            printf("ERROR: unkown argument %s\n", argv[arg]);
199        }
200    }
201    if (!args_ok) {
202        usage(argv[0]);
203        return 1;
204    }
205
206    assert(size_wanted > 0);
207    assert(runs > 0);
208    assert(reset);
209    assert(measure || dump);
210
211    errval_t err;
212    struct capref frame;
213    size_t size;
214    err = frame_alloc(&frame, size_wanted, &size);
215    assert_err(err, "alloc");
216    assert(size >= size_wanted);
217    printf("got %zu bytes\n", size);
218
219    struct memobj *m;
220    struct vregion *v;
221    void *addr;
222
223    err = vspace_map_one_frame(&addr, size, frame, &m, &v);
224    assert_err(err, "map");
225
226    if (dump) {
227        reset_and_dump(addr, size_wanted, runs, reset->fn, reset->name);
228    }
229    else {
230        bench_init();
231
232        char *bench_name = malloc(strlen(reset->name)+strlen(measure->name)+2);
233        strcpy(bench_name, reset->name);
234        strcat(bench_name, ":");
235        strcat(bench_name, measure->name);
236        test(addr, size_wanted, runs, reset->fn, measure->fn, bench_name);
237
238        free(bench_name);
239    }
240
241    printf("client done\n");
242
243    vregion_destroy(v);
244    cap_destroy(frame);
245
246    return 0;
247}
248