VirtualBox

Ignore:
Timestamp:
Mar 27, 2019 11:42:19 PM (6 years ago)
Author:
vboxsync
Message:

FsPerf: Added splice() tests and benchmarks. bugref:9172

File:
1 edited

Legend:

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

    r77925 r77926  
    4747#include <iprt/param.h>
    4848#include <iprt/path.h>
     49#ifdef RT_OS_LINUX
     50# include <iprt/pipe.h>
     51#endif
    4952#include <iprt/process.h>
    5053#include <iprt/rand.h>
     
    7376# ifdef RT_OS_LINUX
    7477#  include <sys/sendfile.h>
     78#  include <sys/syscall.h>
    7579# endif
    7680#endif
     
    278282    kCmdOpt_SendFile,
    279283    kCmdOpt_NoSendFile,
     284#ifdef RT_OS_LINUX
     285    kCmdOpt_Splice,
     286    kCmdOpt_NoSplice,
     287#endif
    280288    kCmdOpt_WritePerf,
    281289    kCmdOpt_NoWritePerf,
     
    362370    { "--sendfile",         kCmdOpt_SendFile,       RTGETOPT_REQ_NOTHING },
    363371    { "--no-sendfile",      kCmdOpt_NoSendFile,     RTGETOPT_REQ_NOTHING },
     372#ifdef RT_OS_LINUX
     373    { "--splice",           kCmdOpt_Splice,         RTGETOPT_REQ_NOTHING },
     374    { "--no-splice",        kCmdOpt_NoSplice,       RTGETOPT_REQ_NOTHING },
     375#endif
    364376    { "--write-tests",      kCmdOpt_WriteTests,     RTGETOPT_REQ_NOTHING },
    365377    { "--no-write-tests",   kCmdOpt_NoWriteTests,   RTGETOPT_REQ_NOTHING },
     
    425437static bool         g_fReadPerf  = true;
    426438static bool         g_fSendFile  = true;
     439#ifdef RT_OS_LINUX
     440static bool         g_fSplice    = true;
     441#endif
    427442static bool         g_fWriteTests= true;
    428443static bool         g_fWritePerf = true;
     
    19181933}
    19191934
    1920 #ifdef RT_OS_LINUX
     1935#if defined(RT_OS_LINUX)
     1936
    19211937/**
    19221938 * Send file thread arguments.
     
    19401956    FSPERFSENDFILEARGS *pArgs = (FSPERFSENDFILEARGS *)pvUser;
    19411957    int                 rc    = VINF_SUCCESS;
     1958
     1959    if (pArgs->fCheckBuf)
     1960        RTTestSetDefault(g_hTest, NULL);
    19421961
    19431962    uint64_t cbReceived = 0;
     
    20542073     */
    20552074    FSPERFSENDFILEARGS Args;
    2056     Args.cbBuf = _16M;
     2075    Args.cbBuf = RT_MIN(cbFileMax, _16M);
    20572076    Args.pbBuf = (uint8_t *)RTMemAlloc(Args.cbBuf);
    20582077    while (!Args.pbBuf)
     
    21282147    RTTestIValue("throughput", (uint64_t)(cbTotal / ((double)nsElapsed / RT_NS_1SEC)),  RTTESTUNIT_BYTES_PER_SEC);
    21292148    RTTestIValue("calls",      cIterations,                                             RTTESTUNIT_CALLS);
     2149    RTTestIValue("bytes",      cbTotal,                                                 RTTESTUNIT_BYTES);
     2150    if (g_fShowDuration)
     2151        RTTestIValue("duration", nsElapsed,                                             RTTESTUNIT_NS);
     2152
     2153    /*
     2154     * Cleanup.
     2155     */
     2156    RTMemFree(Args.pbBuf);
     2157}
     2158
     2159#endif /* RT_OS_LINUX */
     2160#ifdef RT_OS_LINUX
     2161
     2162/**
     2163 * Send file thread arguments.
     2164 */
     2165typedef struct FSPERFSPLICEARGS
     2166{
     2167    uint64_t            offFile;
     2168    size_t              cbSend;
     2169    uint64_t            cbSent;
     2170    size_t              cbBuf;
     2171    uint8_t            *pbBuf;
     2172    uint8_t             bFiller;
     2173    bool                fCheckBuf;
     2174    uint32_t            cCalls;
     2175    RTPIPE              hPipe;
     2176    uint64_t volatile   tsThreadDone;
     2177} FSPERFSPLICEARGS;
     2178
     2179
     2180/** Thread receiving the bytes from a splice() call. */
     2181static DECLCALLBACK(int) fsPerfSpliceRecvThread(RTTHREAD hSelf, void *pvUser)
     2182{
     2183    FSPERFSPLICEARGS *pArgs = (FSPERFSPLICEARGS *)pvUser;
     2184    int               rc    = VINF_SUCCESS;
     2185
     2186    if (pArgs->fCheckBuf)
     2187        RTTestSetDefault(g_hTest, NULL);
     2188
     2189    uint64_t cbReceived = 0;
     2190    while (cbReceived < pArgs->cbSent)
     2191    {
     2192        size_t const cbToRead = RT_MIN(pArgs->cbBuf, pArgs->cbSent - cbReceived);
     2193        size_t       cbActual = 0;
     2194        RTTEST_CHECK_RC_BREAK(g_hTest, rc = RTPipeReadBlocking(pArgs->hPipe, pArgs->pbBuf, cbToRead, &cbActual), VINF_SUCCESS);
     2195        RTTEST_CHECK_BREAK(g_hTest, cbActual != 0);
     2196        RTTEST_CHECK(g_hTest, cbActual <= cbToRead);
     2197        if (pArgs->fCheckBuf)
     2198            fsPerfCheckReadBuf(__LINE__, pArgs->offFile + cbReceived, pArgs->pbBuf, cbActual, pArgs->bFiller);
     2199        cbReceived += cbActual;
     2200    }
     2201
     2202    pArgs->tsThreadDone = RTTimeNanoTS();
     2203
     2204    if (cbReceived == pArgs->cbSent && RT_SUCCESS(rc))
     2205    {
     2206        size_t cbActual = 0;
     2207        rc = RTPipeRead(pArgs->hPipe, pArgs->pbBuf, 1, &cbActual);
     2208        if (rc != VINF_SUCCESS && rc != VINF_TRY_AGAIN && rc != VERR_BROKEN_PIPE)
     2209            RTTestFailed(g_hTest, "RTPipeReadBlocking() -> %Rrc; expected VINF_SUCCESS or VINF_TRY_AGAIN\n", rc);
     2210        else if (cbActual != 0)
     2211            RTTestFailed(g_hTest, "splice read pipe still contains data when done!\n");
     2212    }
     2213
     2214    RTTEST_CHECK_RC(g_hTest, RTPipeClose(pArgs->hPipe), VINF_SUCCESS);
     2215    pArgs->hPipe = NIL_RTPIPE;
     2216
     2217    RT_NOREF(hSelf);
     2218    return rc;
     2219}
     2220
     2221
     2222/** Sends hFile1 to a pipe via the Linux-specific splice() syscall. */
     2223static uint64_t fsPerfSpliceSendFile(FSPERFSPLICEARGS *pArgs, RTFILE hFile1, uint64_t offFile,
     2224                                     size_t cbSend, uint64_t cbSent, uint8_t bFiller, bool fCheckBuf, unsigned iLine)
     2225{
     2226    /* Copy parameters to the argument structure: */
     2227    pArgs->offFile   = offFile;
     2228    pArgs->cbSend    = cbSend;
     2229    pArgs->cbSent    = cbSent;
     2230    pArgs->bFiller   = bFiller;
     2231    pArgs->fCheckBuf = fCheckBuf;
     2232
     2233    /* Create a socket pair. */
     2234    pArgs->hPipe     = NIL_RTPIPE;
     2235    RTPIPE hPipeW    = NIL_RTPIPE;
     2236    RTTESTI_CHECK_RC_RET(RTPipeCreate(&pArgs->hPipe, &hPipeW, 0 /*fFlags*/), VINF_SUCCESS, 0);
     2237
     2238    /* Create the receiving thread: */
     2239    int rc;
     2240    RTTHREAD hThread = NIL_RTTHREAD;
     2241    RTTESTI_CHECK_RC(rc = RTThreadCreate(&hThread, fsPerfSpliceRecvThread, pArgs, 0,
     2242                                         RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "splicerecv"), VINF_SUCCESS);
     2243    if (RT_SUCCESS(rc))
     2244    {
     2245        uint64_t const  tsStart   = RTTimeNanoTS();
     2246        size_t          cbLeft    = cbSend;
     2247        size_t          cbTotal   = 0;
     2248        do
     2249        {
     2250            loff_t offFileIn = offFile;
     2251            ssize_t cbActual = splice((int)RTFileToNative(hFile1), &offFileIn, (int)RTPipeToNative(hPipeW), NULL,
     2252                                      cbLeft, 0 /*fFlags*/);
     2253            int const iErr = errno;
     2254            if (RT_UNLIKELY(cbActual < 0))
     2255            {
     2256                RTTestIFailed("%u: splice(file, &%#RX64, pipe, NULL, %#zx, 0) failed (%zd): %d (%Rrc), offFileIn=%#RX64\n",
     2257                              iLine, offFile, cbLeft, cbActual, iErr, RTErrConvertFromErrno(iErr), (uint64_t)offFileIn);
     2258                break;
     2259            }
     2260            RTTESTI_CHECK_BREAK((uint64_t)cbActual <= cbLeft);
     2261            if ((uint64_t)offFileIn != offFile + (uint64_t)cbActual)
     2262            {
     2263                RTTestIFailed("%u: splice(file, &%#RX64, pipe, NULL, %#zx, 0): %#zx; offFileIn=%#RX64, expected %#RX64\n",
     2264                              iLine, offFile, cbLeft, cbActual, (uint64_t)offFileIn, offFile + (uint64_t)cbActual);
     2265                break;
     2266            }
     2267            if (cbActual > 0)
     2268            {
     2269                pArgs->cCalls++;
     2270                offFile += (size_t)cbActual;
     2271                cbTotal += (size_t)cbActual;
     2272                cbLeft  -= (size_t)cbActual;
     2273            }
     2274            else
     2275                break;
     2276        } while (cbLeft > 0);
     2277
     2278        if (cbTotal != pArgs->cbSent)
     2279            RTTestIFailed("%u: spliced a total of %#zx bytes, expected %#zx!\n", iLine, cbTotal, pArgs->cbSent);
     2280
     2281        RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
     2282        RTTESTI_CHECK_RC(RTThreadWait(hThread, 30 * RT_NS_1SEC, NULL), VINF_SUCCESS);
     2283
     2284        if (pArgs->tsThreadDone >= tsStart)
     2285            return RT_MAX(pArgs->tsThreadDone - tsStart, 1);
     2286    }
     2287    return 0;
     2288}
     2289
     2290
     2291static void fsPerfSpliceToPipe(RTFILE hFile1, uint64_t cbFile)
     2292{
     2293    RTTestISub("splice/to-pipe");
     2294
     2295    /*
     2296     * splice was introduced in 2.6.17 according to the man-page.
     2297     */
     2298    char szRelease[64];
     2299    RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szRelease, sizeof(szRelease));
     2300    if (RTStrVersionCompare(szRelease, "2.6.17") < 0)
     2301    {
     2302        RTTestPassed(g_hTest, "too old kernel (%s)", szRelease);
     2303        return;
     2304    }
     2305
     2306    uint64_t const cbFileMax = RT_MIN(cbFile, UINT32_MAX - PAGE_OFFSET_MASK);
     2307    signal(SIGPIPE, SIG_IGN);
     2308
     2309    /*
     2310     * Allocate a buffer.
     2311     */
     2312    FSPERFSPLICEARGS Args;
     2313    Args.cbBuf = RT_MIN(cbFileMax, _16M);
     2314    Args.pbBuf = (uint8_t *)RTMemAlloc(Args.cbBuf);
     2315    while (!Args.pbBuf)
     2316    {
     2317        Args.cbBuf /= 8;
     2318        RTTESTI_CHECK_RETV(Args.cbBuf >= _64K);
     2319        Args.pbBuf = (uint8_t *)RTMemAlloc(Args.cbBuf);
     2320    }
     2321
     2322    /*
     2323     * First iteration with default buffer content.
     2324     */
     2325    fsPerfSpliceSendFile(&Args, hFile1, 0, cbFileMax, cbFileMax, 0xf6, true /*fCheckBuf*/, __LINE__);
     2326    if (cbFileMax == cbFile)
     2327        fsPerfSpliceSendFile(&Args, hFile1, 63, cbFileMax, cbFileMax - 63, 0xf6, true /*fCheckBuf*/, __LINE__);
     2328    else
     2329        fsPerfSpliceSendFile(&Args, hFile1, 63, cbFileMax - 63, cbFileMax - 63, 0xf6, true /*fCheckBuf*/, __LINE__);
     2330
     2331    /*
     2332     * Write a block using the regular API and then send it, checking that
     2333     * the any caching that sendfile does is correctly updated.
     2334     */
     2335    uint8_t bFiller = 0xf6;
     2336    size_t cbToSend = RT_MIN(cbFileMax, Args.cbBuf);
     2337    do
     2338    {
     2339        fsPerfSpliceSendFile(&Args, hFile1, 0, cbToSend, cbToSend, bFiller, true /*fCheckBuf*/, __LINE__); /* prime cache */
     2340
     2341        bFiller += 1;
     2342        fsPerfFillWriteBuf(0, Args.pbBuf, cbToSend, bFiller);
     2343        RTTESTI_CHECK_RC(RTFileWriteAt(hFile1, 0, Args.pbBuf, cbToSend, NULL), VINF_SUCCESS);
     2344
     2345        fsPerfSpliceSendFile(&Args, hFile1, 0, cbToSend, cbToSend, bFiller, true /*fCheckBuf*/, __LINE__);
     2346
     2347        cbToSend /= 2;
     2348    } while (cbToSend >= PAGE_SIZE && ((unsigned)bFiller - 0xf7U) < 64);
     2349
     2350    /*
     2351     * Restore buffer content
     2352     */
     2353    bFiller = 0xf6;
     2354    fsPerfFillWriteBuf(0, Args.pbBuf, Args.cbBuf, bFiller);
     2355    RTTESTI_CHECK_RC(RTFileWriteAt(hFile1, 0, Args.pbBuf, Args.cbBuf, NULL), VINF_SUCCESS);
     2356
     2357    /*
     2358     * Do 128 random sends.
     2359     */
     2360    uint64_t const cbSmall = RT_MIN(_256K, cbFileMax / 16);
     2361    for (uint32_t iTest = 0; iTest < 128; iTest++)
     2362    {
     2363        cbToSend                     = (size_t)RTRandU64Ex(1, iTest < 64 ? cbSmall : cbFileMax);
     2364        uint64_t const offToSendFrom = RTRandU64Ex(0, cbFile - 1);
     2365        uint64_t const cbSent        = offToSendFrom + cbToSend <= cbFile ? cbToSend : cbFile - offToSendFrom;
     2366
     2367        fsPerfSpliceSendFile(&Args, hFile1, offToSendFrom, cbToSend, cbSent, bFiller, true /*fCheckBuf*/, __LINE__);
     2368    }
     2369
     2370    /*
     2371     * Benchmark it.
     2372     */
     2373    Args.cCalls          = 0;
     2374    uint32_t cIterations = 0;
     2375    uint64_t nsElapsed   = 0;
     2376    for (;;)
     2377    {
     2378        uint64_t cNsThis = fsPerfSpliceSendFile(&Args, hFile1, 0, cbFileMax, cbFileMax, 0xf6, false /*fCheckBuf*/, __LINE__);
     2379        nsElapsed += cNsThis;
     2380        cIterations++;
     2381        if (!cNsThis || nsElapsed >= g_nsTestRun)
     2382            break;
     2383    }
     2384    uint64_t cbTotal = cbFileMax * cIterations;
     2385    RTTestIValue("latency",    nsElapsed / Args.cCalls,                                 RTTESTUNIT_NS_PER_CALL);
     2386    RTTestIValue("throughput", (uint64_t)(cbTotal / ((double)nsElapsed / RT_NS_1SEC)),  RTTESTUNIT_BYTES_PER_SEC);
     2387    RTTestIValue("calls",      Args.cCalls,                                             RTTESTUNIT_CALLS);
     2388    RTTestIValue("bytes/call", cbTotal / Args.cCalls,                                   RTTESTUNIT_BYTES);
     2389    RTTestIValue("iterations", cIterations,                                             RTTESTUNIT_NONE);
     2390    RTTestIValue("bytes",      cbTotal,                                                 RTTESTUNIT_BYTES);
     2391    if (g_fShowDuration)
     2392        RTTestIValue("duration", nsElapsed,                                             RTTESTUNIT_NS);
     2393
     2394    /*
     2395     * Cleanup.
     2396     */
     2397    RTMemFree(Args.pbBuf);
     2398}
     2399
     2400
     2401/** Thread sending the bytes to a splice() call. */
     2402static DECLCALLBACK(int) fsPerfSpliceSendThread(RTTHREAD hSelf, void *pvUser)
     2403{
     2404    FSPERFSPLICEARGS *pArgs = (FSPERFSPLICEARGS *)pvUser;
     2405    int               rc    = VINF_SUCCESS;
     2406
     2407    uint64_t offFile     = pArgs->offFile;
     2408    uint64_t cbTotalSent = 0;
     2409    while (cbTotalSent < pArgs->cbSent)
     2410    {
     2411        size_t const cbToSend = RT_MIN(pArgs->cbBuf, pArgs->cbSent - cbTotalSent);
     2412        fsPerfFillWriteBuf(offFile, pArgs->pbBuf, cbToSend, pArgs->bFiller);
     2413        RTTEST_CHECK_RC_BREAK(g_hTest, rc = RTPipeWriteBlocking(pArgs->hPipe, pArgs->pbBuf, cbToSend, NULL), VINF_SUCCESS);
     2414        offFile     += cbToSend;
     2415        cbTotalSent += cbToSend;
     2416    }
     2417
     2418    pArgs->tsThreadDone = RTTimeNanoTS();
     2419
     2420    RTTEST_CHECK_RC(g_hTest, RTPipeClose(pArgs->hPipe), VINF_SUCCESS);
     2421    pArgs->hPipe = NIL_RTPIPE;
     2422
     2423    RT_NOREF(hSelf);
     2424    return rc;
     2425}
     2426
     2427
     2428/** Fill hFile1 via a pipe and the Linux-specific splice() syscall. */
     2429static uint64_t fsPerfSpliceWriteFile(FSPERFSPLICEARGS *pArgs, RTFILE hFile1, uint64_t offFile,
     2430                                      size_t cbSend, uint64_t cbSent, uint8_t bFiller, bool fCheckFile, unsigned iLine)
     2431{
     2432    /* Copy parameters to the argument structure: */
     2433    pArgs->offFile   = offFile;
     2434    pArgs->cbSend    = cbSend;
     2435    pArgs->cbSent    = cbSent;
     2436    pArgs->bFiller   = bFiller;
     2437    pArgs->fCheckBuf = false;
     2438
     2439    /* Create a socket pair. */
     2440    pArgs->hPipe     = NIL_RTPIPE;
     2441    RTPIPE hPipeR    = NIL_RTPIPE;
     2442    RTTESTI_CHECK_RC_RET(RTPipeCreate(&hPipeR, &pArgs->hPipe, 0 /*fFlags*/), VINF_SUCCESS, 0);
     2443
     2444    /* Create the receiving thread: */
     2445    int rc;
     2446    RTTHREAD hThread = NIL_RTTHREAD;
     2447    RTTESTI_CHECK_RC(rc = RTThreadCreate(&hThread, fsPerfSpliceSendThread, pArgs, 0,
     2448                                         RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "splicerecv"), VINF_SUCCESS);
     2449    if (RT_SUCCESS(rc))
     2450    {
     2451        /*
     2452         * Do the splicing.
     2453         */
     2454        uint64_t const  tsStart   = RTTimeNanoTS();
     2455        size_t          cbLeft    = cbSend;
     2456        size_t          cbTotal   = 0;
     2457        do
     2458        {
     2459            loff_t offFileOut = offFile;
     2460            ssize_t cbActual  = splice((int)RTPipeToNative(hPipeR), NULL, (int)RTFileToNative(hFile1), &offFileOut,
     2461                                       cbLeft, 0 /*fFlags*/);
     2462            int const iErr = errno;
     2463            if (RT_UNLIKELY(cbActual < 0))
     2464            {
     2465                RTTestIFailed("%u: splice(pipe, NULL, file, &%#RX64, %#zx, 0) failed (%zd): %d (%Rrc), offFileOut=%#RX64\n",
     2466                              iLine, offFile, cbLeft, cbActual, iErr, RTErrConvertFromErrno(iErr), (uint64_t)offFileOut);
     2467                break;
     2468            }
     2469            RTTESTI_CHECK_BREAK((uint64_t)cbActual <= cbLeft);
     2470            if ((uint64_t)offFileOut != offFile + (uint64_t)cbActual)
     2471            {
     2472                RTTestIFailed("%u: splice(pipe, NULL, file, &%#RX64, %#zx, 0): %#zx; offFileOut=%#RX64, expected %#RX64\n",
     2473                              iLine, offFile, cbLeft, cbActual, (uint64_t)offFileOut, offFile + (uint64_t)cbActual);
     2474                break;
     2475            }
     2476            if (cbActual > 0)
     2477            {
     2478                pArgs->cCalls++;
     2479                offFile += (size_t)cbActual;
     2480                cbTotal += (size_t)cbActual;
     2481                cbLeft  -= (size_t)cbActual;
     2482            }
     2483            else
     2484                break;
     2485        } while (cbLeft > 0);
     2486        uint64_t const nsElapsed = RTTimeNanoTS() - tsStart;
     2487
     2488        if (cbTotal != pArgs->cbSent)
     2489            RTTestIFailed("%u: spliced a total of %#zx bytes, expected %#zx!\n", iLine, cbTotal, pArgs->cbSent);
     2490
     2491        RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
     2492        RTTESTI_CHECK_RC(RTThreadWait(hThread, 30 * RT_NS_1SEC, NULL), VINF_SUCCESS);
     2493
     2494        /* Check the file content. */
     2495        if (fCheckFile && cbTotal == pArgs->cbSent)
     2496        {
     2497            offFile = pArgs->offFile;
     2498            cbLeft  = cbSent;
     2499            while (cbLeft > 0)
     2500            {
     2501                size_t cbToRead = RT_MIN(cbLeft, pArgs->cbBuf);
     2502                RTTESTI_CHECK_RC_BREAK(RTFileReadAt(hFile1, offFile, pArgs->pbBuf, cbToRead, NULL), VINF_SUCCESS);
     2503                if (!fsPerfCheckReadBuf(iLine, offFile, pArgs->pbBuf, cbToRead, pArgs->bFiller))
     2504                    break;
     2505                offFile += cbToRead;
     2506                cbLeft  -= cbToRead;
     2507            }
     2508        }
     2509        return nsElapsed;
     2510    }
     2511    return 0;
     2512}
     2513
     2514
     2515static void fsPerfSpliceToFile(RTFILE hFile1, uint64_t cbFile)
     2516{
     2517    RTTestISub("splice/to-file");
     2518
     2519    /*
     2520     * splice was introduced in 2.6.17 according to the man-page.
     2521     */
     2522    char szRelease[64];
     2523    RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szRelease, sizeof(szRelease));
     2524    if (RTStrVersionCompare(szRelease, "2.6.17") < 0)
     2525    {
     2526        RTTestPassed(g_hTest, "too old kernel (%s)", szRelease);
     2527        return;
     2528    }
     2529
     2530    uint64_t const cbFileMax = RT_MIN(cbFile, UINT32_MAX - PAGE_OFFSET_MASK);
     2531    signal(SIGPIPE, SIG_IGN);
     2532
     2533    /*
     2534     * Allocate a buffer.
     2535     */
     2536    FSPERFSPLICEARGS Args;
     2537    Args.cbBuf = RT_MIN(cbFileMax, _16M);
     2538    Args.pbBuf = (uint8_t *)RTMemAlloc(Args.cbBuf);
     2539    while (!Args.pbBuf)
     2540    {
     2541        Args.cbBuf /= 8;
     2542        RTTESTI_CHECK_RETV(Args.cbBuf >= _64K);
     2543        Args.pbBuf = (uint8_t *)RTMemAlloc(Args.cbBuf);
     2544    }
     2545
     2546    /*
     2547     * Do the whole file.
     2548     */
     2549    uint8_t bFiller = 0x76;
     2550    fsPerfSpliceWriteFile(&Args, hFile1, 0, cbFileMax, cbFileMax, bFiller, true /*fCheckFile*/, __LINE__);
     2551
     2552    /*
     2553     * Do 64 random chunks (this is slower).
     2554     */
     2555    uint64_t const cbSmall = RT_MIN(_256K, cbFileMax / 16);
     2556    for (uint32_t iTest = 0; iTest < 64; iTest++)
     2557    {
     2558        size_t const   cbToWrite    = (size_t)RTRandU64Ex(1, iTest < 24 ? cbSmall : cbFileMax);
     2559        uint64_t const offToWriteAt = RTRandU64Ex(0, cbFile - cbToWrite);
     2560        uint64_t const cbTryRead    = cbToWrite + (iTest & 1 ? RTRandU32Ex(0, _64K) : 0);
     2561
     2562        bFiller++;
     2563        fsPerfSpliceWriteFile(&Args, hFile1, offToWriteAt, cbTryRead, cbToWrite, bFiller, true /*fCheckFile*/, __LINE__);
     2564    }
     2565
     2566    /*
     2567     * Benchmark it.
     2568     */
     2569    Args.cCalls          = 0;
     2570    uint32_t cIterations = 0;
     2571    uint64_t nsElapsed   = 0;
     2572    for (;;)
     2573    {
     2574        uint64_t cNsThis = fsPerfSpliceWriteFile(&Args, hFile1, 0, cbFileMax, cbFileMax, 0xf6, false /*fCheckBuf*/, __LINE__);
     2575        nsElapsed += cNsThis;
     2576        cIterations++;
     2577        if (!cNsThis || nsElapsed >= g_nsTestRun)
     2578            break;
     2579    }
     2580    uint64_t cbTotal = cbFileMax * cIterations;
     2581    RTTestIValue("latency",    nsElapsed / Args.cCalls,                                 RTTESTUNIT_NS_PER_CALL);
     2582    RTTestIValue("throughput", (uint64_t)(cbTotal / ((double)nsElapsed / RT_NS_1SEC)),  RTTESTUNIT_BYTES_PER_SEC);
     2583    RTTestIValue("calls",      Args.cCalls,                                             RTTESTUNIT_CALLS);
     2584    RTTestIValue("bytes/call", cbTotal / Args.cCalls,                                   RTTESTUNIT_BYTES);
     2585    RTTestIValue("iterations", cIterations,                                             RTTESTUNIT_NONE);
    21302586    RTTestIValue("bytes",      cbTotal,                                                 RTTESTUNIT_BYTES);
    21312587    if (g_fShowDuration)
     
    34443900            for (unsigned i = 0; i < g_cIoBlocks; i++)
    34453901                fsPerfIoReadBlockSize(hFile1, cbFile, g_acbIoBlocks[i]);
    3446 
    3447 #ifdef RT_OS_LINUX
     3902#if defined(RT_OS_LINUX)
    34483903        if (g_fSendFile)
    34493904            fsPerfSendFile(hFile1, cbFile);
    34503905#endif
    34513906#ifdef RT_OS_LINUX
    3452         //if (g_fSplice)
    3453         //    fsPerfSpliceOut(hFile1, cbFile);
     3907        if (g_fSplice)
     3908            fsPerfSpliceToPipe(hFile1, cbFile);
    34543909#endif
    3455 
    34563910        if (g_fMMap)
    34573911            fsPerfMMap(hFile1, hFileNoCache, cbFile);
     
    34633917            for (unsigned i = 0; i < g_cIoBlocks; i++)
    34643918                fsPerfIoWriteBlockSize(hFile1, cbFile, g_acbIoBlocks[i]);
    3465 
     3919#ifdef RT_OS_LINUX
     3920        if (g_fSplice)
     3921            fsPerfSpliceToFile(hFile1, cbFile);
     3922#endif
    34663923        if (g_fFSync)
    34673924            fsPerfFSync(hFile1, cbFile);
     
    39244381                g_fReadPerf  = true;
    39254382                g_fSendFile  = true;
     4383#ifdef RT_OS_LINUX
     4384                g_fSplice    = true;
     4385#endif
    39264386                g_fWriteTests= true;
    39274387                g_fWritePerf = true;
     
    39514411                g_fReadPerf  = false;
    39524412                g_fSendFile  = false;
     4413#ifdef RT_OS_LINUX
     4414                g_fSplice    = false;
     4415#endif
    39534416                g_fWriteTests= false;
    39544417                g_fWritePerf = false;
     
    39794442            CASE_OPT(ReadPerf);
    39804443            CASE_OPT(SendFile);
     4444#ifdef RT_OS_LINUX
     4445            CASE_OPT(Splice);
     4446#endif
    39814447            CASE_OPT(WriteTests);
    39824448            CASE_OPT(WritePerf);
     
    41384604                    fsPerfChSize();
    41394605                if (   g_fReadPerf || g_fReadTests || g_fSendFile || g_fWritePerf || g_fWriteTests
     4606#ifdef RT_OS_LINUX
     4607                    || g_fSplice
     4608#endif
    41404609                    || g_fSeek || g_fFSync || g_fMMap)
    41414610                    fsPerfIo();
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