Changeset 77925 in vbox for trunk/src/VBox/ValidationKit/utils/fs
- Timestamp:
- Mar 27, 2019 8:54:22 PM (6 years ago)
- svn:sync-xref-src-repo-rev:
- 129638
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/utils/fs/FsPerf.cpp
r77908 r77925 52 52 #include <iprt/stream.h> 53 53 #include <iprt/system.h> 54 #include <iprt/tcp.h> 54 55 #include <iprt/test.h> 55 56 #include <iprt/time.h> … … 68 69 # include <sys/uio.h> 69 70 # endif 71 # include <sys/socket.h> 72 # include <signal.h> 70 73 # ifdef RT_OS_LINUX 71 74 # include <sys/sendfile.h> … … 273 276 kCmdOpt_ReadTests, 274 277 kCmdOpt_NoReadTests, 278 kCmdOpt_SendFile, 279 kCmdOpt_NoSendFile, 275 280 kCmdOpt_WritePerf, 276 281 kCmdOpt_NoWritePerf, … … 355 360 { "--read-perf", kCmdOpt_ReadPerf, RTGETOPT_REQ_NOTHING }, 356 361 { "--no-read-perf", kCmdOpt_NoReadPerf, RTGETOPT_REQ_NOTHING }, 362 { "--sendfile", kCmdOpt_SendFile, RTGETOPT_REQ_NOTHING }, 363 { "--no-sendfile", kCmdOpt_NoSendFile, RTGETOPT_REQ_NOTHING }, 357 364 { "--write-tests", kCmdOpt_WriteTests, RTGETOPT_REQ_NOTHING }, 358 365 { "--no-write-tests", kCmdOpt_NoWriteTests, RTGETOPT_REQ_NOTHING }, … … 417 424 static bool g_fReadTests = true; 418 425 static bool g_fReadPerf = true; 426 static bool g_fSendFile = true; 419 427 static bool g_fWriteTests= true; 420 428 static bool g_fWritePerf = true; … … 1910 1918 } 1911 1919 1920 #ifdef RT_OS_LINUX 1921 /** 1922 * Send file thread arguments. 1923 */ 1924 typedef 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. */ 1938 static 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 1976 static 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 2042 static 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 */ 1912 2141 1913 2142 /** For fsPerfIoRead and fsPerfIoWrite. */ … … 2978 3207 2979 3208 /* 2980 * Obse verhow regular writes affects a read-only or readwrite mapping.3209 * Observe how regular writes affects a read-only or readwrite mapping. 2981 3210 * These should ideally be immediately visible in the mapping, at least 2982 3211 * when not performed thru an no-cache handle. … … 3216 3445 fsPerfIoReadBlockSize(hFile1, cbFile, g_acbIoBlocks[i]); 3217 3446 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 3218 3456 if (g_fMMap) 3219 3457 fsPerfMMap(hFile1, hFileNoCache, cbFile); … … 3363 3601 * On linux we can also use sendfile between two files, except for 2.5.x to 2.6.33. 3364 3602 */ 3603 uint64_t const cbFileMax = RT_MIN(cbFile, UINT32_C(0x7ffff000)); 3365 3604 char szRelease[64]; 3366 3605 RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szRelease, sizeof(szRelease)); … … 3379 3618 RTTestIFailed("sendfile(file,file,NULL,%#zx) failed (%zd): %d (%Rrc)", 3380 3619 cbFile, cbSent, errno, RTErrConvertFromErrno(errno)); 3381 else if ((size_t)cbSent != cbFile )3620 else if ((size_t)cbSent != cbFileMax) 3382 3621 RTTestIFailed("sendfile(file,file,NULL,%#zx) returned %#zx, expected %#zx (diff %zd)", 3383 cbFile, cbSent, cbFile , cbSent - cbFile);3622 cbFile, cbSent, cbFileMax, cbSent - cbFileMax); 3384 3623 RTTESTI_CHECK_RC(RTFileClose(hFile2), VINF_SUCCESS); 3385 3624 RTTESTI_CHECK_RC(RTFileClose(hFile1), VINF_SUCCESS); … … 3387 3626 3388 3627 /* 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 } 3404 3646 3405 3647 /* Do partial copy: */ … … 3408 3650 for (uint32_t i = 0; i < 64; i++) 3409 3651 { 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)); 3412 3654 RTTESTI_CHECK_RC_BREAK(RTFileSeek(hFile2, offFile, RTFILE_SEEK_BEGIN, NULL), VINF_SUCCESS); 3413 3655 loff_t offFile2 = offFile; … … 3510 3752 hFile2 = NIL_RTFILE; 3511 3753 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)); 3513 3755 RTTESTI_CHECK_RC(RTFileClose(hFile2), VINF_SUCCESS); 3514 3756 RTTESTI_CHECK_RC(RTFileClose(hFile1), VINF_SUCCESS); 3515 3757 } 3516 3758 #endif 3517 3518 3759 } 3519 3760 … … 3682 3923 g_fReadTests = true; 3683 3924 g_fReadPerf = true; 3925 g_fSendFile = true; 3684 3926 g_fWriteTests= true; 3685 3927 g_fWritePerf = true; … … 3708 3950 g_fReadTests = false; 3709 3951 g_fReadPerf = false; 3952 g_fSendFile = false; 3710 3953 g_fWriteTests= false; 3711 3954 g_fWritePerf = false; … … 3735 3978 CASE_OPT(ReadTests); 3736 3979 CASE_OPT(ReadPerf); 3980 CASE_OPT(SendFile); 3737 3981 CASE_OPT(WriteTests); 3738 3982 CASE_OPT(WritePerf); … … 3893 4137 if (g_fChSize) 3894 4138 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) 3896 4141 fsPerfIo(); 3897 4142 if (g_fCopy)
Note:
See TracChangeset
for help on using the changeset viewer.