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