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