VirtualBox

Ignore:
Timestamp:
Mar 27, 2019 8:54:22 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
129638
Message:

FsPerf: Added regular sendfile test (currently linux only). bugref:9172

File:
1 edited

Legend:

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

    r77908 r77925  
    5252#include <iprt/stream.h>
    5353#include <iprt/system.h>
     54#include <iprt/tcp.h>
    5455#include <iprt/test.h>
    5556#include <iprt/time.h>
     
    6869#  include <sys/uio.h>
    6970# endif
     71# include <sys/socket.h>
     72# include <signal.h>
    7073# ifdef RT_OS_LINUX
    7174#  include <sys/sendfile.h>
     
    273276    kCmdOpt_ReadTests,
    274277    kCmdOpt_NoReadTests,
     278    kCmdOpt_SendFile,
     279    kCmdOpt_NoSendFile,
    275280    kCmdOpt_WritePerf,
    276281    kCmdOpt_NoWritePerf,
     
    355360    { "--read-perf",        kCmdOpt_ReadPerf,       RTGETOPT_REQ_NOTHING },
    356361    { "--no-read-perf",     kCmdOpt_NoReadPerf,     RTGETOPT_REQ_NOTHING },
     362    { "--sendfile",         kCmdOpt_SendFile,       RTGETOPT_REQ_NOTHING },
     363    { "--no-sendfile",      kCmdOpt_NoSendFile,     RTGETOPT_REQ_NOTHING },
    357364    { "--write-tests",      kCmdOpt_WriteTests,     RTGETOPT_REQ_NOTHING },
    358365    { "--no-write-tests",   kCmdOpt_NoWriteTests,   RTGETOPT_REQ_NOTHING },
     
    417424static bool         g_fReadTests = true;
    418425static bool         g_fReadPerf  = true;
     426static bool         g_fSendFile  = true;
    419427static bool         g_fWriteTests= true;
    420428static bool         g_fWritePerf = true;
     
    19101918}
    19111919
     1920#ifdef RT_OS_LINUX
     1921/**
     1922 * Send file thread arguments.
     1923 */
     1924typedef struct FSPERFSENDFILEARGS
     1925{
     1926    uint64_t            offFile;
     1927    size_t              cbSend;
     1928    uint64_t            cbSent;
     1929    size_t              cbBuf;
     1930    uint8_t            *pbBuf;
     1931    uint8_t             bFiller;
     1932    bool                fCheckBuf;
     1933    RTSOCKET            hSocket;
     1934    uint64_t volatile   tsThreadDone;
     1935} FSPERFSENDFILEARGS;
     1936
     1937/** Thread receiving the bytes from a sendfile() call. */
     1938static DECLCALLBACK(int) fsPerfSendFileThread(RTTHREAD hSelf, void *pvUser)
     1939{
     1940    FSPERFSENDFILEARGS *pArgs = (FSPERFSENDFILEARGS *)pvUser;
     1941    int                 rc    = VINF_SUCCESS;
     1942
     1943    uint64_t cbReceived = 0;
     1944    while (cbReceived < pArgs->cbSent)
     1945    {
     1946        size_t const cbToRead = RT_MIN(pArgs->cbBuf, pArgs->cbSent - cbReceived);
     1947        size_t       cbActual = 0;
     1948        RTTEST_CHECK_RC_BREAK(g_hTest, rc = RTTcpRead(pArgs->hSocket, pArgs->pbBuf, cbToRead, &cbActual), VINF_SUCCESS);
     1949        RTTEST_CHECK_BREAK(g_hTest, cbActual != 0);
     1950        RTTEST_CHECK(g_hTest, cbActual <= cbToRead);
     1951        if (pArgs->fCheckBuf)
     1952            fsPerfCheckReadBuf(__LINE__, pArgs->offFile + cbReceived, pArgs->pbBuf, cbActual, pArgs->bFiller);
     1953        cbReceived += cbActual;
     1954    }
     1955
     1956    pArgs->tsThreadDone = RTTimeNanoTS();
     1957
     1958    if (cbReceived == pArgs->cbSent && RT_SUCCESS(rc))
     1959    {
     1960        size_t cbActual = 0;
     1961        rc = RTSocketReadNB(pArgs->hSocket, pArgs->pbBuf, 1, &cbActual);
     1962        if (rc != VINF_SUCCESS && rc != VINF_TRY_AGAIN)
     1963            RTTestFailed(g_hTest, "RTSocketReadNB(sendfile client socket) -> %Rrc; expected VINF_SUCCESS or VINF_TRY_AGAIN\n", rc);
     1964        else if (cbActual != 0)
     1965            RTTestFailed(g_hTest, "sendfile client socket still contains data when done!\n");
     1966    }
     1967
     1968    RTTEST_CHECK_RC(g_hTest, RTSocketClose(pArgs->hSocket), VINF_SUCCESS);
     1969    pArgs->hSocket = NIL_RTSOCKET;
     1970
     1971    RT_NOREF(hSelf);
     1972    return rc;
     1973}
     1974
     1975
     1976static uint64_t fsPerfSendFileOne(FSPERFSENDFILEARGS *pArgs, RTFILE hFile1, uint64_t offFile,
     1977                                  size_t cbSend, uint64_t cbSent, uint8_t bFiller, bool fCheckBuf, unsigned iLine)
     1978{
     1979    /* Copy parameters to the argument structure: */
     1980    pArgs->offFile   = offFile;
     1981    pArgs->cbSend    = cbSend;
     1982    pArgs->cbSent    = cbSent;
     1983    pArgs->bFiller   = bFiller;
     1984    pArgs->fCheckBuf = fCheckBuf;
     1985
     1986    /* Create a socket pair. */
     1987    pArgs->hSocket   = NIL_RTSOCKET;
     1988    RTSOCKET hServer = NIL_RTSOCKET;
     1989    RTTESTI_CHECK_RC_RET(RTTcpCreatePair(&hServer, &pArgs->hSocket, 0), VINF_SUCCESS, 0);
     1990
     1991    /* Create the receiving thread: */
     1992    int rc;
     1993    RTTHREAD hThread = NIL_RTTHREAD;
     1994    RTTESTI_CHECK_RC(rc = RTThreadCreate(&hThread, fsPerfSendFileThread, pArgs, 0,
     1995                                         RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "sendfile"), VINF_SUCCESS);
     1996    if (RT_SUCCESS(rc))
     1997    {
     1998        uint64_t const tsStart = RTTimeNanoTS();
     1999
     2000# if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
     2001        /* SystemV sendfile: */
     2002        loff_t offFileSf = pArgs->offFile;
     2003        ssize_t cbActual = sendfile((int)RTSocketToNative(hServer), (int)RTFileToNative(hFile1), &offFileSf, pArgs->cbSend);
     2004        int const iErr = errno;
     2005        if (cbActual < 0)
     2006            RTTestIFailed("%u: sendfile(socket, file, &%#X64, %#zx) failed (%zd): %d (%Rrc), offFileSf=%#RX64\n",
     2007                          iLine, pArgs->offFile, pArgs->cbSend, cbActual, iErr, RTErrConvertFromErrno(iErr), (uint64_t)offFileSf);
     2008        else if ((uint64_t)cbActual != pArgs->cbSent)
     2009            RTTestIFailed("%u: sendfile(socket, file, &%#RX64, %#zx): %#zx, expected %#RX64 (offFileSf=%#RX64)\n",
     2010                          iLine, pArgs->offFile, pArgs->cbSend, cbActual, pArgs->cbSent, (uint64_t)offFileSf);
     2011        else if ((uint64_t)offFileSf != pArgs->offFile + pArgs->cbSent)
     2012            RTTestIFailed("%u: sendfile(socket, file, &%#RX64, %#zx): %#zx; offFileSf=%#RX64, expected %#RX64\n",
     2013                          iLine, pArgs->offFile, pArgs->cbSend, cbActual, (uint64_t)offFileSf, pArgs->offFile + pArgs->cbSent);
     2014#else
     2015        /* BSD sendfile: */
     2016#  ifdef SF_SYNC
     2017        int fSfFlags = SF_SYNC;
     2018#  else
     2019        int fSfFlags = 0;
     2020#  endif
     2021        off_t cbActual = pArgs->cbSend;
     2022        rc = sendfile((int)RTFileToNative(hFile1), (int)RTSocketToNative(hServer),
     2023                      pArgs->offFile, cbActual, NULL,  &cbActual, fSfFlags);
     2024        int const iErr = errno;
     2025        if (rc != 0)
     2026            RTTestIFailed("%u: sendfile(file, socket, %#RX64, %#zx, NULL,, %#x) failed (%d): %d (%Rrc), cbActual=%#RX64\n",
     2027                          iLine, pArgs->offFile, (size_t)pArgs->cbSend, rc, iErr, RTErrConvertFromErrno(iErr), (uint64_t)cbActual);
     2028        if ((uint64_t)cbActual != pArgs->cbSent)
     2029            RTTestIFailed("%u: sendfile(file, socket, %#RX64, %#zx, NULL,, %#x): cbActual=%#RX64, expected %#RX64 (rc=%d, errno=%d)\n",
     2030                          iLine, pArgs->offFile, (size_t)pArgs->cbSend, (uint64_t)cbActual, pArgs->cbSent, rc, iErr);
     2031# endif
     2032        RTTESTI_CHECK_RC(RTSocketClose(hServer), VINF_SUCCESS);
     2033        RTTESTI_CHECK_RC(RTThreadWait(hThread, 30 * RT_NS_1SEC, NULL), VINF_SUCCESS);
     2034
     2035        if (pArgs->tsThreadDone >= tsStart)
     2036            return RT_MAX(pArgs->tsThreadDone - tsStart, 1);
     2037    }
     2038    return 0;
     2039}
     2040
     2041
     2042static void fsPerfSendFile(RTFILE hFile1, uint64_t cbFile)
     2043{
     2044    RTTestISub("sendfile");
     2045# ifdef RT_OS_LINUX
     2046    uint64_t const cbFileMax = RT_MIN(cbFile, UINT32_MAX - PAGE_OFFSET_MASK);
     2047# else
     2048    uint64_t const cbFileMax = RT_MIN(cbFile, SSIZE_MAX - PAGE_OFFSET_MASK);
     2049# endif
     2050    signal(SIGPIPE, SIG_IGN);
     2051
     2052    /*
     2053     * Allocate a buffer.
     2054     */
     2055    FSPERFSENDFILEARGS Args;
     2056    Args.cbBuf = _16M;
     2057    Args.pbBuf = (uint8_t *)RTMemAlloc(Args.cbBuf);
     2058    while (!Args.pbBuf)
     2059    {
     2060        Args.cbBuf /= 8;
     2061        RTTESTI_CHECK_RETV(Args.cbBuf >= _64K);
     2062        Args.pbBuf = (uint8_t *)RTMemAlloc(Args.cbBuf);
     2063    }
     2064
     2065    /*
     2066     * First iteration with default buffer content.
     2067     */
     2068    fsPerfSendFileOne(&Args, hFile1, 0, cbFileMax, cbFileMax, 0xf6, true /*fCheckBuf*/, __LINE__);
     2069    if (cbFileMax == cbFile)
     2070        fsPerfSendFileOne(&Args, hFile1, 63, cbFileMax, cbFileMax - 63, 0xf6, true /*fCheckBuf*/, __LINE__);
     2071    else
     2072        fsPerfSendFileOne(&Args, hFile1, 63, cbFileMax - 63, cbFileMax - 63, 0xf6, true /*fCheckBuf*/, __LINE__);
     2073
     2074    /*
     2075     * Write a block using the regular API and then send it, checking that
     2076     * the any caching that sendfile does is correctly updated.
     2077     */
     2078    uint8_t bFiller = 0xf6;
     2079    size_t cbToSend = RT_MIN(cbFileMax, Args.cbBuf);
     2080    do
     2081    {
     2082        fsPerfSendFileOne(&Args, hFile1, 0, cbToSend, cbToSend, bFiller, true /*fCheckBuf*/, __LINE__); /* prime cache */
     2083
     2084        bFiller += 1;
     2085        fsPerfFillWriteBuf(0, Args.pbBuf, cbToSend, bFiller);
     2086        RTTESTI_CHECK_RC(RTFileWriteAt(hFile1, 0, Args.pbBuf, cbToSend, NULL), VINF_SUCCESS);
     2087
     2088        fsPerfSendFileOne(&Args, hFile1, 0, cbToSend, cbToSend, bFiller, true /*fCheckBuf*/, __LINE__);
     2089
     2090        cbToSend /= 2;
     2091    } while (cbToSend >= PAGE_SIZE && ((unsigned)bFiller - 0xf7U) < 64);
     2092
     2093    /*
     2094     * Restore buffer content
     2095     */
     2096    bFiller = 0xf6;
     2097    fsPerfFillWriteBuf(0, Args.pbBuf, Args.cbBuf, bFiller);
     2098    RTTESTI_CHECK_RC(RTFileWriteAt(hFile1, 0, Args.pbBuf, Args.cbBuf, NULL), VINF_SUCCESS);
     2099
     2100    /*
     2101     * Do 128 random sends.
     2102     */
     2103    uint64_t const cbSmall = RT_MIN(_256K, cbFileMax / 16);
     2104    for (uint32_t iTest = 0; iTest < 128; iTest++)
     2105    {
     2106        cbToSend                     = (size_t)RTRandU64Ex(1, iTest < 64 ? cbSmall : cbFileMax);
     2107        uint64_t const offToSendFrom = RTRandU64Ex(0, cbFile - 1);
     2108        uint64_t const cbSent        = offToSendFrom + cbToSend <= cbFile ? cbToSend : cbFile - offToSendFrom;
     2109
     2110        fsPerfSendFileOne(&Args, hFile1, offToSendFrom, cbToSend, cbSent, bFiller, true /*fCheckBuf*/, __LINE__);
     2111    }
     2112
     2113    /*
     2114     * Benchmark it.
     2115     */
     2116    uint32_t cIterations = 0;
     2117    uint64_t nsElapsed   = 0;
     2118    for (;;)
     2119    {
     2120        uint64_t cNsThis = fsPerfSendFileOne(&Args, hFile1, 0, cbFileMax, cbFileMax, 0xf6, false /*fCheckBuf*/, __LINE__);
     2121        nsElapsed += cNsThis;
     2122        cIterations++;
     2123        if (!cNsThis || nsElapsed >= g_nsTestRun)
     2124            break;
     2125    }
     2126    uint64_t cbTotal = cbFileMax * cIterations;
     2127    RTTestIValue("latency",    nsElapsed / cIterations,                                 RTTESTUNIT_NS_PER_CALL);
     2128    RTTestIValue("throughput", (uint64_t)(cbTotal / ((double)nsElapsed / RT_NS_1SEC)),  RTTESTUNIT_BYTES_PER_SEC);
     2129    RTTestIValue("calls",      cIterations,                                             RTTESTUNIT_CALLS);
     2130    RTTestIValue("bytes",      cbTotal,                                                 RTTESTUNIT_BYTES);
     2131    if (g_fShowDuration)
     2132        RTTestIValue("duration", nsElapsed,                                             RTTESTUNIT_NS);
     2133
     2134    /*
     2135     * Cleanup.
     2136     */
     2137    RTMemFree(Args.pbBuf);
     2138}
     2139
     2140#endif /* RT_OS_LINUX */
    19122141
    19132142/** For fsPerfIoRead and fsPerfIoWrite. */
     
    29783207
    29793208        /*
    2980          * Obsever how regular writes affects a read-only or readwrite mapping.
     3209         * Observe how regular writes affects a read-only or readwrite mapping.
    29813210         * These should ideally be immediately visible in the mapping, at least
    29823211         * when not performed thru an no-cache handle.
     
    32163445                fsPerfIoReadBlockSize(hFile1, cbFile, g_acbIoBlocks[i]);
    32173446
     3447#ifdef RT_OS_LINUX
     3448        if (g_fSendFile)
     3449            fsPerfSendFile(hFile1, cbFile);
     3450#endif
     3451#ifdef RT_OS_LINUX
     3452        //if (g_fSplice)
     3453        //    fsPerfSpliceOut(hFile1, cbFile);
     3454#endif
     3455
    32183456        if (g_fMMap)
    32193457            fsPerfMMap(hFile1, hFileNoCache, cbFile);
     
    33633601         * On linux we can also use sendfile between two files, except for 2.5.x to 2.6.33.
    33643602         */
     3603        uint64_t const cbFileMax = RT_MIN(cbFile, UINT32_C(0x7ffff000));
    33653604        char szRelease[64];
    33663605        RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szRelease, sizeof(szRelease));
     
    33793618                RTTestIFailed("sendfile(file,file,NULL,%#zx) failed (%zd): %d (%Rrc)",
    33803619                              cbFile, cbSent, errno, RTErrConvertFromErrno(errno));
    3381             else if ((size_t)cbSent != cbFile)
     3620            else if ((size_t)cbSent != cbFileMax)
    33823621                RTTestIFailed("sendfile(file,file,NULL,%#zx) returned %#zx, expected %#zx (diff %zd)",
    3383                               cbFile, cbSent, cbFile, cbSent - cbFile);
     3622                              cbFile, cbSent, cbFileMax, cbSent - cbFileMax);
    33843623            RTTESTI_CHECK_RC(RTFileClose(hFile2), VINF_SUCCESS);
    33853624            RTTESTI_CHECK_RC(RTFileClose(hFile1), VINF_SUCCESS);
     
    33873626
    33883627            /* Try copy a little bit too much: */
    3389             hFile1 = NIL_RTFILE;
    3390             RTTESTI_CHECK_RC(RTFileOpen(&hFile1, g_szDir, RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_READ), VINF_SUCCESS);
    3391             RTFileDelete(g_szDir2);
    3392             hFile2 = NIL_RTFILE;
    3393             RTTESTI_CHECK_RC(RTFileOpen(&hFile2, g_szDir2, RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_WRITE), VINF_SUCCESS);
    3394             size_t cbToCopy = cbFile + RTRandU32Ex(1, _64M);
    3395             cbSent = sendfile((int)RTFileToNative(hFile2), (int)RTFileToNative(hFile1), NULL, cbToCopy);
    3396             if (cbSent < 0)
    3397                 RTTestIFailed("sendfile(file,file,NULL,%#zx) failed (%zd): %d (%Rrc)",
    3398                               cbToCopy, cbSent, errno, RTErrConvertFromErrno(errno));
    3399             else if ((size_t)cbSent != cbFile)
    3400                 RTTestIFailed("sendfile(file,file,NULL,%#zx) returned %#zx, expected %#zx (diff %zd)",
    3401                               cbToCopy, cbSent, cbFile, cbSent - cbFile);
    3402             RTTESTI_CHECK_RC(RTFileClose(hFile2), VINF_SUCCESS);
    3403             RTTESTI_CHECK_RC(RTFileCompare(g_szDir, g_szDir2), VINF_SUCCESS);
     3628            if (cbFile == cbFileMax)
     3629            {
     3630                hFile1 = NIL_RTFILE;
     3631                RTTESTI_CHECK_RC(RTFileOpen(&hFile1, g_szDir, RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_READ), VINF_SUCCESS);
     3632                RTFileDelete(g_szDir2);
     3633                hFile2 = NIL_RTFILE;
     3634                RTTESTI_CHECK_RC(RTFileOpen(&hFile2, g_szDir2, RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_WRITE), VINF_SUCCESS);
     3635                size_t cbToCopy = cbFile + RTRandU32Ex(1, _64M);
     3636                cbSent = sendfile((int)RTFileToNative(hFile2), (int)RTFileToNative(hFile1), NULL, cbToCopy);
     3637                if (cbSent < 0)
     3638                    RTTestIFailed("sendfile(file,file,NULL,%#zx) failed (%zd): %d (%Rrc)",
     3639                                  cbToCopy, cbSent, errno, RTErrConvertFromErrno(errno));
     3640                else if ((size_t)cbSent != cbFile)
     3641                    RTTestIFailed("sendfile(file,file,NULL,%#zx) returned %#zx, expected %#zx (diff %zd)",
     3642                                  cbToCopy, cbSent, cbFile, cbSent - cbFile);
     3643                RTTESTI_CHECK_RC(RTFileClose(hFile2), VINF_SUCCESS);
     3644                RTTESTI_CHECK_RC(RTFileCompare(g_szDir, g_szDir2), VINF_SUCCESS);
     3645            }
    34043646
    34053647            /* Do partial copy: */
     
    34083650            for (uint32_t i = 0; i < 64; i++)
    34093651            {
    3410                 cbToCopy = RTRandU32Ex(0, cbFile - 1);
    3411                 uint32_t const offFile  = RTRandU32Ex(1, (uint64_t)RT_MIN(cbFile - cbToCopy, UINT32_MAX));
     3652                size_t cbToCopy = RTRandU32Ex(0, cbFileMax - 1);
     3653                uint32_t const offFile  = RTRandU32Ex(1, (uint64_t)RT_MIN(cbFileMax - cbToCopy, UINT32_MAX));
    34123654                RTTESTI_CHECK_RC_BREAK(RTFileSeek(hFile2, offFile, RTFILE_SEEK_BEGIN, NULL), VINF_SUCCESS);
    34133655                loff_t offFile2 = offFile;
     
    35103752            hFile2 = NIL_RTFILE;
    35113753            RTTESTI_CHECK_RC(RTFileOpen(&hFile2, g_szDir2, RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_WRITE), VINF_SUCCESS);
    3512             PROFILE_COPY_FN("sendfile/overwrite", fsPerfCopyWorkerSendFile(hFile1, hFile2, cbFile));
     3754            PROFILE_COPY_FN("sendfile/overwrite", fsPerfCopyWorkerSendFile(hFile1, hFile2, cbFileMax));
    35133755            RTTESTI_CHECK_RC(RTFileClose(hFile2), VINF_SUCCESS);
    35143756            RTTESTI_CHECK_RC(RTFileClose(hFile1), VINF_SUCCESS);
    35153757        }
    35163758#endif
    3517 
    35183759    }
    35193760
     
    36823923                g_fReadTests = true;
    36833924                g_fReadPerf  = true;
     3925                g_fSendFile  = true;
    36843926                g_fWriteTests= true;
    36853927                g_fWritePerf = true;
     
    37083950                g_fReadTests = false;
    37093951                g_fReadPerf  = false;
     3952                g_fSendFile  = false;
    37103953                g_fWriteTests= false;
    37113954                g_fWritePerf = false;
     
    37353978            CASE_OPT(ReadTests);
    37363979            CASE_OPT(ReadPerf);
     3980            CASE_OPT(SendFile);
    37373981            CASE_OPT(WriteTests);
    37383982            CASE_OPT(WritePerf);
     
    38934137                if (g_fChSize)
    38944138                    fsPerfChSize();
    3895                 if (g_fReadPerf || g_fReadTests || g_fWritePerf || g_fWriteTests || g_fSeek || g_fFSync || g_fMMap)
     4139                if (   g_fReadPerf || g_fReadTests || g_fSendFile || g_fWritePerf || g_fWriteTests
     4140                    || g_fSeek || g_fFSync || g_fMMap)
    38964141                    fsPerfIo();
    38974142                if (g_fCopy)
Note: See TracChangeset for help on using the changeset viewer.

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