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