1/*
2 * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdlib.h>
11#include <stdio.h>
12//#include <time.h>
13#include <barrelfish/barrelfish.h>
14#include <barrelfish/sys_debug.h>
15#include <barrelfish/deferred.h>
16#include <devif/queue_interface.h>
17#include <devif/backends/loopback_devif.h>
18#include <devif/backends/null.h>
19#include <bench/bench.h>
20#include <vfs/vfs.h>
21
22//#define DEBUG(x...) printf("devif_test: " x)
23#define DEBUG(x...) do {} while (0)
24
25#define BUF_SIZE 2048
26#define NUM_BUFS 128
27#define MEMORY_SIZE BUF_SIZE*NUM_BUFS
28
29#define NUM_REGIONS 128
30#define NUM_ROUNDS 100000
31#define NUM_STACKS 10
32
33static struct capref memory;
34static regionid_t regid;
35static struct frame_identity id;
36static lpaddr_t phys;
37
38static void* va;
39
40struct direct_state {
41    struct list_ele* first;
42    struct list_ele* last;
43};
44
45struct list_ele{
46    regionid_t rid;
47    bufferid_t bid;
48    lpaddr_t addr;
49    size_t len;
50    uint64_t flags;
51
52    struct list_ele* next;
53};
54
55static struct loopback_queue* queue;
56static struct null_q* null_q[NUM_STACKS+1];
57static struct devq* que;
58
59static cycles_t tot_deq = 0;
60static cycles_t tot_enq = 0;
61static cycles_t tot_reg = 0;
62static cycles_t tot_dereg = 0;
63static cycles_t start_enq = 0, end_enq = 0;
64static cycles_t start_deq = 0, end_deq = 0;
65static cycles_t start_reg = 0, end_reg = 0;
66static cycles_t start_dereg = 0, end_dereg = 0;
67
68static bench_ctl_t *ctl_tmp_en;
69static bench_ctl_t *ctl_tmp_de;
70static bench_ctl_t *ctl_tmp_reg;
71static bench_ctl_t *ctl_tmp_dereg;
72
73static cycles_t tscperus;
74static char* machine_name;
75
76static void dump_results_nfs(char* prefix, bool destroy)
77//static void dump_results_console(char* prefix, bool destroy)
78{
79    char buffer[512];
80
81    // first 10 % is warmup
82    if (ctl_tmp_en == NULL) {
83        return;
84    }
85
86    for (int i = NUM_ROUNDS/10 ; i < NUM_ROUNDS; i++) {
87#ifdef BENCH_DEVQ
88        sprintf(buffer, ";%s_devq;enqueue;%lu;dequeue;%lu;register;%lu;deregister;%lu \n",
89#else
90        sprintf(buffer, ";%s;enqueue;%lu;dequeue;%lu;register;%lu;deregister;%lu \n",
91#endif
92                prefix,
93                ctl_tmp_en->data[i], ctl_tmp_de->data[i], ctl_tmp_reg->data[i],
94                ctl_tmp_dereg->data[i]);
95        printf("%s", buffer);
96    }
97
98    if (destroy) {
99        bench_ctl_destroy(ctl_tmp_dereg);
100        bench_ctl_destroy(ctl_tmp_reg);
101        bench_ctl_destroy(ctl_tmp_de);
102        bench_ctl_destroy(ctl_tmp_en);
103    }
104}
105
106static void test_register(void)
107{
108    errval_t err;
109    struct capref regions[NUM_REGIONS];
110    regionid_t rids[NUM_REGIONS];
111
112    tot_reg = 0;
113    tot_dereg = 0;
114
115    ctl_tmp_reg = calloc(1, sizeof(*ctl_tmp_reg));
116    ctl_tmp_reg->mode = BENCH_MODE_FIXEDRUNS;
117    ctl_tmp_reg->result_dimensions = 1;
118    ctl_tmp_reg->min_runs = NUM_ROUNDS;
119    ctl_tmp_reg->data = calloc(ctl_tmp_reg->min_runs * ctl_tmp_reg->result_dimensions,
120                       sizeof(*ctl_tmp_de->data));
121
122    ctl_tmp_dereg = calloc(1, sizeof(*ctl_tmp_dereg));
123    ctl_tmp_dereg->mode = BENCH_MODE_FIXEDRUNS;
124    ctl_tmp_dereg->result_dimensions = 1;
125    ctl_tmp_dereg->min_runs = NUM_ROUNDS;
126    ctl_tmp_dereg->data = calloc(ctl_tmp_dereg->min_runs * ctl_tmp_dereg->result_dimensions,
127                       sizeof(*ctl_tmp_dereg->data));
128
129    for (int i = 0; i < NUM_REGIONS; i++) {
130        err = frame_alloc(&regions[i], BASE_PAGE_SIZE, NULL);
131        if (err_is_fail(err)){
132            USER_PANIC("Allocating cap failed \n");
133        }
134    }
135
136    srand(rdtscp());
137    int idx = 0;
138    struct capref ret;
139    cycles_t res1;
140    cycles_t res2;
141    for (int i = 0; i < NUM_ROUNDS; i++) {
142        idx = i % NUM_REGIONS;
143        start_reg = rdtscp();
144        err = devq_register(que, regions[idx], &rids[idx]);
145        end_reg = rdtscp();
146        if (err_is_fail(err)){
147            USER_PANIC("Registering memory to devq failed: %s \n",
148                        err_getstring(err));
149        } else {
150            tot_reg += end_reg - start_reg;
151            res1 = end_reg - start_reg;
152            bench_ctl_add_run(ctl_tmp_reg, &res1);
153        }
154
155        start_dereg = rdtscp();
156        err = devq_deregister(que, rids[idx], &ret);
157        end_dereg = rdtscp();
158        if (err_is_fail(err)){
159            USER_PANIC("Registering memory to devq failed: %s\n",
160                       err_getstring(err));
161        } else {
162            tot_dereg += end_dereg - start_dereg;
163            res2 = end_dereg - start_dereg;
164            bench_ctl_add_run(ctl_tmp_dereg, &res2);
165        }
166    }
167
168    for (int i = 0; i < NUM_REGIONS; i++) {
169        err = cap_destroy(regions[i]);
170        if (err_is_fail(err)){
171            USER_PANIC("Destroy region failed: %s\n",
172                       err_getstring(err));
173        }
174    }
175
176    //bench_ctl_dump_analysis(ctl_tmp_dereg, 0, "deregister", tscperus);
177    //bench_ctl_dump_analysis(ctl_tmp_reg, 0, "register", tscperus);
178
179}
180
181static void test_randomized_test(void)
182{
183    errval_t err;
184    regionid_t rid;
185    genoffset_t offset;
186    genoffset_t length;
187    genoffset_t valid_data;
188    genoffset_t valid_length;
189    uint64_t flags;
190
191    tot_enq = 0;
192    tot_deq = 0;
193
194    ctl_tmp_en = calloc(1, sizeof(*ctl_tmp_en));
195    ctl_tmp_en->mode = BENCH_MODE_FIXEDRUNS;
196    ctl_tmp_en->result_dimensions = 1;
197    ctl_tmp_en->min_runs = NUM_ROUNDS;
198    ctl_tmp_en->data = calloc(ctl_tmp_en->min_runs * ctl_tmp_en->result_dimensions,
199                       sizeof(*ctl_tmp_de->data));
200
201    ctl_tmp_de = calloc(1, sizeof(*ctl_tmp_en));
202    ctl_tmp_de->mode = BENCH_MODE_FIXEDRUNS;
203    ctl_tmp_de->result_dimensions = 1;
204    ctl_tmp_de->min_runs = NUM_ROUNDS;
205    ctl_tmp_de->data = calloc(ctl_tmp_de->min_runs * ctl_tmp_de->result_dimensions,
206                       sizeof(*ctl_tmp_de->data));
207
208    srand(rdtscp());
209    int idx = 0;
210    cycles_t res;
211    // enqueue from the beginning of the region
212    for (int i = 0; i < NUM_ROUNDS; i++) {
213
214        idx = i % NUM_BUFS;
215        start_enq = rdtscp();
216
217        err = devq_enqueue(que, regid, idx*BUF_SIZE, BUF_SIZE,
218                           0, BUF_SIZE, 0);
219
220        end_enq = rdtscp();
221        if (err_is_fail(err)){
222            USER_PANIC("Enqueue failed: %s \n", err_getstring(err));
223        } else {
224            tot_enq += end_enq - start_enq;
225            res = end_enq - start_enq;
226            bench_ctl_add_run(ctl_tmp_de, &res);
227        }
228
229        start_deq = rdtscp();
230        err = devq_dequeue(que, &rid, &offset, &length, &valid_data,
231                           &valid_length, &flags);
232        end_deq = rdtscp();
233        if (err_is_ok(err)){
234            tot_deq += end_deq - start_deq;
235            res = end_deq - start_deq;
236            bench_ctl_add_run(ctl_tmp_en, &res);
237        } else {
238            USER_PANIC("Dequeue failed: %s \n", err_getstring(err));
239        }
240    }
241
242    //bench_ctl_dump_analysis(ctl_tmp_de, 0, "enqueue", tscperus);
243    //bench_ctl_dump_analysis(ctl_tmp_en, 0, "dequeue", tscperus);
244}
245
246int main(int argc, char *argv[])
247{
248
249    if (argc > 1) {
250        machine_name = argv[1];
251    } else {
252        machine_name = "default";
253    }
254
255    errval_t err;
256
257    // mount_vfs
258    vfs_init();
259
260    char fname[256];
261    err = vfs_mount("/nfs", "nfs://10.110.4.4/mnt/local/nfs/haeckir");
262    if(err_is_fail(err)) {
263        USER_PANIC("vfs_mount: %s \n", err_getstring(err));
264    }
265
266    sprintf(fname, "/nfs/%s", machine_name);
267    err = vfs_mkdir(fname);
268    if (err_is_fail(err)) {
269        printf("Folder %s already exists \n", fname);
270    } else {
271        printf("Creating folder %s \n", fname);
272    }
273
274    // Allocate memory
275    err = frame_alloc(&memory, MEMORY_SIZE, NULL);
276    if (err_is_fail(err)){
277        USER_PANIC("Allocating cap failed \n");
278    }
279
280    // RX frame
281    err = frame_identify(memory, &id);
282    if (err_is_fail(err)) {
283        USER_PANIC("Frame identify failed \n");
284    }
285
286    err = vspace_map_one_frame_attr(&va, id.bytes, memory,
287                                    VREGION_FLAGS_READ, NULL, NULL);
288    if (err_is_fail(err)) {
289        USER_PANIC("Frame mapping failed \n");
290    }
291
292    phys = id.base;
293
294    debug_printf("Descriptor queue test started \n");
295    err = loopback_queue_create(&queue);
296    if (err_is_fail(err)){
297        USER_PANIC("Allocating devq failed \n");
298    }
299
300    // stack null queue on top
301    err = null_create(&null_q[0], (struct devq*) queue);
302    if (err_is_fail(err)) {
303        USER_PANIC("Allocating null q failed \n");
304    }
305
306    que = (struct devq*) queue;
307
308    err = devq_register(que, memory, &regid);
309    if (err_is_fail(err)){
310        USER_PANIC("Registering memory to devq failed \n");
311    }
312
313    err = sys_debug_get_tsc_per_ms(&tscperus);
314    assert(err_is_ok(err));
315    tscperus /= 1000;
316
317    printf("Starting randomized queue\n");
318    que = (struct devq*) queue;
319
320    test_register();
321
322    test_randomized_test();
323
324    dump_results_nfs("Loopback", true);
325
326#if 0
327    ctl_tmp_en = devq_get_benchmark_data(que, 0);
328    ctl_tmp_de = devq_get_benchmark_data(que, 1);
329    ctl_tmp_reg = devq_get_benchmark_data(que, 2);
330    ctl_tmp_dereg = devq_get_benchmark_data(que, 3);
331    dump_results_nfs("Loopback_bcalls", false);
332#endif
333    char name[512];
334    sprintf(name, "Null %d", 1);
335    for (int i = 0; i < 10; i++) {
336        printf("############################################################ \n");
337
338        err = devq_deregister(que, regid, &memory);
339        if (err_is_fail(err)){
340            USER_PANIC("Deregistering memory from devq failed: %s \n",
341                       err_getstring(err));
342        }
343
344        printf("Starting randomized test debug\n");
345        que = (struct devq*) null_q[i];
346
347        test_register();
348
349        err = devq_register(que, memory, &regid);
350        if (err_is_fail(err)){
351            USER_PANIC("Registering memory to devq failed \n");
352        }
353
354        test_randomized_test();
355
356        dump_results_nfs(name, true);
357
358        sprintf(name, "Null %d", i+2);
359
360        // stack null queue on top
361        err = null_create(&null_q[i+1], (struct devq*) null_q[i]);
362        if (err_is_fail(err)) {
363            USER_PANIC("Allocating null q failed \n");
364        }
365
366    }
367    printf("SUCCESS! \n");;
368
369}
370
371