VirtualBox

Changeset 80186 in vbox for trunk/src/VBox/ValidationKit


Ignore:
Timestamp:
Aug 7, 2019 2:14:00 PM (5 years ago)
Author:
vboxsync
Message:

ValidationKit/IoPerf: Statistics

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/utils/storage/IoPerf.cpp

    r80185 r80186  
    110110
    111111/**
     112 * Statistics values for a single request kept around until the
     113 * test completed for statistics collection.
     114 */
     115typedef 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. */
     123typedef IOPERFREQSTAT *PIOPERFREQSTAT;
     124
     125
     126/**
    112127 * I/O perf request.
    113128 */
    114129typedef struct IOPERFREQ
    115130{
    116     /** Start timestamp. */
    117     uint64_t                    tsStart;
    118131    /** Request operation code. */
    119132    RTIOQUEUEOP                 enmOp;
     
    128141    /** Size of the read buffer. */
    129142    size_t                      cbXferRead;
     143    /** Pointer to statistics record. */
     144    PIOPERFREQSTAT              pStats;
    130145} IOPERFREQ;
    131146/** Pointer to an I/O perf request. */
     
    178193    /** Start timestamp. */
    179194    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;
    180203    /** Test dependent data. */
    181204    union
     
    498521        pIoReq->pvXfer = NULL;
    499522
    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;
    501531}
    502532
     
    549579    int rc = VINF_SUCCESS;
    550580
     581    pJob->idxReqStatNext = 0;
     582
    551583    switch (pJob->enmTest)
    552584    {
     
    595627static void ioPerfJobTestFinish(PIOPERFJOB pJob)
    596628{
    597     uint64_t nsRuntime = RTTimeNanoTS() - pJob->tsStart;
    598     RTTestIValue("Runtime", nsRuntime, RTTESTUNIT_NS);
     629    pJob->tsFinish = RTTimeNanoTS();
    599630
    600631    switch (pJob->enmTest)
     
    707738                            Assert(paIoQCEvt[i].cbXfered == pReq->cbXfer);
    708739
    709                             /** @todo Statistics collection. */
     740                            if (pReq->pStats)
     741                                pReq->pStats->tsComplete = RTTimeNanoTS();
     742
    710743                            if (!ioPerfJobTestIsDone(pJob))
    711744                            {
     
    719752                                cReqsQueued--;
    720753                        }
     754                        else
     755                            RTTestIErrorInc();
    721756                    }
    722757
     
    740775
    741776/**
     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 */
     783static 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/**
    742819 * Synchronizes with the other jobs and waits for the current test to execute.
    743820 *
     
    785862        if (RT_FAILURE(rc))
    786863            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);
    787872    }
    788873
     
    883968    pJob->cbIoReqReadBuf = cReqsMax * cbIoBlock;
    884969    pJob->uWriteChance   = uWriteChance;
     970    pJob->cReqStats      = (uint32_t)(pJob->cbTestSet / pJob->cbIoBlock + ((pJob->cbTestSet % pJob->cbIoBlock) ? 1 : 0));
     971    pJob->idxReqStatNext = 0;
    885972
    886973    int rc = VINF_SUCCESS;
     
    888975    if (RT_LIKELY(pJob->paIoReqs))
    889976    {
    890         pJob->pvIoReqReadBuf = RTMemPageAlloc(pJob->cbIoReqReadBuf);
    891         if (RT_LIKELY(pJob->pvIoReqReadBuf))
     977        pJob->paReqStats = (PIOPERFREQSTAT)RTMemAllocZ(pJob->cReqStats * sizeof(IOPERFREQSTAT));
     978        if (RT_LIKELY(pJob->paReqStats))
    892979        {
    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))
    896982            {
    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++)
    911986                {
    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);
    9261000                    if (RT_SUCCESS(rc))
    9271001                    {
    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
    9291016                        if (RT_SUCCESS(rc))
    9301017                        {
    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))
    9391020                            {
    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))
    9421029                                {
    943                                     rc = RTIoQueueHandleRegister(pJob->hIoQueue, &pJob->Hnd);
     1030                                    rc = RTIoQueueCreate(&pJob->hIoQueue, pIoQProv, 0 /*fFlags*/, cReqsMax, cReqsMax);
    9441031                                    if (RT_SUCCESS(rc))
    9451032                                    {
    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);
    9511034                                        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                                        }
    9531044                                    }
    9541045                                }
     1046                                else
     1047                                    rc = VERR_NOT_SUPPORTED;
    9551048                            }
    956                             else
    957                                 rc = VERR_NOT_SUPPORTED;
     1049
     1050                            RTRandAdvDestroy(pJob->hRand);
    9581051                        }
    9591052
    960                         RTRandAdvDestroy(pJob->hRand);
     1053                        RTFileClose(pJob->Hnd.u.hFile);
     1054                        RTFileDelete(pJob->pszFilename);
    9611055                    }
    9621056
    963                     RTFileClose(pJob->Hnd.u.hFile);
    964                     RTFileDelete(pJob->pszFilename);
     1057                    RTStrFree(pJob->pszFilename);
    9651058                }
    966 
    967                 RTStrFree(pJob->pszFilename);
     1059                else
     1060                    rc = VERR_NO_STR_MEMORY;
     1061
     1062                RTMemPageFree(pJob->pvIoReqReadBuf, pJob->cbIoReqReadBuf);
    9681063            }
    969 
    970             RTMemPageFree(pJob->pvIoReqReadBuf, pJob->cbIoReqReadBuf);
     1064            else
     1065                rc = VERR_NO_MEMORY;
     1066
     1067            RTMemFree(pJob->paReqStats);
    9711068        }
    9721069        else
    973             rc = VERR_NO_STR_MEMORY;
    974     }
     1070            rc = VERR_NO_MEMORY;
     1071    }
     1072    else
     1073        rc = VERR_NO_MEMORY;
    9751074
    9761075    return rc;
     
    10011100    RTMemPageFree(pJob->pvIoReqReadBuf, pJob->cbIoReqReadBuf);
    10021101    RTMemFree(pJob->paIoReqs);
     1102    RTMemFree(pJob->paReqStats);
    10031103    return VINF_SUCCESS;
    10041104}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette