VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTFileAio.cpp@ 102792

Last change on this file since 102792 was 99775, checked in by vboxsync, 17 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.1 KB
Line 
1/* $Id: tstRTFileAio.cpp 99775 2023-05-12 12:21:58Z vboxsync $ */
2/** @file
3 * IPRT Testcase - File Async I/O.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/file.h>
42
43#include <iprt/err.h>
44#include <iprt/mem.h>
45#include <iprt/param.h>
46#include <iprt/string.h>
47#include <iprt/test.h>
48
49
50/*********************************************************************************************************************************
51* Defined Constants And Macros *
52*********************************************************************************************************************************/
53/** @todo make configurable through cmd line. */
54#define TSTFILEAIO_MAX_REQS_IN_FLIGHT 64
55#define TSTFILEAIO_BUFFER_SIZE (64*_1K)
56
57
58/*********************************************************************************************************************************
59* Global Variables *
60*********************************************************************************************************************************/
61static RTTEST g_hTest = NIL_RTTEST;
62
63
64static void tstFileAioTestReadWriteBasic(RTFILE File, bool fWrite, void *pvTestBuf,
65 size_t cbTestBuf, size_t cbTestFile, uint32_t cMaxReqsInFlight)
66{
67 /* Allocate request array. */
68 RTFILEAIOREQ *paReqs;
69 paReqs = (PRTFILEAIOREQ)RTTestGuardedAllocHead(g_hTest, cMaxReqsInFlight * sizeof(RTFILEAIOREQ));
70 RTTESTI_CHECK_RETV(paReqs);
71 RT_BZERO(paReqs, cMaxReqsInFlight * sizeof(RTFILEAIOREQ));
72
73 /* Allocate array holding pointer to data buffers. */
74 void **papvBuf = (void **)RTTestGuardedAllocHead(g_hTest, cMaxReqsInFlight * sizeof(void *));
75 RTTESTI_CHECK_RETV(papvBuf);
76
77 /* Allocate the buffers*/
78 for (unsigned i = 0; i < cMaxReqsInFlight; i++)
79 {
80 RTTESTI_CHECK_RC_OK_RETV(RTTestGuardedAlloc(g_hTest, cbTestBuf, PAGE_SIZE, true /*fHead*/, &papvBuf[i]));
81 if (fWrite)
82 memcpy(papvBuf[i], pvTestBuf, cbTestBuf);
83 if (fWrite)
84 memcpy(papvBuf[i], pvTestBuf, cbTestBuf);
85 else
86 RT_BZERO(papvBuf[i], cbTestBuf);
87 }
88
89 /* Allocate array holding completed requests. */
90 RTFILEAIOREQ *paReqsCompleted;
91 paReqsCompleted = (PRTFILEAIOREQ)RTTestGuardedAllocHead(g_hTest, cMaxReqsInFlight * sizeof(RTFILEAIOREQ));
92 RTTESTI_CHECK_RETV(paReqsCompleted);
93 RT_BZERO(paReqsCompleted, cMaxReqsInFlight * sizeof(RTFILEAIOREQ));
94
95 /* Create a context and associate the file handle with it. */
96 RTFILEAIOCTX hAioContext;
97 RTTESTI_CHECK_RC_RETV(RTFileAioCtxCreate(&hAioContext, cMaxReqsInFlight, 0 /* fFlags */), VINF_SUCCESS);
98 RTTESTI_CHECK_RC_RETV(RTFileAioCtxAssociateWithFile(hAioContext, File), VINF_SUCCESS);
99
100 /* Initialize requests. */
101 for (unsigned i = 0; i < cMaxReqsInFlight; i++)
102 RTFileAioReqCreate(&paReqs[i]);
103
104 RTFOFF off = 0;
105 int cRuns = 0;
106 uint64_t NanoTS = RTTimeNanoTS();
107 size_t cbLeft = cbTestFile;
108 while (cbLeft)
109 {
110 int rc;
111 int cReqs = 0;
112 for (unsigned i = 0; i < cMaxReqsInFlight; i++)
113 {
114 size_t cbTransfer = cbLeft < cbTestBuf ? cbLeft : cbTestBuf;
115 if (!cbTransfer)
116 break;
117
118 if (fWrite)
119 rc = RTFileAioReqPrepareWrite(paReqs[i], File, off, papvBuf[i],
120 cbTransfer, papvBuf[i]);
121 else
122 rc = RTFileAioReqPrepareRead(paReqs[i], File, off, papvBuf[i],
123 cbTransfer, papvBuf[i]);
124 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
125
126 cbLeft -= cbTransfer;
127 off += cbTransfer;
128 cReqs++;
129 }
130
131 rc = RTFileAioCtxSubmit(hAioContext, paReqs, cReqs);
132 RTTESTI_CHECK_MSG(rc == VINF_SUCCESS, ("Failed to submit tasks after %d runs. rc=%Rrc\n", cRuns, rc));
133 if (rc != VINF_SUCCESS)
134 break;
135
136 /* Wait */
137 uint32_t cCompleted = 0;
138 RTTESTI_CHECK_RC(rc = RTFileAioCtxWait(hAioContext, cReqs, RT_INDEFINITE_WAIT,
139 paReqsCompleted, cMaxReqsInFlight, &cCompleted),
140 VINF_SUCCESS);
141 if (rc != VINF_SUCCESS)
142 break;
143
144 if (!fWrite)
145 {
146 for (uint32_t i = 0; i < cCompleted; i++)
147 {
148 /* Compare that we read the right stuff. */
149 void *pvBuf = RTFileAioReqGetUser(paReqsCompleted[i]);
150 RTTESTI_CHECK(pvBuf);
151
152 size_t cbTransfered;
153 RTTESTI_CHECK_RC(rc = RTFileAioReqGetRC(paReqsCompleted[i], &cbTransfered), VINF_SUCCESS);
154 if (rc != VINF_SUCCESS)
155 break;
156 RTTESTI_CHECK_MSG(cbTransfered == cbTestBuf, ("cbTransfered=%zd\n", cbTransfered));
157 RTTESTI_CHECK_RC_OK(rc = (memcmp(pvBuf, pvTestBuf, cbTestBuf) == 0 ? VINF_SUCCESS : VERR_BAD_EXE_FORMAT));
158 if (rc != VINF_SUCCESS)
159 break;
160 memset(pvBuf, 0, cbTestBuf);
161 }
162 }
163 cRuns++;
164 if (RT_FAILURE(rc))
165 break;
166 }
167
168 NanoTS = RTTimeNanoTS() - NanoTS;
169 uint64_t SpeedKBs = (uint64_t)((double)cbTestFile / ((double)NanoTS / 1000000000.0) / 1024);
170 RTTestValue(g_hTest, "Throughput", SpeedKBs, RTTESTUNIT_KILOBYTES_PER_SEC);
171
172 /* cleanup */
173 for (unsigned i = 0; i < cMaxReqsInFlight; i++)
174 RTTestGuardedFree(g_hTest, papvBuf[i]);
175 RTTestGuardedFree(g_hTest, papvBuf);
176 for (unsigned i = 0; i < cMaxReqsInFlight; i++)
177 RTTESTI_CHECK_RC(RTFileAioReqDestroy(paReqs[i]), VINF_SUCCESS);
178 RTTESTI_CHECK_RC(RTFileAioCtxDestroy(hAioContext), VINF_SUCCESS);
179 RTTestGuardedFree(g_hTest, paReqs);
180}
181
182int main()
183{
184 int rc = RTTestInitAndCreate("tstRTFileAio", &g_hTest);
185 if (rc)
186 return rc;
187
188 /* Check if the API is available. */
189 RTTestSub(g_hTest, "RTFileAioGetLimits");
190 RTFILEAIOLIMITS AioLimits;
191 RT_ZERO(AioLimits);
192 RTTESTI_CHECK_RC(rc = RTFileAioGetLimits(&AioLimits), VINF_SUCCESS);
193 if (RT_SUCCESS(rc))
194 {
195 RTTestSub(g_hTest, "Write");
196 RTFILE hFile;
197 RTFSTYPE enmType;
198 bool fAsyncMayFail = false;
199 rc = RTFsQueryType("tstFileAio#1.tst", &enmType);
200 if ( RT_SUCCESS(rc)
201 && enmType == RTFSTYPE_TMPFS)
202 fAsyncMayFail = true;
203 rc = RTFileOpen(&hFile, "tstFileAio#1.tst",
204 RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_ASYNC_IO);
205 RTTESTI_CHECK( rc == VINF_SUCCESS
206 || ((rc == VERR_ACCESS_DENIED || rc == VERR_INVALID_PARAMETER) && fAsyncMayFail));
207 if (RT_SUCCESS(rc))
208 {
209 uint8_t *pbTestBuf = (uint8_t *)RTTestGuardedAllocTail(g_hTest, TSTFILEAIO_BUFFER_SIZE);
210 for (unsigned i = 0; i < TSTFILEAIO_BUFFER_SIZE; i++)
211 pbTestBuf[i] = i % 256;
212
213 uint32_t cReqsMax = AioLimits.cReqsOutstandingMax < TSTFILEAIO_MAX_REQS_IN_FLIGHT
214 ? AioLimits.cReqsOutstandingMax
215 : TSTFILEAIO_MAX_REQS_IN_FLIGHT;
216
217 /* Basic write test. */
218 RTTestIPrintf(RTTESTLVL_ALWAYS, "Preparing test file, this can take some time and needs quite a bit of harddisk space...\n");
219 tstFileAioTestReadWriteBasic(hFile, true /*fWrite*/, pbTestBuf, TSTFILEAIO_BUFFER_SIZE, 100*_1M, cReqsMax);
220
221 /* Reopen the file before doing the next test. */
222 RTTESTI_CHECK_RC(RTFileClose(hFile), VINF_SUCCESS);
223 if (RTTestErrorCount(g_hTest) == 0)
224 {
225 RTTestSub(g_hTest, "Read/Write");
226 RTTESTI_CHECK_RC(rc = RTFileOpen(&hFile, "tstFileAio#1.tst",
227 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_ASYNC_IO),
228 VINF_SUCCESS);
229 if (RT_SUCCESS(rc))
230 {
231 tstFileAioTestReadWriteBasic(hFile, false /*fWrite*/, pbTestBuf, TSTFILEAIO_BUFFER_SIZE, 100*_1M, cReqsMax);
232 RTFileClose(hFile);
233 }
234 }
235
236 /* Cleanup */
237 RTFileDelete("tstFileAio#1.tst");
238 }
239 else
240 RTTestSkipped(g_hTest, "rc=%Rrc", rc);
241 }
242
243 /*
244 * Summary
245 */
246 return RTTestSummaryAndDestroy(g_hTest);
247}
248
Note: See TracBrowser for help on using the repository browser.

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