Changeset 80186 in vbox for trunk/src/VBox/ValidationKit
- Timestamp:
- Aug 7, 2019 2:14:00 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/utils/storage/IoPerf.cpp
r80185 r80186 110 110 111 111 /** 112 * Statistics values for a single request kept around until the 113 * test completed for statistics collection. 114 */ 115 typedef struct IOPERFREQSTAT 116 { 117 /** Start timestamp for the request. */ 118 uint64_t tsStart; 119 /** Completion timestamp for the request. */ 120 uint64_t tsComplete; 121 } IOPERFREQSTAT; 122 /** Pointer to a request statistics record. */ 123 typedef IOPERFREQSTAT *PIOPERFREQSTAT; 124 125 126 /** 112 127 * I/O perf request. 113 128 */ 114 129 typedef struct IOPERFREQ 115 130 { 116 /** Start timestamp. */117 uint64_t tsStart;118 131 /** Request operation code. */ 119 132 RTIOQUEUEOP enmOp; … … 128 141 /** Size of the read buffer. */ 129 142 size_t cbXferRead; 143 /** Pointer to statistics record. */ 144 PIOPERFREQSTAT pStats; 130 145 } IOPERFREQ; 131 146 /** Pointer to an I/O perf request. */ … … 178 193 /** Start timestamp. */ 179 194 uint64_t tsStart; 195 /** End timestamp. for the job. */ 196 uint64_t tsFinish; 197 /** Number of request statistic records. */ 198 uint32_t cReqStats; 199 /** Index of the next free statistics record to use. */ 200 uint32_t idxReqStatNext; 201 /** Array of request statisc records for the whole test. */ 202 PIOPERFREQSTAT paReqStats; 180 203 /** Test dependent data. */ 181 204 union … … 498 521 pIoReq->pvXfer = NULL; 499 522 500 pIoReq->tsStart = RTTimeNanoTS(); 523 Assert(pJob->idxReqStatNext < pJob->cReqStats); 524 if (RT_LIKELY(pJob->idxReqStatNext < pJob->cReqStats)) 525 { 526 pIoReq->pStats = &pJob->paReqStats[pJob->idxReqStatNext++]; 527 pIoReq->pStats->tsStart = RTTimeNanoTS(); 528 } 529 else 530 pIoReq->pStats = NULL; 501 531 } 502 532 … … 549 579 int rc = VINF_SUCCESS; 550 580 581 pJob->idxReqStatNext = 0; 582 551 583 switch (pJob->enmTest) 552 584 { … … 595 627 static void ioPerfJobTestFinish(PIOPERFJOB pJob) 596 628 { 597 uint64_t nsRuntime = RTTimeNanoTS() - pJob->tsStart; 598 RTTestIValue("Runtime", nsRuntime, RTTESTUNIT_NS); 629 pJob->tsFinish = RTTimeNanoTS(); 599 630 600 631 switch (pJob->enmTest) … … 707 738 Assert(paIoQCEvt[i].cbXfered == pReq->cbXfer); 708 739 709 /** @todo Statistics collection. */ 740 if (pReq->pStats) 741 pReq->pStats->tsComplete = RTTimeNanoTS(); 742 710 743 if (!ioPerfJobTestIsDone(pJob)) 711 744 { … … 719 752 cReqsQueued--; 720 753 } 754 else 755 RTTestIErrorInc(); 721 756 } 722 757 … … 740 775 741 776 /** 777 * Calculates the statistic values for the given job after a 778 * test finished. 779 * 780 * @returns nothing. 781 * @param pJob The job data. 782 */ 783 static void ioPerfJobStats(PIOPERFJOB pJob) 784 { 785 uint64_t nsJobRuntime = pJob->tsFinish - pJob->tsStart; 786 RTTestIValueF(nsJobRuntime, RTTESTUNIT_NS, "Job/%RU32/Runtime", pJob->idJob); 787 788 uint64_t *paReqRuntimeNs = (uint64_t *)RTMemAllocZ(pJob->cReqStats * sizeof(uint64_t)); 789 if (RT_LIKELY(paReqRuntimeNs)) 790 { 791 /* Calculate runtimes for each request first. */ 792 for (uint32_t i = 0; i < pJob->cReqStats; i++) 793 { 794 PIOPERFREQSTAT pStat = &pJob->paReqStats[i]; 795 paReqRuntimeNs[i] = pStat->tsComplete - pStat->tsStart; 796 } 797 798 /* Get average bandwidth for the job. */ 799 RTTestIValueF((uint64_t)(pJob->cbTestSet / ((double)nsJobRuntime / RT_NS_1SEC)), 800 RTTESTUNIT_BYTES_PER_SEC, "Job/%RU32/AvgBandwidth", pJob->idJob); 801 802 RTTestIValueF((uint64_t)(pJob->cReqStats / ((double)nsJobRuntime / RT_NS_1SEC)), 803 RTTESTUNIT_OCCURRENCES_PER_SEC, "Job/%RU32/AvgIops", pJob->idJob); 804 805 /* Calculate the average latency for the requests. */ 806 uint64_t uLatency = 0; 807 for (uint32_t i = 0; i < pJob->cReqStats; i++) 808 uLatency += paReqRuntimeNs[i]; 809 RTTestIValueF(uLatency / pJob->cReqStats, RTTESTUNIT_NS, "Job/%RU32/AvgLatency", pJob->idJob); 810 811 RTMemFree(paReqRuntimeNs); 812 } 813 else 814 RTTestIErrorInc(); 815 } 816 817 818 /** 742 819 * Synchronizes with the other jobs and waits for the current test to execute. 743 820 * … … 785 862 if (RT_FAILURE(rc)) 786 863 break; 864 865 /* 866 * Do the statistics here for a single job run, 867 * the master will do this for each job and combined statistics 868 * otherwise. 869 */ 870 if (!pJob->pMaster) 871 ioPerfJobStats(pJob); 787 872 } 788 873 … … 883 968 pJob->cbIoReqReadBuf = cReqsMax * cbIoBlock; 884 969 pJob->uWriteChance = uWriteChance; 970 pJob->cReqStats = (uint32_t)(pJob->cbTestSet / pJob->cbIoBlock + ((pJob->cbTestSet % pJob->cbIoBlock) ? 1 : 0)); 971 pJob->idxReqStatNext = 0; 885 972 886 973 int rc = VINF_SUCCESS; … … 888 975 if (RT_LIKELY(pJob->paIoReqs)) 889 976 { 890 pJob->p vIoReqReadBuf = RTMemPageAlloc(pJob->cbIoReqReadBuf);891 if (RT_LIKELY(pJob->p vIoReqReadBuf))977 pJob->paReqStats = (PIOPERFREQSTAT)RTMemAllocZ(pJob->cReqStats * sizeof(IOPERFREQSTAT)); 978 if (RT_LIKELY(pJob->paReqStats)) 892 979 { 893 uint8_t *pbReadBuf = (uint8_t *)pJob->pvIoReqReadBuf; 894 895 for (uint32_t i = 0; i < cReqsMax; i++) 980 pJob->pvIoReqReadBuf = RTMemPageAlloc(pJob->cbIoReqReadBuf); 981 if (RT_LIKELY(pJob->pvIoReqReadBuf)) 896 982 { 897 pJob->paIoReqs[i].pvXferRead = pbReadBuf; 898 pJob->paIoReqs[i].cbXferRead = cbIoBlock; 899 pbReadBuf += cbIoBlock; 900 } 901 902 /* Create the file. */ 903 pJob->pszFilename = RTStrAPrintf2("%sioperf-%u.file", pszTestDir, idJob); 904 if (RT_LIKELY(pJob->pszFilename)) 905 { 906 uint32_t fOpen = RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_READWRITE | RTFILE_O_ASYNC_IO; 907 if (g_fNoCache) 908 fOpen |= RTFILE_O_NO_CACHE; 909 rc = RTFileOpen(&pJob->Hnd.u.hFile, pJob->pszFilename, fOpen); 910 if (RT_SUCCESS(rc)) 983 uint8_t *pbReadBuf = (uint8_t *)pJob->pvIoReqReadBuf; 984 985 for (uint32_t i = 0; i < cReqsMax; i++) 911 986 { 912 switch (enmPrepMethod) 913 { 914 case IOPERFTESTSETPREP_JUST_CREATE: 915 break; 916 case IOPERFTESTSETPREP_SET_SZ: 917 rc = RTFileSetSize(pJob->Hnd.u.hFile, pJob->cbTestSet); 918 break; 919 case IOPERFTESTSETPREP_SET_ALLOC_SZ: 920 rc = RTFileSetAllocationSize(pJob->Hnd.u.hFile, pJob->cbTestSet, RTFILE_ALLOC_SIZE_F_DEFAULT); 921 break; 922 default: 923 AssertMsgFailed(("Invalid file preparation method: %d\n", enmPrepMethod)); 924 } 925 987 pJob->paIoReqs[i].pvXferRead = pbReadBuf; 988 pJob->paIoReqs[i].cbXferRead = cbIoBlock; 989 pbReadBuf += cbIoBlock; 990 } 991 992 /* Create the file. */ 993 pJob->pszFilename = RTStrAPrintf2("%sioperf-%u.file", pszTestDir, idJob); 994 if (RT_LIKELY(pJob->pszFilename)) 995 { 996 uint32_t fOpen = RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_READWRITE | RTFILE_O_ASYNC_IO; 997 if (g_fNoCache) 998 fOpen |= RTFILE_O_NO_CACHE; 999 rc = RTFileOpen(&pJob->Hnd.u.hFile, pJob->pszFilename, fOpen); 926 1000 if (RT_SUCCESS(rc)) 927 1001 { 928 rc = ioPerfJobTestSetPrep(pJob); 1002 switch (enmPrepMethod) 1003 { 1004 case IOPERFTESTSETPREP_JUST_CREATE: 1005 break; 1006 case IOPERFTESTSETPREP_SET_SZ: 1007 rc = RTFileSetSize(pJob->Hnd.u.hFile, pJob->cbTestSet); 1008 break; 1009 case IOPERFTESTSETPREP_SET_ALLOC_SZ: 1010 rc = RTFileSetAllocationSize(pJob->Hnd.u.hFile, pJob->cbTestSet, RTFILE_ALLOC_SIZE_F_DEFAULT); 1011 break; 1012 default: 1013 AssertMsgFailed(("Invalid file preparation method: %d\n", enmPrepMethod)); 1014 } 1015 929 1016 if (RT_SUCCESS(rc)) 930 1017 { 931 /* Create I/O queue. */ 932 PCRTIOQUEUEPROVVTABLE pIoQProv = NULL; 933 if (!pszIoEngine) 934 pIoQProv = RTIoQueueProviderGetBestForHndType(RTHANDLETYPE_FILE); 935 else 936 pIoQProv = RTIoQueueProviderGetById(pszIoEngine); 937 938 if (RT_LIKELY(pIoQProv)) 1018 rc = ioPerfJobTestSetPrep(pJob); 1019 if (RT_SUCCESS(rc)) 939 1020 { 940 rc = RTIoQueueCreate(&pJob->hIoQueue, pIoQProv, 0 /*fFlags*/, cReqsMax, cReqsMax); 941 if (RT_SUCCESS(rc)) 1021 /* Create I/O queue. */ 1022 PCRTIOQUEUEPROVVTABLE pIoQProv = NULL; 1023 if (!pszIoEngine) 1024 pIoQProv = RTIoQueueProviderGetBestForHndType(RTHANDLETYPE_FILE); 1025 else 1026 pIoQProv = RTIoQueueProviderGetById(pszIoEngine); 1027 1028 if (RT_LIKELY(pIoQProv)) 942 1029 { 943 rc = RTIoQueue HandleRegister(pJob->hIoQueue, &pJob->Hnd);1030 rc = RTIoQueueCreate(&pJob->hIoQueue, pIoQProv, 0 /*fFlags*/, cReqsMax, cReqsMax); 944 1031 if (RT_SUCCESS(rc)) 945 1032 { 946 /* Spin up the worker thread. */ 947 if (pMaster) 948 rc = RTThreadCreateF(&pJob->hThread, ioPerfJobThread, pJob, 0, 949 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "ioperf-%u", idJob); 950 1033 rc = RTIoQueueHandleRegister(pJob->hIoQueue, &pJob->Hnd); 951 1034 if (RT_SUCCESS(rc)) 952 return VINF_SUCCESS; 1035 { 1036 /* Spin up the worker thread. */ 1037 if (pMaster) 1038 rc = RTThreadCreateF(&pJob->hThread, ioPerfJobThread, pJob, 0, 1039 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "ioperf-%u", idJob); 1040 1041 if (RT_SUCCESS(rc)) 1042 return VINF_SUCCESS; 1043 } 953 1044 } 954 1045 } 1046 else 1047 rc = VERR_NOT_SUPPORTED; 955 1048 } 956 else 957 rc = VERR_NOT_SUPPORTED;1049 1050 RTRandAdvDestroy(pJob->hRand); 958 1051 } 959 1052 960 RTRandAdvDestroy(pJob->hRand); 1053 RTFileClose(pJob->Hnd.u.hFile); 1054 RTFileDelete(pJob->pszFilename); 961 1055 } 962 1056 963 RTFileClose(pJob->Hnd.u.hFile); 964 RTFileDelete(pJob->pszFilename); 1057 RTStrFree(pJob->pszFilename); 965 1058 } 966 967 RTStrFree(pJob->pszFilename); 1059 else 1060 rc = VERR_NO_STR_MEMORY; 1061 1062 RTMemPageFree(pJob->pvIoReqReadBuf, pJob->cbIoReqReadBuf); 968 1063 } 969 970 RTMemPageFree(pJob->pvIoReqReadBuf, pJob->cbIoReqReadBuf); 1064 else 1065 rc = VERR_NO_MEMORY; 1066 1067 RTMemFree(pJob->paReqStats); 971 1068 } 972 1069 else 973 rc = VERR_NO_STR_MEMORY; 974 } 1070 rc = VERR_NO_MEMORY; 1071 } 1072 else 1073 rc = VERR_NO_MEMORY; 975 1074 976 1075 return rc; … … 1001 1100 RTMemPageFree(pJob->pvIoReqReadBuf, pJob->cbIoReqReadBuf); 1002 1101 RTMemFree(pJob->paIoReqs); 1102 RTMemFree(pJob->paReqStats); 1003 1103 return VINF_SUCCESS; 1004 1104 }
Note:
See TracChangeset
for help on using the changeset viewer.