- Timestamp:
- Jul 31, 2019 11:04:15 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/utils/storage/IoPerf.cpp
r80032 r80065 57 57 *********************************************************************************************************************************/ 58 58 59 /** Size multiplier for the random data buffer to seek around. */ 60 #define IOPERF_RAND_DATA_BUF_FACTOR 3 61 59 62 60 63 /********************************************************************************************************************************* … … 104 107 IOPERFTESTSETPREP_32BIT_HACK = 0x7fffffff 105 108 } IOPERFTESTSETPREP; 109 110 111 /** 112 * I/O perf request. 113 */ 114 typedef struct IOPERFREQ 115 { 116 /** Start timestamp. */ 117 uint64_t tsStart; 118 /** Request operation code. */ 119 RTIOQUEUEOP enmOp; 120 /** Start offset. */ 121 uint64_t offXfer; 122 /** Transfer size for the request. */ 123 size_t cbXfer; 124 /** The buffer used for the transfer. */ 125 void *pvXfer; 126 /** This is the statically assigned destination buffer for read requests for this request. */ 127 void *pvXferRead; 128 /** Size of the read buffer. */ 129 size_t cbXferRead; 130 } IOPERFREQ; 131 /** Pointer to an I/O perf request. */ 132 typedef IOPERFREQ *PIOPERFREQ; 133 /** Pointer to a constant I/O perf request. */ 134 typedef const IOPERFREQ *PCIOPERFREQ; 106 135 107 136 … … 133 162 /** Maximum number of requests to queue. */ 134 163 uint32_t cReqsMax; 164 /** Pointer to the array of request specific data. */ 165 PIOPERFREQ paIoReqs; 166 /** Page aligned chunk of memory assigned as read buffers for the individual requests. */ 167 void *pvIoReqReadBuf; 168 /** Size of the read memory buffer. */ 169 size_t cbIoReqReadBuf; 170 /** Random number generator used. */ 171 RTRAND hRand; 172 /** The random data buffer used for writes. */ 173 uint8_t *pbRandWrite; 174 /** Size of the random write buffer in 512 byte blocks. */ 175 uint32_t cRandWriteBlocks512B; 135 176 /** Test dependent data. */ 136 177 union 137 178 { 138 uint32_t uDummy; 179 /** Sequential read write. */ 180 uint64_t offNextSeq; 139 181 } Tst; 140 182 } IOPERFJOB; … … 191 233 { "--dir", 'd', RTGETOPT_REQ_STRING }, 192 234 { "--relative-dir", 'r', RTGETOPT_REQ_NOTHING }, 193 { "--enable-all", 'e', RTGETOPT_REQ_NOTHING },194 { "--disable-all", 'z', RTGETOPT_REQ_NOTHING },195 235 196 236 { "--jobs", 'j', RTGETOPT_REQ_UINT32 }, … … 198 238 { "--test-set-size", 's', RTGETOPT_REQ_UINT64 }, 199 239 { "--block-size", 'b', RTGETOPT_REQ_UINT32 }, 240 { "--maximum-requests", 'm', RTGETOPT_REQ_UINT32 }, 200 241 201 242 { "--first-write", kCmdOpt_FirstWrite, RTGETOPT_REQ_NOTHING }, … … 280 321 * @return Next test to run. 281 322 */ 282 static IOPERFTEST ioPerf TestSelectNext()323 static IOPERFTEST ioPerfJobTestSelectNext() 283 324 { 284 325 AssertReturn(g_idxTest < RT_ELEMENTS(g_aenmTests), IOPERFTEST_SHUTDOWN); 285 326 286 327 while ( g_idxTest < RT_ELEMENTS(g_aenmTests) 287 && g_aenmTests[g_idxTest] != IOPERFTEST_DISABLED)328 && g_aenmTests[g_idxTest] == IOPERFTEST_DISABLED) 288 329 g_idxTest++; 289 330 … … 291 332 292 333 return g_aenmTests[g_idxTest]; 334 } 335 336 337 /** 338 * Returns the I/O queue operation for the next request. 339 * 340 * @returns I/O queue operation enum. 341 * @param pJob The job data for the current worker. 342 */ 343 static RTIOQUEUEOP ioPerfJobTestGetIoQOp(PIOPERFJOB pJob) 344 { 345 switch (pJob->enmTest) 346 { 347 case IOPERFTEST_FIRST_WRITE: 348 case IOPERFTEST_SEQ_WRITE: 349 case IOPERFTEST_SEQ_READ: 350 case IOPERFTEST_REV_WRITE: 351 case IOPERFTEST_RND_WRITE: 352 return RTIOQUEUEOP_WRITE; 353 354 case IOPERFTEST_RND_READ: 355 case IOPERFTEST_REV_READ: 356 return RTIOQUEUEOP_READ; 357 case IOPERFTEST_SEQ_READWRITE: 358 case IOPERFTEST_RND_READWRITE: 359 AssertMsgFailed(("Not implemented!\n")); 360 break; 361 default: 362 AssertMsgFailed(("Invalid/unknown test selected: %d\n", pJob->enmTest)); 363 break; 364 } 365 366 return RTIOQUEUEOP_INVALID; 367 } 368 369 370 /** 371 * Returns the offset to use for the next request. 372 * 373 * @returns Offset to use. 374 * @param pJob The job data for the current worker. 375 */ 376 static uint64_t ioPerfJobTestGetOffsetNext(PIOPERFJOB pJob) 377 { 378 uint64_t offNext = 0; 379 380 switch (pJob->enmTest) 381 { 382 case IOPERFTEST_FIRST_WRITE: 383 case IOPERFTEST_SEQ_WRITE: 384 case IOPERFTEST_SEQ_READ: 385 offNext = pJob->Tst.offNextSeq; 386 pJob->Tst.offNextSeq += pJob->cbIoBlock; 387 break; 388 389 case IOPERFTEST_REV_WRITE: 390 case IOPERFTEST_REV_READ: 391 case IOPERFTEST_RND_WRITE: 392 case IOPERFTEST_RND_READ: 393 case IOPERFTEST_SEQ_READWRITE: 394 case IOPERFTEST_RND_READWRITE: 395 AssertMsgFailed(("Not implemented!\n")); 396 break; 397 default: 398 AssertMsgFailed(("Invalid/unknown test selected: %d\n", pJob->enmTest)); 399 break; 400 } 401 402 return offNext; 403 } 404 405 406 /** 407 * Returns a pointer to the write buffer with random data for the given offset which 408 * is predictable for data verification. 409 * 410 * @returns Pointer to I/O block sized data buffer with random data. 411 * @param pJob The job data for the current worker. 412 * @param off The offset to get the buffer for. 413 */ 414 static void *ioPerfJobTestGetWriteBufForOffset(PIOPERFJOB pJob, uint64_t off) 415 { 416 /* 417 * Dividing the file into 512 byte blocks so buffer pointers are at least 418 * 512 byte aligned to work with async I/O on some platforms (Linux and O_DIRECT for example). 419 */ 420 uint64_t uBlock = off / 512; 421 uint32_t idxBuf = uBlock % pJob->cRandWriteBlocks512B; 422 return pJob->pbRandWrite + idxBuf * 512; 423 } 424 425 426 /** 427 * Initialize the given request for submission. 428 * 429 * @returns nothing. 430 * @param pJob The job data for the current worker. 431 * @param pIoReq The request to initialize. 432 */ 433 static void ioPerfJobTestReqInit(PIOPERFJOB pJob, PIOPERFREQ pIoReq) 434 { 435 pIoReq->enmOp = ioPerfJobTestGetIoQOp(pJob); 436 pIoReq->offXfer = ioPerfJobTestGetOffsetNext(pJob); 437 pIoReq->cbXfer = pJob->cbIoBlock; 438 if (pIoReq->enmOp == RTIOQUEUEOP_READ) 439 pIoReq->pvXfer = pIoReq->pvXferRead; 440 else if (pIoReq->enmOp == RTIOQUEUEOP_WRITE) 441 pIoReq->pvXfer = ioPerfJobTestGetWriteBufForOffset(pJob, pIoReq->offXfer); 442 else /* Flush */ 443 pIoReq->pvXfer = NULL; 444 445 pIoReq->tsStart = RTTimeNanoTS(); 446 } 447 448 449 /** 450 * Initializes the test state for the current test. 451 * 452 * @returns IPRT status code. 453 * @param pJob The job data for the current worker. 454 */ 455 static int ioPerfJobTestInit(PIOPERFJOB pJob) 456 { 457 switch (pJob->enmTest) 458 { 459 case IOPERFTEST_FIRST_WRITE: 460 case IOPERFTEST_SEQ_WRITE: 461 case IOPERFTEST_SEQ_READ: 462 pJob->Tst.offNextSeq = 0; 463 break; 464 465 case IOPERFTEST_REV_WRITE: 466 case IOPERFTEST_REV_READ: 467 case IOPERFTEST_RND_WRITE: 468 case IOPERFTEST_RND_READ: 469 case IOPERFTEST_SEQ_READWRITE: 470 case IOPERFTEST_RND_READWRITE: 471 AssertMsgFailed(("Not implemented!\n")); 472 break; 473 default: 474 AssertMsgFailed(("Invalid/unknown test selected: %d\n", pJob->enmTest)); 475 break; 476 } 477 478 return VINF_SUCCESS; 479 } 480 481 482 /** 483 * Frees allocated resources specific for the current test. 484 * 485 * @returns nothing. 486 * @param pJob The job data for the current worker. 487 */ 488 static void ioPerfJobTestFinish(PIOPERFJOB pJob) 489 { 490 switch (pJob->enmTest) 491 { 492 case IOPERFTEST_FIRST_WRITE: 493 case IOPERFTEST_SEQ_WRITE: 494 case IOPERFTEST_SEQ_READ: 495 break; /* Nothing to do. */ 496 497 case IOPERFTEST_REV_WRITE: 498 case IOPERFTEST_REV_READ: 499 case IOPERFTEST_RND_WRITE: 500 case IOPERFTEST_RND_READ: 501 case IOPERFTEST_SEQ_READWRITE: 502 case IOPERFTEST_RND_READWRITE: 503 AssertMsgFailed(("Not implemented!\n")); 504 break; 505 default: 506 AssertMsgFailed(("Invalid/unknown test selected: %d\n", pJob->enmTest)); 507 break; 508 } 509 } 510 511 512 /** 513 * Returns whether the current test is done with submitting new requests (reached test set size). 514 * 515 * @returns True when the test has submitted all required requests, false if there are still requests required 516 */ 517 static bool ioPerfJobTestIsDone(PIOPERFJOB pJob) 518 { 519 switch (pJob->enmTest) 520 { 521 case IOPERFTEST_FIRST_WRITE: 522 case IOPERFTEST_SEQ_WRITE: 523 case IOPERFTEST_SEQ_READ: 524 return pJob->Tst.offNextSeq == pJob->cbTestSet; 525 526 case IOPERFTEST_REV_WRITE: 527 case IOPERFTEST_REV_READ: 528 case IOPERFTEST_RND_WRITE: 529 case IOPERFTEST_RND_READ: 530 case IOPERFTEST_SEQ_READWRITE: 531 case IOPERFTEST_RND_READWRITE: 532 AssertMsgFailed(("Not implemented!\n")); 533 break; 534 default: 535 AssertMsgFailed(("Invalid/unknown test selected: %d\n", pJob->enmTest)); 536 break; 537 } 538 539 return true; 540 } 541 542 543 /** 544 * The test I/O loop pumping I/O. 545 * 546 * @returns IPRT status code. 547 * @param pJob The job data for the current worker. 548 */ 549 static int ioPerfJobTestIoLoop(PIOPERFJOB pJob) 550 { 551 int rc = ioPerfJobTestInit(pJob); 552 if (RT_SUCCESS(rc)) 553 { 554 /* Allocate the completion event array. */ 555 uint32_t cReqsQueued = 0; 556 PRTIOQUEUECEVT paIoQCEvt = (PRTIOQUEUECEVT)RTMemAllocZ(pJob->cReqsMax * sizeof(RTIOQUEUECEVT)); 557 if (RT_LIKELY(paIoQCEvt)) 558 { 559 /* Queue requests up to the maximum. */ 560 while ( (cReqsQueued < pJob->cReqsMax) 561 && !ioPerfJobTestIsDone(pJob) 562 && RT_SUCCESS(rc)) 563 { 564 PIOPERFREQ pReq = &pJob->paIoReqs[cReqsQueued]; 565 ioPerfJobTestReqInit(pJob, pReq); 566 rc = RTIoQueueRequestPrepare(pJob->hIoQueue, &pJob->Hnd, pReq->enmOp, 567 pReq->offXfer, pReq->pvXfer, pReq->cbXfer, 0 /*fReqFlags*/, 568 pReq); 569 cReqsQueued++; 570 } 571 572 /* Commit the prepared requests. */ 573 if ( RT_SUCCESS(rc) 574 && cReqsQueued) 575 rc = RTIoQueueCommit(pJob->hIoQueue); 576 577 /* Enter wait loop and process completed requests. */ 578 while ( RT_SUCCESS(rc) 579 && cReqsQueued) 580 { 581 uint32_t cCEvtCompleted = 0; 582 583 rc = RTIoQueueEvtWait(pJob->hIoQueue, paIoQCEvt, pJob->cReqsMax, 1 /*cMinWait*/, 584 &cCEvtCompleted, 0 /*fFlags*/); 585 if (RT_SUCCESS(rc)) 586 { 587 uint32_t cReqsThisQueued = 0; 588 589 /* Process any completed event and continue to fill the queue as long as there is stuff to do. */ 590 for (uint32_t i = 0; i < cCEvtCompleted; i++) 591 { 592 PIOPERFREQ pReq = (PIOPERFREQ)paIoQCEvt[i].pvUser; 593 594 if (RT_SUCCESS(paIoQCEvt[i].rcReq)) 595 { 596 Assert(paIoQCEvt[i].cbXfered == pReq->cbXfer); 597 598 /** @todo Statistics collection. */ 599 if (!ioPerfJobTestIsDone(pJob)) 600 { 601 ioPerfJobTestReqInit(pJob, pReq); 602 rc = RTIoQueueRequestPrepare(pJob->hIoQueue, &pJob->Hnd, pReq->enmOp, 603 pReq->offXfer, pReq->pvXfer, pReq->cbXfer, 0 /*fReqFlags*/, 604 pReq); 605 cReqsThisQueued++; 606 } 607 else 608 cReqsQueued--; 609 } 610 } 611 612 if ( cReqsThisQueued 613 && RT_SUCCESS(rc)) 614 rc = RTIoQueueCommit(pJob->hIoQueue); 615 } 616 } 617 618 RTMemFree(paIoQCEvt); 619 } 620 621 ioPerfJobTestFinish(pJob); 622 } 623 624 return rc; 293 625 } 294 626 … … 304 636 if (pJob->pMaster) 305 637 { 306 /* Enter the rende vouzs semaphore. */638 /* Enter the rendezvous semaphore. */ 307 639 int rc = VINF_SUCCESS; 308 640 … … 312 644 /* Single threaded run, collect the results from our current test and select the next test. */ 313 645 /** @todo Results and statistics collection. */ 314 pJob->enmTest = ioPerf TestSelectNext();646 pJob->enmTest = ioPerfJobTestSelectNext(); 315 647 return VINF_SUCCESS; 316 }317 318 319 /**320 * Sequential read test.321 *322 * @returns IPRT status code.323 * @param pJob The job data for the current worker.324 */325 static int ioPerfTestSeqRead(PIOPERFJOB pJob)326 {327 RT_NOREF(pJob);328 return VERR_NOT_IMPLEMENTED;329 648 } 330 649 … … 348 667 break; 349 668 350 switch (pJob->enmTest) 351 { 352 case IOPERFTEST_FIRST_WRITE: 353 break; 354 case IOPERFTEST_SEQ_READ: 355 rc = ioPerfTestSeqRead(pJob); 356 break; 357 case IOPERFTEST_SEQ_WRITE: 358 break; 359 case IOPERFTEST_RND_READ: 360 break; 361 case IOPERFTEST_RND_WRITE: 362 break; 363 case IOPERFTEST_REV_READ: 364 break; 365 case IOPERFTEST_REV_WRITE: 366 break; 367 case IOPERFTEST_SEQ_READWRITE: 368 break; 369 case IOPERFTEST_RND_READWRITE: 370 break; 371 case IOPERFTEST_SHUTDOWN: 372 fShutdown = true; 373 break; 374 default: 375 AssertMsgFailed(("Invalid job: %d\n", pJob->enmTest)); 376 } 669 rc = ioPerfJobTestIoLoop(pJob); 377 670 } while ( RT_SUCCESS(rc) 378 671 && !fShutdown); … … 391 684 PIOPERFJOB pJob = (PIOPERFJOB)pvUser; 392 685 return ioPerfJobWorkLoop(pJob); 686 } 687 688 689 /** 690 * Prepares the test set by laying out the files and filling them with data. 691 * 692 * @returns IPRT status code. 693 * @param pJob The job to initialize. 694 */ 695 static int ioPerfJobTestSetPrep(PIOPERFJOB pJob) 696 { 697 int rc = RTRandAdvCreateParkMiller(&pJob->hRand); 698 if (RT_SUCCESS(rc)) 699 { 700 rc = RTRandAdvSeed(pJob->hRand, RTTimeNanoTS()); 701 if (RT_SUCCESS(rc)) 702 { 703 /* 704 * Create a random data buffer for writes, we'll use multiple of the I/O block size to 705 * be able to seek in the buffer quite a bit to make the file content as random as possible 706 * to avoid mechanisms like compression or deduplication for now which can influence storage 707 * benchmarking unpredictably. 708 */ 709 pJob->cRandWriteBlocks512B = ((IOPERF_RAND_DATA_BUF_FACTOR - 1) * pJob->cbIoBlock) / 512; 710 pJob->pbRandWrite = (uint8_t *)RTMemPageAllocZ(IOPERF_RAND_DATA_BUF_FACTOR * pJob->cbIoBlock); 711 if (RT_LIKELY(pJob->pbRandWrite)) 712 { 713 RTRandAdvBytes(pJob->hRand, pJob->pbRandWrite, IOPERF_RAND_DATA_BUF_FACTOR * pJob->cbIoBlock); 714 715 /* Write the content here if the first write test is disabled. */ 716 if (g_aenmTests[IOPERFTEST_FIRST_WRITE] == IOPERFTEST_DISABLED) 717 { 718 for (uint64_t off = 0; off < pJob->cbTestSet && RT_SUCCESS(rc); off += pJob->cbIoBlock) 719 { 720 void *pvWrite = ioPerfJobTestGetWriteBufForOffset(pJob, off); 721 rc = RTFileWriteAt(pJob->Hnd.u.hFile, off, pvWrite, pJob->cbIoBlock, NULL); 722 } 723 } 724 } 725 } 726 RTRandAdvDestroy(pJob->hRand); 727 } 728 729 return rc; 393 730 } 394 731 … … 413 750 uint64_t cbTestSet, size_t cbIoBlock, uint32_t cReqsMax) 414 751 { 415 pJob->pMaster = pMaster;416 pJob->idJob = idJob;417 pJob->enmTest = IOPERFTEST_INVALID;418 pJob->hThread = NIL_RTTHREAD;419 pJob->Hnd.enmType = RTHANDLETYPE_FILE;420 pJob->cbTestSet = cbTestSet;421 pJob->cbIoBlock = cbIoBlock;422 pJob->cReqsMax = cReqsMax;423 424 /* Create the file. */ 752 pJob->pMaster = pMaster; 753 pJob->idJob = idJob; 754 pJob->enmTest = IOPERFTEST_INVALID; 755 pJob->hThread = NIL_RTTHREAD; 756 pJob->Hnd.enmType = RTHANDLETYPE_FILE; 757 pJob->cbTestSet = cbTestSet; 758 pJob->cbIoBlock = cbIoBlock; 759 pJob->cReqsMax = cReqsMax; 760 pJob->cbIoReqReadBuf = cReqsMax * cbIoBlock; 761 425 762 int rc = VINF_SUCCESS; 426 pJob->p szFilename = RTStrAPrintf2("%sioperf-%u.file", pszTestDir, idJob);427 if (RT_LIKELY(pJob->p szFilename))428 { 429 rc = RTFileOpen(&pJob->Hnd.u.hFile, pJob->pszFilename, RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_READWRITE);430 if (RT_ SUCCESS(rc))763 pJob->paIoReqs = (PIOPERFREQ)RTMemAllocZ(cReqsMax * sizeof(IOPERFREQ)); 764 if (RT_LIKELY(pJob->paIoReqs)) 765 { 766 pJob->pvIoReqReadBuf = RTMemPageAlloc(pJob->cbIoReqReadBuf); 767 if (RT_LIKELY(pJob->pvIoReqReadBuf)) 431 768 { 432 switch (enmPrepMethod) 769 uint8_t *pbReadBuf = (uint8_t *)pJob->pvIoReqReadBuf; 770 771 for (uint32_t i = 0; i < cReqsMax; i++) 433 772 { 434 case IOPERFTESTSETPREP_JUST_CREATE: 435 break; 436 case IOPERFTESTSETPREP_SET_SZ: 437 rc = RTFileSetSize(pJob->Hnd.u.hFile, pJob->cbTestSet); 438 break; 439 case IOPERFTESTSETPREP_SET_ALLOC_SZ: 440 rc = RTFileSetAllocationSize(pJob->Hnd.u.hFile, pJob->cbTestSet, RTFILE_ALLOC_SIZE_F_DEFAULT); 441 break; 442 default: 443 AssertMsgFailed(("Invalid file preparation method: %d\n", enmPrepMethod)); 773 pJob->paIoReqs[i].pvXferRead = pbReadBuf; 774 pJob->paIoReqs[i].cbXferRead = cbIoBlock; 775 pbReadBuf += cbIoBlock; 444 776 } 445 777 446 if (RT_SUCCESS(rc)) 778 /* Create the file. */ 779 pJob->pszFilename = RTStrAPrintf2("%sioperf-%u.file", pszTestDir, idJob); 780 if (RT_LIKELY(pJob->pszFilename)) 447 781 { 448 /* Create I/O queue. */ 449 PCRTIOQUEUEPROVVTABLE pIoQProv = NULL; 450 if (pszIoEngine) 451 pIoQProv = RTIoQueueProviderGetBestForHndType(RTHANDLETYPE_FILE); 452 else 453 pIoQProv = RTIoQueueProviderGetById(pszIoEngine); 454 455 if (RT_LIKELY(pIoQProv)) 782 rc = RTFileOpen(&pJob->Hnd.u.hFile, pJob->pszFilename, RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_READWRITE); 783 if (RT_SUCCESS(rc)) 456 784 { 457 rc = RTIoQueueCreate(&pJob->hIoQueue, pIoQProv, 0 /*fFlags*/, cReqsMax, cReqsMax); 785 switch (enmPrepMethod) 786 { 787 case IOPERFTESTSETPREP_JUST_CREATE: 788 break; 789 case IOPERFTESTSETPREP_SET_SZ: 790 rc = RTFileSetSize(pJob->Hnd.u.hFile, pJob->cbTestSet); 791 break; 792 case IOPERFTESTSETPREP_SET_ALLOC_SZ: 793 rc = RTFileSetAllocationSize(pJob->Hnd.u.hFile, pJob->cbTestSet, RTFILE_ALLOC_SIZE_F_DEFAULT); 794 break; 795 default: 796 AssertMsgFailed(("Invalid file preparation method: %d\n", enmPrepMethod)); 797 } 798 458 799 if (RT_SUCCESS(rc)) 459 800 { 460 /* Spin up the worker thread. */ 461 if (pMaster) 462 rc = RTThreadCreateF(&pJob->hThread, ioPerfJobThread, pJob, 0, 463 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "ioperf-%u", idJob); 464 801 rc = ioPerfJobTestSetPrep(pJob); 465 802 if (RT_SUCCESS(rc)) 466 return VINF_SUCCESS; 803 { 804 /* Create I/O queue. */ 805 PCRTIOQUEUEPROVVTABLE pIoQProv = NULL; 806 if (!pszIoEngine) 807 pIoQProv = RTIoQueueProviderGetBestForHndType(RTHANDLETYPE_FILE); 808 else 809 pIoQProv = RTIoQueueProviderGetById(pszIoEngine); 810 811 if (RT_LIKELY(pIoQProv)) 812 { 813 rc = RTIoQueueCreate(&pJob->hIoQueue, pIoQProv, 0 /*fFlags*/, cReqsMax, cReqsMax); 814 if (RT_SUCCESS(rc)) 815 { 816 rc = RTIoQueueHandleRegister(pJob->hIoQueue, &pJob->Hnd); 817 if (RT_SUCCESS(rc)) 818 { 819 /* Spin up the worker thread. */ 820 if (pMaster) 821 rc = RTThreadCreateF(&pJob->hThread, ioPerfJobThread, pJob, 0, 822 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "ioperf-%u", idJob); 823 824 if (RT_SUCCESS(rc)) 825 return VINF_SUCCESS; 826 } 827 } 828 } 829 else 830 rc = VERR_NOT_SUPPORTED; 831 } 832 833 RTRandAdvDestroy(pJob->hRand); 467 834 } 835 836 RTFileClose(pJob->Hnd.u.hFile); 837 RTFileDelete(pJob->pszFilename); 468 838 } 469 else 470 rc = VERR_NOT_SUPPORTED;839 840 RTStrFree(pJob->pszFilename); 471 841 } 472 842 473 RTFileClose(pJob->Hnd.u.hFile); 474 RTFileDelete(pJob->pszFilename); 843 RTMemPageFree(pJob->pvIoReqReadBuf, pJob->cbIoReqReadBuf); 475 844 } 476 477 RTStrFree(pJob->pszFilename); 478 } 479 else 480 rc = VERR_NO_STR_MEMORY; 845 else 846 rc = VERR_NO_STR_MEMORY; 847 } 481 848 482 849 return rc; … … 492 859 static int ioPerfJobTeardown(PIOPERFJOB pJob) 493 860 { 494 int rc = RTThreadWait(pJob->hThread, RT_INDEFINITE_WAIT, NULL); AssertRC(rc); RT_NOREF(rc); 495 861 if (pJob->pMaster) 862 { 863 int rc = RTThreadWait(pJob->hThread, RT_INDEFINITE_WAIT, NULL); 864 AssertRC(rc); RT_NOREF(rc); 865 } 866 867 RTIoQueueHandleDeregister(pJob->hIoQueue, &pJob->Hnd); 496 868 RTIoQueueDestroy(pJob->hIoQueue); 869 RTRandAdvDestroy(pJob->hRand); 870 RTMemPageFree(pJob->pbRandWrite, IOPERF_RAND_DATA_BUF_FACTOR * pJob->cbIoBlock); 497 871 RTFileClose(pJob->Hnd.u.hFile); 498 872 RTFileDelete(pJob->pszFilename); 499 873 RTStrFree(pJob->pszFilename); 874 RTMemPageFree(pJob->pvIoReqReadBuf, pJob->cbIoReqReadBuf); 875 RTMemFree(pJob->paIoReqs); 500 876 return VINF_SUCCESS; 501 877 } … … 512 888 513 889 int rc = ioPerfJobInit(&Job, NULL, 0, g_pszIoEngine, 514 g_szDir, IOPERFTESTSETPREP_SET_ ALLOC_SZ,890 g_szDir, IOPERFTESTSETPREP_SET_SZ, 515 891 g_cbTestSet, g_cbIoBlock, g_cReqsMax); 516 892 if (RT_SUCCESS(rc)) … … 558 934 case 'd': pszHelp = "The directory to use for testing. default: CWD/fstestdir"; break; 559 935 case 'r': pszHelp = "Don't abspath test dir (good for deep dirs). default: disabled"; break; 560 case 'e': pszHelp = "Enables all tests. default: -e"; break;561 case 'z': pszHelp = "Disables all tests. default: -e"; break;562 936 case 'v': pszHelp = "More verbose execution."; break; 563 937 case 'q': pszHelp = "Quiet execution."; break; … … 620 994 break; 621 995 996 case 'i': 997 g_pszIoEngine = ValueUnion.psz; 998 break; 999 1000 case 's': 1001 g_cbTestSet = ValueUnion.u64; 1002 break; 1003 1004 case 'b': 1005 g_cbIoBlock = ValueUnion.u32; 1006 break; 1007 1008 case 'm': 1009 g_cReqsMax = ValueUnion.u32; 1010 break; 1011 622 1012 case 'q': 623 1013 g_uVerbosity = 0;
Note:
See TracChangeset
for help on using the changeset viewer.