VirtualBox

Ignore:
Timestamp:
Mar 21, 2019 6:08:12 PM (6 years ago)
Author:
vboxsync
Message:

FsPerf: Added file copy tests and benchmark. bugref:9172

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/utils/fs/FsPerf.cpp

    r77692 r77831  
    284284    kCmdOpt_SetBlockSize,
    285285    kCmdOpt_AddBlockSize,
     286    kCmdOpt_Copy,
     287    kCmdOpt_NoCopy,
    286288
    287289    kCmdOpt_ShowDuration,
     
    364366    { "--set-block-size",   kCmdOpt_SetBlockSize,   RTGETOPT_REQ_UINT32 },
    365367    { "--add-block-size",   kCmdOpt_AddBlockSize,   RTGETOPT_REQ_UINT32 },
     368    { "--copy",             kCmdOpt_Copy,           RTGETOPT_REQ_NOTHING },
     369    { "--no-copy",          kCmdOpt_NoCopy,         RTGETOPT_REQ_NOTHING },
    366370
    367371    { "--show-duration",        kCmdOpt_ShowDuration,       RTGETOPT_REQ_NOTHING },
     
    414418static bool         g_fFSync     = true;
    415419static bool         g_fMMap      = true;
     420static bool         g_fCopy      = true;
    416421/** @} */
    417422
     
    451456/** The test directory (absolute).  This will always have a trailing slash. */
    452457static char         g_szDir[RTPATH_MAX];
     458/** The test directory (absolute), 2nd copy for use with InDir2().  */
     459static char         g_szDir2[RTPATH_MAX];
    453460/** The empty test directory (absolute). This will always have a trailing slash. */
    454461static char         g_szEmptyDir[RTPATH_MAX];
     
    508515    g_szDir[g_cchDir + cchAppend] = '\0';
    509516    return &g_szDir[0];
     517}
     518
     519
     520/**
     521 * Construct a path relative to the base test directory, 2nd copy.
     522 *
     523 * @returns g_szDir2.
     524 * @param   pszAppend           What to append.
     525 * @param   cchAppend           How much to append.
     526 */
     527DECLINLINE(char *) InDir2(const char *pszAppend, size_t cchAppend)
     528{
     529    Assert(g_szDir[g_cchDir - 1] == RTPATH_SLASH);
     530    memcpy(g_szDir2, g_szDir, g_cchDir);
     531    memcpy(&g_szDir2[g_cchDir], pszAppend, cchAppend);
     532    g_szDir2[g_cchDir + cchAppend] = '\0';
     533    return &g_szDir2[0];
    510534}
    511535
     
    30703094    if (cbFile + _16M < (uint64_t)cbFree)
    30713095        cbFile = RT_ALIGN_64(cbFile, _64K);
     3096    else if (cbFree < _32M)
     3097    {
     3098        RTTestSkipped(g_hTest, "Insufficent free space: %'RU64 bytes, requires >= 32MB", cbFree);
     3099        return;
     3100    }
    30723101    else
    30733102    {
    3074         if (cbFree < _32M)
    3075         {
    3076             RTTestSkipped(g_hTest, "Insufficent free space: %'RU64 bytes, requires >= 32MB", cbFree);
    3077             return;
    3078         }
    30793103        cbFile = cbFree - (cbFree > _128M ? _64M : _16M);
    30803104        cbFile = RT_ALIGN_64(cbFile, _64K);
     
    31483172        RTTESTI_CHECK_RC(RTFileClose(hFileNoCache), VINF_SUCCESS);
    31493173    RTTESTI_CHECK_RC(RTFileClose(hFileWriteThru), VINF_SUCCESS);
     3174    RTTESTI_CHECK_RC(RTFileDelete(g_szDir), VINF_SUCCESS);
     3175}
     3176
     3177
     3178DECL_FORCE_INLINE(int) fsPerfCopyWorker1(const char *pszSrc, const char *pszDst)
     3179{
     3180    RTFileDelete(pszDst);
     3181    return RTFileCopy(pszSrc, pszDst);
     3182}
     3183
     3184
     3185static void fsPerfCopy(void)
     3186{
     3187    RTTestISub("copy");
     3188
     3189    /*
     3190     * Non-existing files.
     3191     */
     3192    RTTESTI_CHECK_RC(RTFileCopy(InEmptyDir(RT_STR_TUPLE("no-such-file")),
     3193                                InDir2(RT_STR_TUPLE("whatever"))), VERR_FILE_NOT_FOUND);
     3194    RTTESTI_CHECK_RC(RTFileCopy(InEmptyDir(RT_STR_TUPLE("no-such-dir" RTPATH_SLASH_STR "no-such-file")),
     3195                                InDir2(RT_STR_TUPLE("no-such-file"))), FSPERF_VERR_PATH_NOT_FOUND);
     3196    RTTESTI_CHECK_RC(RTFileCopy(InDir(RT_STR_TUPLE("known-file" RTPATH_SLASH_STR "no-such-file")),
     3197                                InDir2(RT_STR_TUPLE("whatever"))), VERR_PATH_NOT_FOUND);
     3198
     3199    RTTESTI_CHECK_RC(RTFileCopy(InDir(RT_STR_TUPLE("known-file")),
     3200                                InEmptyDir(RT_STR_TUPLE("no-such-dir" RTPATH_SLASH_STR "no-such-file"))), FSPERF_VERR_PATH_NOT_FOUND);
     3201    RTTESTI_CHECK_RC(RTFileCopy(InDir(RT_STR_TUPLE("known-file")),
     3202                                InDir2(RT_STR_TUPLE("known-file" RTPATH_SLASH_STR "no-such-file"))), VERR_PATH_NOT_FOUND);
     3203
     3204    /*
     3205     * Determin the size of the test file.
     3206     * We want to be able to make 1 copy of it.
     3207     */
     3208    g_szDir[g_cchDir] = '\0';
     3209    RTFOFF cbFree = 0;
     3210    RTTESTI_CHECK_RC_RETV(RTFsQuerySizes(g_szDir, NULL, &cbFree, NULL, NULL), VINF_SUCCESS);
     3211    uint64_t cbFile = g_cbIoFile;
     3212    if (cbFile + _16M < (uint64_t)cbFree)
     3213        cbFile = RT_ALIGN_64(cbFile, _64K);
     3214    else if (cbFree < _32M)
     3215    {
     3216        RTTestSkipped(g_hTest, "Insufficent free space: %'RU64 bytes, requires >= 32MB", cbFree);
     3217        return;
     3218    }
     3219    else
     3220    {
     3221        cbFile = cbFree - (cbFree > _128M ? _64M : _16M);
     3222        cbFile = RT_ALIGN_64(cbFile, _64K);
     3223        RTTestIPrintf(RTTESTLVL_ALWAYS,  "Adjusted file size to %'RU64 bytes, due to %'RU64 bytes free.\n", cbFile, cbFree);
     3224    }
     3225    if (cbFile < _512K * 2)
     3226    {
     3227        RTTestSkipped(g_hTest, "Specified test file size too small: %'RU64 bytes, requires >= 1MB", cbFile);
     3228        return;
     3229    }
     3230    cbFile /= 2;
     3231
     3232    /*
     3233     * Create a cbFile sized test file.
     3234     */
     3235    RTFILE hFile1;
     3236    RTTESTI_CHECK_RC_RETV(RTFileOpen(&hFile1, InDir(RT_STR_TUPLE("file22")),
     3237                                     RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_READWRITE), VINF_SUCCESS);
     3238    uint8_t *pbFree = NULL;
     3239    int rc = fsPerfIoPrepFile(hFile1, cbFile, &pbFree);
     3240    RTMemFree(pbFree);
     3241    RTTESTI_CHECK_RC(RTFileClose(hFile1), VINF_SUCCESS);
     3242    if (RT_SUCCESS(rc))
     3243    {
     3244        /*
     3245         * Make copies.
     3246         */
     3247        /* plain */
     3248        RTFileDelete(InDir2(RT_STR_TUPLE("file23")));
     3249        RTTESTI_CHECK_RC(RTFileCopy(g_szDir, g_szDir2), VINF_SUCCESS);
     3250        RTTESTI_CHECK_RC(RTFileCopy(g_szDir, g_szDir2), VERR_ALREADY_EXISTS);
     3251        RTTESTI_CHECK_RC(RTFileCompare(g_szDir, g_szDir2), VINF_SUCCESS);
     3252
     3253        /* by handle */
     3254        hFile1 = NIL_RTFILE;
     3255        RTTESTI_CHECK_RC(RTFileOpen(&hFile1, g_szDir, RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_READ), VINF_SUCCESS);
     3256        RTFILE hFile2 = NIL_RTFILE;
     3257        RTTESTI_CHECK_RC(RTFileOpen(&hFile2, g_szDir2, RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_WRITE), VINF_SUCCESS);
     3258        RTTESTI_CHECK_RC(RTFileCopyByHandles(hFile1, hFile2), VINF_SUCCESS);
     3259        RTTESTI_CHECK_RC(RTFileClose(hFile2), VINF_SUCCESS);
     3260        RTTESTI_CHECK_RC(RTFileClose(hFile1), VINF_SUCCESS);
     3261        RTTESTI_CHECK_RC(RTFileCompare(g_szDir, g_szDir2), VINF_SUCCESS);
     3262
     3263        /* copy part */
     3264        hFile1 = NIL_RTFILE;
     3265        RTTESTI_CHECK_RC(RTFileOpen(&hFile1, g_szDir, RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_READ), VINF_SUCCESS);
     3266        hFile2 = NIL_RTFILE;
     3267        RTTESTI_CHECK_RC(RTFileOpen(&hFile2, g_szDir2, RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_WRITE), VINF_SUCCESS);
     3268        RTTESTI_CHECK_RC(RTFileCopyPart(hFile1, 0, hFile2, 0, cbFile / 2, 0, NULL), VINF_SUCCESS);
     3269        RTTESTI_CHECK_RC(RTFileCopyPart(hFile1, cbFile / 2, hFile2, cbFile / 2, cbFile - cbFile / 2, 0, NULL), VINF_SUCCESS);
     3270        RTTESTI_CHECK_RC(RTFileClose(hFile2), VINF_SUCCESS);
     3271        RTTESTI_CHECK_RC(RTFileClose(hFile1), VINF_SUCCESS);
     3272        RTTESTI_CHECK_RC(RTFileCompare(g_szDir, g_szDir2), VINF_SUCCESS);
     3273
     3274        /*
     3275         * Do some benchmarking.
     3276         */
     3277#define PROFILE_COPY_FN(a_szOperation, a_fnCall) \
     3278            do \
     3279            { \
     3280                /* Estimate how many iterations we need to fill up the given timeslot: */ \
     3281                fsPerfYield(); \
     3282                uint64_t nsStart = RTTimeNanoTS(); \
     3283                uint64_t ns; \
     3284                do \
     3285                    ns = RTTimeNanoTS(); \
     3286                while (ns == nsStart); \
     3287                nsStart = ns; \
     3288                \
     3289                uint64_t iIteration = 0; \
     3290                do \
     3291                { \
     3292                    RTTESTI_CHECK_RC(a_fnCall, VINF_SUCCESS); \
     3293                    iIteration++; \
     3294                    ns = RTTimeNanoTS() - nsStart; \
     3295                } while (ns < RT_NS_10MS); \
     3296                ns /= iIteration; \
     3297                if (ns > g_nsPerNanoTSCall + 32) \
     3298                    ns -= g_nsPerNanoTSCall; \
     3299                uint64_t cIterations = g_nsTestRun / ns; \
     3300                if (cIterations < 2) \
     3301                    cIterations = 2; \
     3302                else if (cIterations & 1) \
     3303                    cIterations++; \
     3304                \
     3305                /* Do the actual profiling: */ \
     3306                iIteration = 0; \
     3307                fsPerfYield(); \
     3308                nsStart = RTTimeNanoTS(); \
     3309                for (uint32_t iAdjust = 0; iAdjust < 4; iAdjust++) \
     3310                { \
     3311                    for (; iIteration < cIterations; iIteration++)\
     3312                        RTTESTI_CHECK_RC(a_fnCall, VINF_SUCCESS); \
     3313                    ns = RTTimeNanoTS() - nsStart;\
     3314                    if (ns >= g_nsTestRun - (g_nsTestRun / 10)) \
     3315                        break; \
     3316                    cIterations += cIterations / 4; \
     3317                    if (cIterations & 1) \
     3318                        cIterations++; \
     3319                    nsStart += g_nsPerNanoTSCall; \
     3320                } \
     3321                RTTestIValueF(ns / iIteration, \
     3322                              RTTESTUNIT_NS_PER_OCCURRENCE, a_szOperation " latency"); \
     3323                RTTestIValueF((uint64_t)((uint64_t)iIteration * cbFile / ((double)ns / RT_NS_1SEC)), \
     3324                              RTTESTUNIT_BYTES_PER_SEC,     a_szOperation " throughput"); \
     3325                RTTestIValueF((uint64_t)iIteration * cbFile, \
     3326                              RTTESTUNIT_BYTES,             a_szOperation " bytes"); \
     3327                RTTestIValueF(iIteration, \
     3328                              RTTESTUNIT_OCCURRENCES,       a_szOperation " iterations"); \
     3329                if (g_fShowDuration) \
     3330                    RTTestIValueF(ns, RTTESTUNIT_NS,        a_szOperation " duration"); \
     3331            } while (0)
     3332
     3333        PROFILE_COPY_FN("RTFileCopy/Replace",           fsPerfCopyWorker1(g_szDir, g_szDir2));
     3334
     3335        hFile1 = NIL_RTFILE;
     3336        RTTESTI_CHECK_RC(RTFileOpen(&hFile1, g_szDir, RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_READ), VINF_SUCCESS);
     3337        RTFileDelete(g_szDir2);
     3338        hFile2 = NIL_RTFILE;
     3339        RTTESTI_CHECK_RC(RTFileOpen(&hFile2, g_szDir2, RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_WRITE), VINF_SUCCESS);
     3340        PROFILE_COPY_FN("RTFileCopyByHandles/Overwrite", RTFileCopyByHandles(hFile1, hFile2));
     3341        RTTESTI_CHECK_RC(RTFileClose(hFile2), VINF_SUCCESS);
     3342        RTTESTI_CHECK_RC(RTFileClose(hFile1), VINF_SUCCESS);
     3343
     3344        /* We could benchmark RTFileCopyPart with various block sizes and whatnot...
     3345           But it's currently well covered by the two previous operations. */
     3346    }
     3347
     3348    /*
     3349     * Clean up.
     3350     */
     3351    RTFileDelete(InDir2(RT_STR_TUPLE("file22c1")));
     3352    RTFileDelete(InDir2(RT_STR_TUPLE("file22c2")));
     3353    RTFileDelete(InDir2(RT_STR_TUPLE("file22c3")));
    31503354    RTTESTI_CHECK_RC(RTFileDelete(g_szDir), VINF_SUCCESS);
    31513355}
     
    33113515                g_fFSync     = true;
    33123516                g_fMMap      = true;
     3517                g_fCopy      = true;
    33133518                break;
    33143519
     
    33363541                g_fFSync     = false;
    33373542                g_fMMap      = false;
     3543                g_fCopy      = false;
    33383544                break;
    33393545
     
    33633569            CASE_OPT(MMap);
    33643570            CASE_OPT(IgnoreNoCache);
     3571            CASE_OPT(Copy);
    33653572
    33663573            CASE_OPT(ShowDuration);
     
    35163723                if (g_fReadPerf || g_fReadTests || g_fWritePerf || g_fWriteTests || g_fSeek || g_fFSync || g_fMMap)
    35173724                    fsPerfIo();
     3725                if (g_fCopy)
     3726                    fsPerfCopy();
    35183727            }
    35193728
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