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/waitset.h>
15#include <barrelfish/waitset_chan.h>
16#include <barrelfish/deferred.h>
17#include <devif/queue_interface.h>
18#include <devif/backends/net/sfn5122f_devif.h>
19#include <devif/backends/net/e10k_devif.h>
20#include <devif/backends/debug.h>
21#include <devif/backends/descq.h>
22#include <devif/backends/null.h>
23#include <bench/bench.h>
24#include <net_interfaces/flags.h>
25
26//#define BENCH
27
28//#define DEBUG(x...) printf("devif_test: " x)
29#define DEBUG(x...) do {} while (0)
30
31#define BUF_SIZE 2048
32#define NUM_BUFS 128
33#define MEMORY_SIZE BUF_SIZE*NUM_BUFS
34
35static struct capref memory;
36static regionid_t regid;
37static struct frame_identity id;
38static lpaddr_t phys;
39
40static volatile uint32_t num_tx = 0;
41static volatile uint32_t num_rx = 0;
42
43static void* va;
44
45struct direct_state {
46    struct list_ele* first;
47    struct list_ele* last;
48};
49
50struct list_ele{
51    regionid_t rid;
52    bufferid_t bid;
53    lpaddr_t addr;
54    size_t len;
55    uint64_t flags;
56
57    struct list_ele* next;
58};
59
60static struct descq* queue;
61static struct debug_q* debug_q;
62static struct null_q* null_q;
63static struct devq* que;
64
65static volatile bool enq[NUM_BUFS];
66
67#ifdef BENCH
68static uint64_t tot_deq = 0;
69static uint64_t tot_enq = 0;
70static uint64_t tot_notify = 0;
71static uint64_t start_enq = 0, end_enq = 0;
72static uint64_t start_deq = 0, end_deq = 0;
73static uint64_t start_not = 0, end_not = 0;
74
75static double avg_deq, avg_enq, avg_not;
76static double avg_deq_d, avg_enq_d, avg_not_d;
77static double avg_deq_n, avg_enq_n, avg_not_n;
78#endif
79
80
81static errval_t descq_notify(struct descq* q)
82{
83    errval_t err = SYS_ERR_OK;
84
85    regionid_t rid;
86    genoffset_t offset;
87    genoffset_t length;
88    genoffset_t valid_data;
89    genoffset_t valid_length;
90    uint64_t flags;
91
92    while(err_is_ok(err)) {
93
94#ifdef BENCH
95        start_deq = rdtsc();
96#endif
97        err = devq_dequeue(que, &rid, &offset, &length, &valid_data,
98                           &valid_length, &flags);
99        if (err_is_ok(err)){
100#ifdef BENCH
101            end_deq = rdtsc();
102            tot_deq += end_deq - start_deq;
103#endif
104            num_rx++;
105            enq[offset/BUF_SIZE] = false;
106        }
107    }
108    return SYS_ERR_OK;
109}
110
111#define NUM_REGIONS 128
112
113#define NUM_ROUNDS 1000000
114
115static void test_register(void)
116{
117    errval_t err;
118    struct capref regions[NUM_REGIONS];
119    regionid_t rids[NUM_REGIONS];
120    bool is_reg[NUM_REGIONS];
121
122    for (int i = 0; i < NUM_REGIONS; i++) {
123        err = frame_alloc(&regions[i], BASE_PAGE_SIZE, NULL);
124        if (err_is_fail(err)){
125            USER_PANIC("Allocating cap failed \n");
126        }
127        is_reg[i] = false;
128    }
129
130    srand(rdtsc());
131    int idx = 0;
132    struct capref ret;
133    for (int i = 0; i < NUM_ROUNDS/10; i++) {
134        idx = rand() % NUM_REGIONS;
135        if (is_reg[idx]) {
136            err = devq_deregister(que, rids[idx], &ret);
137            if (err_is_fail(err)){
138                USER_PANIC("Registering memory to devq failed: %s\n",
139                           err_getstring(err));
140            }
141            is_reg[idx] = false;
142        } else {
143            err = devq_register(que, regions[idx], &rids[idx]);
144            if (err_is_fail(err)){
145                USER_PANIC("Registering memory to devq failed: %s \n",
146                            err_getstring(err));
147            }
148            is_reg[idx] = true;
149        }
150    }
151
152    for (int i = 0; i < NUM_REGIONS; i++) {
153        if (is_reg[i]) {
154            err = devq_deregister(que, rids[i], &ret);
155            if (err_is_fail(err)){
156                USER_PANIC("Registering memory to devq failed: %s\n",
157                           err_getstring(err));
158            }
159        }
160    }
161}
162
163static void test_enqueue_dequeue(void)
164{
165    errval_t err;
166    num_tx = 0;
167    num_rx = 0;
168    // enqueue from the beginning of the region
169    for (int i = 0; i < NUM_BUFS/8; i++) {
170        err = devq_enqueue(que, regid, i*BUF_SIZE, BUF_SIZE,
171                           0, BUF_SIZE, 0);
172        if (err_is_fail(err)){
173            USER_PANIC("Enqueue failed: %s \n", err_getstring(err));
174        } else {
175            num_tx++;
176        }
177    }
178
179
180    // enqueue from the end of the region
181    for (int i = 0; i < NUM_BUFS/8; i++) {
182        err = devq_enqueue(que, regid, MEMORY_SIZE-((i+1)*BUF_SIZE),
183                           BUF_SIZE, 0, BUF_SIZE, 0);
184        if (err_is_fail(err)){
185            USER_PANIC("Enqueue failed: %s \n", err_getstring(err));
186        } else {
187            num_tx++;
188        }
189    }
190
191    err = devq_notify(que);
192    if (err_is_fail(err)) {
193        USER_PANIC("Devq notify failed: %s\n", err_getstring(err));
194    }
195
196    while(num_rx < (NUM_BUFS/4)) {
197        event_dispatch(get_default_waitset());
198    }
199}
200
201
202static void test_failures(void)
203{
204    errval_t err;
205    num_tx = 0;
206    num_rx = 0;
207
208
209    err = devq_enqueue(que, regid, 0, BUF_SIZE,
210                       0, BUF_SIZE, 0);
211    if (err_is_fail(err)) {
212        USER_PANIC("Enqueue failed: %s \n", err_getstring(err));
213    }
214
215    // do the same enqueue again
216
217    err = devq_enqueue(que, regid, 0, BUF_SIZE,
218                       0, BUF_SIZE, 0);
219    if (err_is_ok(err)) {
220        USER_PANIC("Enqueue should fail! \n");
221    }
222
223    // revert to original state
224    err = devq_notify(que);
225    if (err_is_fail(err)) {
226        USER_PANIC("Enqueue failed: %s \n", err_getstring(err));
227    }
228
229    while(num_rx < 1) {
230        event_dispatch(get_default_waitset());
231    }
232
233    err = devq_enqueue(que, regid, 4096, BUF_SIZE,
234                       0, BUF_SIZE, 0);
235    if (err_is_fail(err)) {
236        USER_PANIC("Enqueue failed: %s \n", err_getstring(err));
237    }
238
239    // do an overlapping enqueue
240    err = devq_enqueue(que, regid, 5120, BUF_SIZE,
241                       0, BUF_SIZE, 0);
242    if (err_is_ok(err)) {
243        USER_PANIC("Enqueue should fail! \n");
244    }
245
246    // revert to original state
247    err = devq_notify(que);
248    if (err_is_fail(err)) {
249        USER_PANIC("Enqueue failed: %s \n", err_getstring(err));
250    }
251
252    while(num_rx < 2) {
253        event_dispatch(get_default_waitset());
254    }
255
256    // enqueue buffer not in region
257    err = devq_enqueue(que, regid, MEMORY_SIZE+BUF_SIZE, BUF_SIZE,
258                       0, BUF_SIZE, 0);
259    if (err_is_ok(err)) {
260        USER_PANIC("Enqueue should fail! \n");
261    }
262
263}
264
265
266static void test_randomized_test(void)
267{
268    errval_t err;
269    num_tx = 0;
270    num_rx = 0;
271    memset((void*)enq, 0, sizeof(bool)*NUM_BUFS);
272
273#ifdef BENCH
274    tot_enq = 0;
275    tot_deq = 0;
276    tot_notify = 0;
277#endif
278
279    for (int i = 0; i < NUM_BUFS; i++) {
280        enq[i] = false;
281    }
282
283    srand(rdtsc());
284    int idx = 0;
285    // enqueue from the beginning of the region
286    for (int i = 0; i < NUM_ROUNDS; i++) {
287        for (int j = 0; j < NUM_BUFS/2; j++) {
288            idx = rand() % NUM_BUFS;
289            while (enq[idx]) {
290                idx = rand() % NUM_BUFS;
291            }
292
293#ifdef BENCH
294            start_enq = rdtsc();
295#endif
296            err = devq_enqueue(que, regid, idx*BUF_SIZE, BUF_SIZE,
297                               0, BUF_SIZE, 0);
298            if (err_is_fail(err)){
299                USER_PANIC("Enqueue failed: %s \n", err_getstring(err));
300            } else {
301#ifdef BENCH
302                end_enq = rdtsc();
303                tot_enq += end_enq - start_enq;
304#endif
305                enq[idx] = true;
306                num_tx++;
307            }
308        }
309
310        if ((i % 100000) == 0) {
311            printf("Round %d \n", i);
312        }
313
314#ifdef BENCH
315        start_not = rdtsc();
316#endif
317        err = devq_notify(que);
318        if (err_is_fail(err)) {
319            USER_PANIC("Devq notify failed: %s\n", err_getstring(err));
320        }
321#ifdef BENCH
322        end_not = rdtsc();
323        tot_notify += end_not - start_not;
324#endif
325        while(num_rx < ((i+1)*NUM_BUFS/2)) {
326            event_dispatch(get_default_waitset());
327        }
328    }
329
330}
331
332int main(int argc, char *argv[])
333{
334    errval_t err;
335    // Allocate memory
336    err = frame_alloc(&memory, MEMORY_SIZE, NULL);
337    if (err_is_fail(err)){
338        USER_PANIC("Allocating cap failed \n");
339    }
340
341    // RX frame
342    err = frame_identify(memory, &id);
343    if (err_is_fail(err)) {
344        USER_PANIC("Frame identify failed \n");
345    }
346
347    err = vspace_map_one_frame_attr(&va, id.bytes, memory,
348                                    VREGION_FLAGS_READ, NULL, NULL);
349    if (err_is_fail(err)) {
350        USER_PANIC("Frame mapping failed \n");
351    }
352
353    phys = id.base;
354
355    struct descq_func_pointer f;
356    f.notify = descq_notify;
357
358    debug_printf("Descriptor queue test started \n");
359    err = descq_create(&queue, DESCQ_DEFAULT_SIZE, "test_queue",
360                       false, NULL, &f);
361    if (err_is_fail(err)){
362        USER_PANIC("Allocating devq failed \n");
363    }
364
365    // stack debug queue on top
366    err = debug_create(&debug_q, (struct devq*) queue);
367    if (err_is_fail(err)) {
368        USER_PANIC("Allocating debug q failed \n");
369    }
370
371    // stack null queue on top
372    err = null_create(&null_q, (struct devq*) debug_q);
373    if (err_is_fail(err)) {
374        USER_PANIC("Allocating null q failed \n");
375    }
376
377    que = (struct devq*) debug_q;
378
379    err = devq_register(que, memory, &regid);
380    if (err_is_fail(err)){
381        USER_PANIC("Registering memory to devq failed \n");
382    }
383
384    printf("Starting failure handling test \n");
385    test_failures();
386
387    printf("Starting register/deregister test \n");
388    test_register();
389
390    printf("Starting enqueue/dequeue test \n");
391    test_enqueue_dequeue();
392
393    printf("Starting randomized test debug\n");
394    que = (struct devq*) debug_q;
395    test_randomized_test();
396
397#ifdef BENCH
398    avg_enq_d = ((double) tot_deq)/(NUM_ROUNDS*NUM_BUFS/2);
399    avg_deq_d = ((double) tot_enq)/(NUM_ROUNDS*NUM_BUFS/2);
400    avg_not_d = ((double) tot_notify)/NUM_ROUNDS;
401
402    printf("AVG deq debug %f \n", avg_enq_d);
403    printf("AVG enq debug %f \n", avg_deq_d);
404    printf("AVG notify debug %f \n", avg_not_d);
405    printf("############################################################ \n");
406
407
408    err = devq_deregister(que, regid, &memory);
409    if (err_is_fail(err)){
410        USER_PANIC("Deregistering memory from devq failed: %s \n",
411                   err_getstring(err));
412    }
413
414    printf("Starting randomized test non debug\n");
415    que = (struct devq*) queue;
416
417    err = devq_register(que, memory, &regid);
418    if (err_is_fail(err)){
419        USER_PANIC("Registering memory to devq failed \n");
420    }
421
422    test_randomized_test();
423
424    avg_enq = ((double) tot_deq)/(NUM_ROUNDS*NUM_BUFS/2);
425    avg_deq = ((double) tot_enq)/(NUM_ROUNDS*NUM_BUFS/2);
426    avg_not = ((double) tot_notify)/NUM_ROUNDS;
427
428    printf("AVG deq %f \n", avg_enq);
429    printf("AVG enq %f \n", avg_deq);
430    printf("AVG notify %f \n", avg_not);
431    printf("############################################################ \n");
432
433    err = devq_deregister(que, regid, &memory);
434    if (err_is_fail(err)){
435        USER_PANIC("Deregistering memory from devq failed: %s \n",
436                   err_getstring(err));
437    }
438
439    printf("Starting randomized test debug + null\n");
440    que = (struct devq*) null_q;
441
442    err = devq_register(que, memory, &regid);
443    if (err_is_fail(err)){
444        USER_PANIC("Registering memory to devq failed \n");
445    }
446
447    test_randomized_test();
448
449    avg_enq_n = ((double) tot_deq)/(NUM_ROUNDS*NUM_BUFS/2);
450    avg_deq_n = ((double) tot_enq)/(NUM_ROUNDS*NUM_BUFS/2);
451    avg_not_n = ((double) tot_notify)/NUM_ROUNDS;
452
453    printf("AVG deq debug + null %f \n", avg_enq_n);
454    printf("AVG enq debug + null %f \n", avg_deq_n);
455    printf("AVG notify debug + null %f \n", avg_not_n);
456
457    printf("############################################################ \n");
458
459    printf("AVG enq overhead null %f \n", avg_enq_n - avg_enq_d);
460    printf("AVG deq overhead null %f \n", avg_deq_n - avg_deq_d);
461    printf("AVG notify overhead null %f \n", avg_not_n - avg_not_d);
462
463    printf("############################################################ \n");
464
465    printf("AVG enq overhead debug %f \n", avg_enq_d-avg_enq);
466    printf("AVG deq overhead debug %f \n", avg_deq_d - avg_deq);
467    printf("AVG notify overhead debug %f \n", avg_not_d - avg_not);
468#endif
469
470    err = devq_deregister(que, regid, &memory);
471    if (err_is_fail(err)){
472        USER_PANIC("Deregistering memory from devq failed: %s \n",
473                   err_getstring(err));
474    }
475
476    printf("SUCCESS \n");
477}
478
479