1/**
2 * \file
3 * \brief ahci benchmarks
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18#include <inttypes.h>
19#include <barrelfish/barrelfish.h>
20#include <limits.h>
21#include <trace/trace.h>
22#include <vfs/vfs.h>
23#include <vfs/vfs_path.h>
24
25#define ENTRIES(array)  (sizeof(array) / sizeof(array[0]))
26
27static const char *cwd = "/";
28
29static int mount(const char *path, const char *uri)
30{
31    char *apath = vfs_path_mkabsolute(cwd, path);
32    errval_t err = vfs_mount(apath, uri);
33    free(apath);
34    if (err_is_fail(err)) {
35        DEBUG_ERR(err, "in vfs_mount %s %s", path, uri);
36        return 1;
37    }
38    return 0;
39}
40
41static double
42dd_bench(char *source, char *target, size_t blocksize, size_t count)
43{
44    vfs_handle_t source_vh = NULL;
45    vfs_handle_t target_vh = NULL;
46
47    size_t blocks_written = 0;
48
49    size_t total_bytes_read = 0;
50    size_t total_bytes_written = 0;
51
52    errval_t err;
53    double ret = 0;
54    double kbps = 0.0;
55
56    err = vfs_open(source, &source_vh);
57    if (err_is_fail(err)) {
58        printf("%s: %s (%ld)\n", source, err_getstring(err), err);
59        return -1;
60    }
61
62    err = vfs_create(target, &target_vh);
63    if (err_is_fail(err)) {
64        // close source handle
65        if (source_vh != NULL)
66            vfs_close(source_vh);
67        printf("%s: %s (%ld)\n", target, err_getstring(err), err);
68        return -1;
69    }
70
71    uint8_t *buffer = malloc(blocksize);
72
73    uint64_t tscperms;
74    err = sys_debug_get_tsc_per_ms(&tscperms);
75    assert(err_is_ok(err));
76
77    uint64_t start = rdtsc();
78
79    if (buffer == NULL) {
80        ret = -2;
81        printf("failed to allocate buffer of size %zd\n", blocksize);
82        goto out;
83    }
84
85    size_t rsize, wsize;
86    do {
87        err = vfs_read(source_vh, buffer, blocksize, &rsize);
88        if (err_is_fail(err)) {
89            DEBUG_ERR(err, "error reading file");
90            ret = -1;
91            goto out;
92        }
93
94        total_bytes_read += rsize;
95
96        size_t wpos = 0;
97        while (wpos < rsize) {
98            if (wpos > 0)
99                printf("was unable to write the whole chunk of size %zd. Now at pos: %zd of buffer\n", rsize, wpos);
100
101            err = vfs_write(target_vh, &buffer[wpos], rsize - wpos, &wsize);
102            if (err_is_fail(err) || wsize == 0) {
103                DEBUG_ERR(err, "error writing file");
104                ret = -1;
105                goto out;
106            }
107            wpos += wsize;
108            total_bytes_written += wsize;
109        }
110
111        blocks_written++;
112
113    } while (rsize > 0 && !(count > 0 && blocks_written >= count));
114
115out:
116    if (buffer != NULL)
117        free(buffer);
118
119    if (source_vh != NULL) {
120        err = vfs_close(source_vh);
121        if (err_is_fail(err)) {
122            DEBUG_ERR(err, "in vfs_close");
123        }
124    }
125
126    if (target_vh != NULL) {
127        err = vfs_close(target_vh);
128        if (err_is_fail(err)) {
129            DEBUG_ERR(err, "in vfs_close");
130        }
131    }
132
133    uint64_t stop = rdtsc();
134    uint64_t elapsed_msecs = ((stop - start) / tscperms);
135    double elapsed_secs = (double)elapsed_msecs/1000.0;
136
137    kbps = ((double)total_bytes_written / 1024.0) / elapsed_secs;
138
139    if (ret == 0)
140        return kbps;
141    else
142        return ret;
143}
144
145struct bench_res {
146    double read;
147    double write;
148};
149
150static errval_t
151fill_bench(char *target, uint8_t *buffer, size_t blocksize, size_t count, struct bench_res *result)
152{
153    vfs_handle_t target_vh = NULL;
154
155    size_t blocks_written = 0;
156    size_t blocks_read = 0;
157
158    size_t total_bytes_read = 0;
159    size_t total_bytes_written = 0;
160
161    uint64_t start = 0, stop = 0;
162    errval_t err;
163
164    uint64_t tscperms;
165    err = sys_debug_get_tsc_per_ms(&tscperms);
166    assert(err_is_ok(err));
167
168    errval_t ret = 0;
169
170    err = vfs_open(target, &target_vh);
171    if (err_is_fail(err)) {
172        printf("%s: %s (%ld)\n", target, err_getstring(err), err);
173        return err;
174    }
175
176    start = rdtsc();
177
178    if (buffer == NULL) {
179        ret = -2;
180        printf("failed to allocate buffer of size %zd\n", blocksize);
181        goto out;
182    }
183
184    size_t wsize;
185    do {
186        // initialize buffer
187        for (size_t i = 0; i < blocksize; i += sizeof(size_t))
188            *((size_t *)(buffer + i)) = blocks_written;
189
190        // write to file
191        size_t wpos = 0;
192        while (wpos < blocksize) {
193            if (wpos > 0)
194                printf("was unable to write the whole chunk of size %zd. Now at pos: %zd of buffer\n", blocksize, wpos);
195
196            err = vfs_write(target_vh, &buffer[wpos], blocksize - wpos, &wsize);
197            if (err_is_fail(err) || wsize == 0) {
198                DEBUG_ERR(err, "error writing file");
199                ret = err;
200                goto out;
201            }
202            wpos += wsize;
203            total_bytes_written += wsize;
204        }
205
206        blocks_written++;
207
208    } while (blocksize > 0 && !(count > 0 && blocks_written >= count));
209
210    err = vfs_close(target_vh);
211    if (err_is_fail(err)) {
212        DEBUG_ERR(err, "in vfs_close");
213        goto out;
214    }
215
216    stop = rdtsc();
217    {
218        uint64_t elapsed_msecs = ((stop - start) / tscperms);
219        double elapsed_secs = (double)elapsed_msecs/1000.0;
220
221        result->write = ((double)total_bytes_written / 1024.0) / elapsed_secs;
222	printf("%lf\n", result->write);
223    }
224
225    err = vfs_open(target, &target_vh);
226    if (err_is_fail(err)) {
227        printf("%s: %s (%ld)\n", target, err_getstring(err), err);
228        goto out;
229    }
230    err = vfs_seek(target_vh, VFS_SEEK_SET, 0);
231    if (err_is_fail(err)) {
232        DEBUG_ERR(err, "seeking failed");
233        ret = err;
234        goto out;
235    }
236
237    start = rdtsc();
238
239    size_t rsize;
240    do {
241        // read
242        size_t rpos = 0;
243        while (rpos < blocksize) {
244            if (rpos > 0)
245                printf("was unable to read whole chunk of size %zd. Now at pos: %zd of buffer\n", blocksize, rpos);
246
247            err = vfs_read(target_vh, &buffer[rpos], blocksize - rpos, &rsize);
248            if (err_is_fail(err) || wsize == 0) {
249                DEBUG_ERR(err, "error reading file");
250                ret = err;
251                goto out;
252            }
253            rpos += rsize;
254            total_bytes_read += rsize;
255        }
256
257        // verify data
258        for (size_t i = 0; i < blocksize; i += sizeof(size_t)) {
259            if (*((size_t *)(buffer + i)) != blocks_read) {
260                printf("Verification failed! Block %zd, value %zd\n", blocks_read, *((size_t *)(buffer + i)) );
261                ret = err;
262                goto out;
263            }
264        }
265
266        blocks_read++;
267    } while (blocksize > 0 && !(count > 0 && blocks_read >= count));
268
269out:
270    if (target_vh != NULL) {
271        err = vfs_close(target_vh);
272        if (err_is_fail(err)) {
273            DEBUG_ERR(err, "in vfs_close");
274            ret = err;
275        }
276    }
277
278    stop = rdtsc();
279    {
280        uint64_t elapsed_msecs = ((stop - start) / tscperms);
281        double elapsed_secs = (double)elapsed_msecs/1000.0;
282
283        result->read = ((double)total_bytes_read / 1024.0) / elapsed_secs;
284	    printf("%lf\n", result->read);
285    }
286
287    return ret;
288}
289
290
291
292static int
293ahci_benchmark(int argc, char *argv[])
294{
295    if (argc != 3) {
296        printf("usage: %s <source> <target>\nsource and target must be absolute paths!\n", argv[0]);
297        return 1;
298    }
299
300    char *source = argv[1];
301    char *target = argv[2];
302
303    printf("Running dd disk test\n");
304
305    size_t blocksize, count = 16;
306    dd_bench(source, target, 131072, 16);
307
308
309    for (blocksize = 131072; blocksize >= 512; blocksize /= 2, count *= 2) {
310        double r1, r2, r3;
311        r1 = dd_bench(source, target, blocksize, count);
312        r2 = dd_bench(source, target, blocksize, count);
313        r3 = dd_bench(source, target, blocksize, count);
314        double kbps = (r1 + r2 + r3) / 3;
315        printf("%zd\t%.3lf\n", blocksize, kbps);
316    }
317
318    printf("dd disk test completed\n");
319
320    return 0;
321}
322
323static int
324ahci_fillbench(int argc, char *argv[])
325{
326    if (argc != 2) {
327        printf("usage: %s <target>\ntarget must be an absolute path!\n", argv[0]);
328        return 1;
329    }
330
331    char *target = argv[1];
332
333    printf("Running fill disk test\n");
334
335    size_t blocksize, count = 256;
336    struct bench_res dummy;
337    uint8_t *buffer = malloc(131072);
338    fill_bench(target, buffer, 131072, count, &dummy);
339
340    printf("bs\tread\tvar\twrite\tvar\n");
341
342    for (blocksize = 131072; blocksize >= 512; blocksize /= 2, count *= 2) {
343        struct bench_res r1, r2, r3;
344        fill_bench(target, buffer, blocksize, count, &r1);
345        fill_bench(target, buffer, blocksize, count, &r2);
346        fill_bench(target, buffer, blocksize, count, &r3);
347        double write_kbps = (r1.write + r2.write + r3.write) / 3;
348        double read_kbps = (r1.read + r2.read + r3.read) / 3;
349
350        double write_var = (write_kbps - r1.write) * (write_kbps - r1.write);
351        write_var += (write_kbps - r2.write) * (write_kbps - r2.write);
352        write_var += (write_kbps - r3.write) * (write_kbps - r3.write);
353
354        write_var /= 3;
355
356        double read_var = (read_kbps - r1.read) * (read_kbps - r1.read);
357        read_var += (read_kbps - r2.read) * (read_kbps - r2.read);
358        read_var += (read_kbps - r3.read) * (read_kbps - r3.read);
359
360        read_var /= 3;
361
362        printf("%zd\t%.3lf\t%.3lf\t%.3lf\t%.3lf\n", blocksize, read_kbps, read_var, write_kbps, write_var);
363    }
364
365    free(buffer);
366    printf("fill disk test completed\n");
367
368    return 0;
369
370}
371
372static int
373shuffle_file(int argc, char *argv[])
374{
375    if (argc != 6) {
376        printf("Usage: %s <file> <filesize> <blocksize> <count> <seed>\n", argv[0]);
377
378        return 0;
379    }
380
381    size_t filesize = atoi(argv[2]);
382    size_t blocksize = atoi(argv[3]);
383    size_t count = atoi(argv[4]);
384    size_t randval = atoi(argv[5]);
385    size_t randbit;
386    char * filename = argv[1];
387
388    size_t rsize = 0;
389    size_t wsize = 0;
390
391    int ret = 0;
392
393
394#define RAND_NEXT do {\
395    randbit = ((randval >> 0) ^ (randval >> 3)) & 1;\
396    randval = (randval >> 1) | (randbit << (sizeof(size_t) * CHAR_BIT - 1));\
397} while (0)
398
399#define RAND_BLOCK ((randval % (filesize / blocksize)) * blocksize)
400
401    if (filesize % blocksize != 0) {
402        printf("Please spcifiy the filesize as a multiple of blocksize\n");
403        return 0;
404    }
405
406    uint8_t * buffer = malloc(blocksize);
407
408    if (buffer == NULL) {
409        printf("failed to allocate buffer of size %zd\n", blocksize);
410        return 1;
411    }
412
413    errval_t err;
414    vfs_handle_t f = NULL;
415    char *path = vfs_path_mkabsolute(cwd, filename);
416    err = vfs_open(path, &f);
417
418    if (err_is_fail(err)) {
419        printf("%s: %s\n", path, err_getstring(err));
420        return 1;
421    }
422
423    uint64_t tscperms;
424    err = sys_debug_get_tsc_per_ms(&tscperms);
425    assert(err_is_ok(err));
426
427    //printf("ticks per millisec: %" PRIu64 "\n", tscperms);
428    uint64_t start = rdtsc();
429
430    size_t count2 = count;
431    while (count2--) {
432        RAND_NEXT;
433        vfs_seek(f, VFS_SEEK_SET, RAND_BLOCK);
434
435        err = vfs_read(f, buffer, blocksize, &rsize);
436        if (err_is_fail(err)) {
437            DEBUG_ERR(err, "error reading file");
438            ret = 1;
439            goto out;
440        }
441
442        assert(rsize == blocksize);
443
444        RAND_NEXT;
445        vfs_seek(f, VFS_SEEK_SET, RAND_BLOCK);
446
447        err = vfs_write(f, buffer, blocksize, &wsize);
448        if (err_is_fail(err) || wsize == 0) {
449            DEBUG_ERR(err, "error writing file");
450            ret = 1;
451            goto out;
452        }
453
454        assert(wsize == blocksize);
455    }
456
457    uint64_t stop = rdtsc();
458    uint64_t elapsed_msecs = ((stop - start) / tscperms);
459    double elapsed_secs = (double)elapsed_msecs/1000.0;
460
461    printf("start: %" PRIu64 " stop: %" PRIu64 "\n", start, stop);
462
463    double kbps = ((double)(count * blocksize) / 1024.0) / elapsed_secs;
464
465    printf("%zu bytes read. %zu bytes written. %f s, %f kB/s\n", count * blocksize, count * blocksize, elapsed_secs, kbps);
466
467out:
468    if (buffer != NULL)
469        free(buffer);
470
471    if (f != NULL) {
472        err = vfs_close(f);
473        if (err_is_fail(err)) {
474            DEBUG_ERR(err, "in vfs_close");
475        }
476    }
477
478    return ret;
479}
480
481static int
482rand_bench(char *target, uint8_t *buffer, size_t filesize, size_t blocksize, size_t count, size_t randval, struct bench_res *result)
483{
484    size_t randbit;
485
486    size_t rsize = 0;
487    size_t wsize = 0;
488
489    int ret = 0;
490
491
492#define RAND_NEXT do {\
493    randbit = ((randval >> 0) ^ (randval >> 3)) & 1;\
494    randval = (randval >> 1) | (randbit << (sizeof(size_t) * CHAR_BIT - 1));\
495} while (0)
496
497#define RAND_BLOCK ((randval % (filesize / blocksize)) * blocksize)
498
499    if (filesize % blocksize != 0) {
500        printf("Please spcifiy the filesize as a multiple of blocksize\n");
501        return 0;
502    }
503
504    errval_t err;
505    vfs_handle_t f = NULL;
506    char *path = vfs_path_mkabsolute(cwd, target);
507    err = vfs_open(path, &f);
508
509    if (err_is_fail(err)) {
510        printf("%s: %s\n", path, err_getstring(err));
511        return 1;
512    }
513
514    uint64_t tscperms;
515    err = sys_debug_get_tsc_per_ms(&tscperms);
516    assert(err_is_ok(err));
517
518    //printf("ticks per millisec: %" PRIu64 "\n", tscperms);
519    uint64_t start = rdtsc();
520
521    size_t count2 = count;
522    while (count2--) {
523        RAND_NEXT;
524        vfs_seek(f, VFS_SEEK_SET, RAND_BLOCK);
525
526        err = vfs_read(f, buffer, blocksize, &rsize);
527        if (err_is_fail(err)) {
528            DEBUG_ERR(err, "error reading file");
529            ret = 1;
530            goto out;
531        }
532
533        assert(rsize == blocksize);
534    }
535
536    uint64_t stop = rdtsc();
537    uint64_t elapsed_msecs = ((stop - start) / tscperms);
538    double elapsed_secs = (double)elapsed_msecs/1000.0;
539
540    result->read = ((double)(count * blocksize) / 1024.0) / elapsed_secs;
541
542    start = rdtsc();
543
544    count2 = count;
545    while(count2--) {
546        RAND_NEXT;
547        vfs_seek(f, VFS_SEEK_SET, RAND_BLOCK);
548
549        err = vfs_write(f, buffer, blocksize, &wsize);
550        if (err_is_fail(err) || wsize == 0) {
551            DEBUG_ERR(err, "error writing file");
552            ret = 1;
553            goto out;
554        }
555
556        assert(wsize == blocksize);
557        vfs_flush(f);
558    }
559
560    stop = rdtsc();
561    elapsed_msecs = ((stop - start) / tscperms);
562    elapsed_secs = (double)elapsed_msecs/1000.0;
563
564    result->write = ((double)(count * blocksize) / 1024.0) / elapsed_secs;
565
566out:
567    if (f != NULL) {
568        err = vfs_close(f);
569        if (err_is_fail(err)) {
570            DEBUG_ERR(err, "in vfs_close");
571        }
572    }
573
574    return ret;
575}
576
577#define FILESIZE (1024 * 1024 * 1024)
578static int
579ahci_randbench(int argc, char *argv[])
580{
581    if (argc != 2) {
582        printf("usage: %s <target>\ntarget must be an absolute path!\n", argv[0]);
583        return 1;
584    }
585
586    char *target = argv[1];
587
588    printf("Running random disk test\n");
589
590    size_t blocksize, count = 256;
591    uint8_t *buffer = malloc(131072);
592
593    printf("bs\tread\tvar\twrite\tvar\n");
594
595    for (blocksize = 131072; blocksize >= 512; blocksize /= 2) {
596        struct bench_res r1, r2, r3;
597        rand_bench(target, buffer, FILESIZE, blocksize, count, 9147, &r1);
598        rand_bench(target, buffer, FILESIZE, blocksize, count, 26447, &r2);
599        rand_bench(target, buffer, FILESIZE, blocksize, count, 5109, &r3);
600        double read_kbps = (r1.read + r2.read + r3.read) / 3;
601        double read_var = (read_kbps - r1.read) * (read_kbps - r1.read);
602        read_var += (read_kbps - r2.read) * (read_kbps - r2.read);
603        read_var += (read_kbps - r3.read) * (read_kbps - r3.read);
604        read_var /= 3;
605
606        double write_kbps = (r1.write + r2.write + r3.write) / 3;
607        double write_var = (write_kbps - r1.write) * (write_kbps - r1.write);
608        write_var += (write_kbps - r2.write) * (write_kbps - r2.write);
609        write_var += (write_kbps - r3.write) * (write_kbps - r3.write);
610        write_var /= 3;
611
612        printf("%zd\t%.3lf\t%.3lf\t%.3lf\t%.3lf\n", blocksize, read_kbps, read_var, write_kbps, write_var);
613    }
614
615    free(buffer);
616    printf("random disk test completed\n");
617
618    return 0;
619
620}
621
622static int
623rand_bench_time(char *target, uint8_t *buffer, size_t filesize, size_t blocksize, size_t count, size_t randval, struct bench_res *result)
624{
625    size_t randbit;
626
627    size_t rsize = 0;
628    size_t wsize = 0;
629
630    int ret = 0;
631
632
633#define RAND_NEXT do {\
634    randbit = ((randval >> 0) ^ (randval >> 3)) & 1;\
635    randval = (randval >> 1) | (randbit << (sizeof(size_t) * CHAR_BIT - 1));\
636} while (0)
637
638#define RAND_BLOCK ((randval % (filesize / blocksize)) * blocksize)
639
640    if (filesize % blocksize != 0) {
641        printf("Please spcifiy the filesize as a multiple of blocksize\n");
642        return 0;
643    }
644
645    errval_t err;
646    vfs_handle_t f = NULL;
647    char *path = vfs_path_mkabsolute(cwd, target);
648    err = vfs_open(path, &f);
649
650    if (err_is_fail(err)) {
651        printf("%s: %s\n", path, err_getstring(err));
652        return 1;
653    }
654
655    uint64_t tscperms;
656    err = sys_debug_get_tsc_per_ms(&tscperms);
657    assert(err_is_ok(err));
658
659    //printf("ticks per millisec: %" PRIu64 "\n", tscperms);
660    uint64_t start = rdtsc();
661
662    size_t count2 = count;
663    while (count2--) {
664        RAND_NEXT;
665        vfs_seek(f, VFS_SEEK_SET, RAND_BLOCK);
666
667        err = vfs_read(f, buffer, blocksize, &rsize);
668        if (err_is_fail(err)) {
669            DEBUG_ERR(err, "error reading file");
670            ret = 1;
671            goto out;
672        }
673
674        assert(rsize == blocksize);
675    }
676
677    uint64_t stop = rdtsc();
678    uint64_t elapsed_msecs = ((stop - start) / tscperms);
679    double elapsed_secs = (double)elapsed_msecs/1000.0;
680
681    result->read = elapsed_secs;
682
683    start = rdtsc();
684
685    count2 = count;
686    while(count2--) {
687        RAND_NEXT;
688        vfs_seek(f, VFS_SEEK_SET, RAND_BLOCK);
689
690        err = vfs_write(f, buffer, blocksize, &wsize);
691        if (err_is_fail(err) || wsize == 0) {
692            DEBUG_ERR(err, "error writing file");
693            ret = 1;
694            goto out;
695        }
696
697        assert(wsize == blocksize);
698        vfs_flush(f);
699    }
700
701#if defined(__x86_64__) || defined(__i386__)
702    stop = rdtsc();
703    elapsed_msecs = ((stop - start) / tscperms);
704    elapsed_secs = (double)elapsed_msecs/1000.0;
705
706    result->write = elapsed_secs;
707#endif
708
709out:
710    if (f != NULL) {
711        err = vfs_close(f);
712        if (err_is_fail(err)) {
713            DEBUG_ERR(err, "in vfs_close");
714        }
715    }
716
717    return ret;
718}
719
720#define FILESIZE (1024 * 1024 * 1024)
721static int
722ahci_randbench_time(int argc, char *argv[])
723{
724    if (argc != 2) {
725        printf("usage: %s <target>\ntarget must be an absolute path!\n", argv[0]);
726        return 1;
727    }
728
729    char *target = argv[1];
730
731    printf("Running random disk test\n");
732
733    size_t blocksize, count = 256;
734    uint8_t *buffer = malloc(131072);
735
736    printf("bs\tread\tvar\n");
737
738    for (blocksize = 131072; blocksize >= 512; blocksize /= 2) {
739        struct bench_res r1, r2, r3;
740        rand_bench_time(target, buffer, FILESIZE, blocksize, count, 9147, &r1);
741        rand_bench_time(target, buffer, FILESIZE, blocksize, count, 26447, &r2);
742        rand_bench_time(target, buffer, FILESIZE, blocksize, count, 5109, &r3);
743        r1.read /= count;
744        r2.read /= count;
745        r3.read /= count;
746        r1.write /= count;
747        r2.write /= count;
748        r3.write /= count;
749        double read_sec = (r1.read + r2.read + r3.read) / 3;
750        double read_var = (read_sec - r1.read) * (read_sec - r1.read);
751        read_var += (read_sec - r2.read) * (read_sec - r2.read);
752        read_var += (read_sec - r3.read) * (read_sec - r3.read);
753        read_var /= 3;
754        double write_sec = (r1.write + r2.write + r3.write) / 3;
755        double write_var = (write_sec - r1.write) * (write_sec - r1.write);
756        write_var += (write_sec - r2.write) * (write_sec - r2.write);
757        write_var += (write_sec - r3.write) * (write_sec - r3.write);
758        write_var /= 3;
759
760        printf("%zd\t%.3lf\t%.3lf\t%.3lf\t%.3lf\n", blocksize, read_sec, read_var, write_sec, write_var);
761    }
762
763    free(buffer);
764    printf("random disk test completed\n");
765
766    return 0;
767
768}
769
770static int
771ahci_read_write(int argc, char *argv[])
772{
773    if (argc != 4) {
774        printf("usage: %s <block device> <blocksize> <count>\n", argv[0]);
775        return 1;
776    }
777
778    char *dev = argv[1];
779    size_t blocksize = atoi(argv[2]);
780    size_t count = atoi(argv[3]);
781    printf("malloc buf\n");
782    uint8_t *buf = malloc(blocksize);
783    int ret = 0;
784
785    errval_t err;
786    vfs_handle_t f = NULL;
787    char *path = vfs_path_mkabsolute(cwd, dev);
788    printf("open\n");
789    err = vfs_open(path, &f);
790
791    if (err_is_fail(err)) {
792        printf("%s: %s\n", path, err_getstring(err));
793        ret = 1;
794        goto out;
795    }
796
797    for (int i = 0; i < count; i++) {
798        size_t read = 0;
799        size_t rsize;
800        while(read < blocksize) {
801            printf("read\n");
802            err = vfs_read(f, &buf[read], blocksize, &rsize);
803            if (err_is_fail(err)) {
804                DEBUG_ERR(err, "error reading file");
805                ret = 1;
806                goto out;
807            }
808            read += rsize;
809        }
810
811        size_t written = 0;
812        size_t wsize;
813        while(written < blocksize) {
814            printf("write\n");
815            err = vfs_write(f, &buf[written], blocksize, &wsize);
816            if (err_is_fail(err)) {
817                DEBUG_ERR(err, "error writing file");
818                ret = 1;
819                goto out;
820            }
821            written += wsize;
822        }
823    }
824
825out:
826    if (buf) {
827        printf("free\n");
828        free(buf);
829    }
830    if (f) {
831        printf("close\n");
832        err = vfs_close(f);
833        if (err_is_fail(err)) {
834            DEBUG_ERR(err, "in vfs_close");
835        }
836    }
837
838    return ret;
839}
840
841typedef int (*Command)(int argc, char *argv[]);
842struct cmd {
843    const char  *name;
844    Command     cmd;
845    const char  *usage;
846};
847
848static struct cmd commands[] = {
849    { "benchmark", ahci_benchmark, "benchmark ahci" },
850    { "fillbench", ahci_fillbench, "benchmark ahci sequential" },
851    { "randbench", ahci_randbench, "benchmark ahci random (throughput)" },
852    { "randbench_time", ahci_randbench_time, "benchmark ahci random (response time)" },
853    { "read_write", ahci_read_write, "read from block device and write back" },
854    { "shuffle_file", shuffle_file, "Shuffle a file around" },
855};
856
857#define NUM_COMMANDS (sizeof(commands)/sizeof(commands[0]))
858
859static struct cmd *find_command(const char *name)
860{
861    for(int i = 0; i < ENTRIES(commands); i++) {
862        struct cmd *cmd = &commands[i];
863
864        if(strcmp(name, cmd->name) == 0) {
865            return cmd;
866        }
867    }
868
869    return NULL;
870}
871
872static void usage(char *progname)
873{
874    printf("%s <mountpoint> <mount uri> <command> <command_args...>\n", progname);
875    for (int i = 0; i < NUM_COMMANDS; i++) {
876        printf("\t%s: %s\n", commands[i].name, commands[i].usage);
877    }
878    printf("To get detailed usage informations for the different benchmarks\n"
879           "run the command without additional arguments.\n\n");
880}
881
882int main(int argc, char *argv[])
883{
884    // mount
885    if (argc < 4) {
886        usage(argv[0]);
887        return 1;
888    }
889    // argv[1] mountpoint, argv[2] mount uri
890    if(mount(argv[1], argv[2]))
891        return 1;
892
893    // find command
894    struct cmd *cmd;
895    if ((cmd = find_command(argv[3])) == NULL)
896        return 1;
897
898    return cmd->cmd(argc-3, argv+3);
899}
900