VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/storage/IoPerf.cpp@ 80032

Last change on this file since 80032 was 80032, checked in by vboxsync, 5 years ago

ValidationKit/utils/IoPerf: Start on a I/O benchmarking/testing utility for our automated tests using the new I/O queue API [build fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.5 KB
Line 
1/* $Id: IoPerf.cpp 80032 2019-07-28 22:10:14Z vboxsync $ */
2/** @file
3 * IoPerf - Storage I/O Performance Benchmark.
4 */
5
6/*
7 * Copyright (C) 2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/asm.h>
32#include <iprt/assert.h>
33#include <iprt/err.h>
34#include <iprt/dir.h>
35#include <iprt/file.h>
36#include <iprt/getopt.h>
37#include <iprt/initterm.h>
38#include <iprt/ioqueue.h>
39#include <iprt/list.h>
40#include <iprt/mem.h>
41#include <iprt/message.h>
42#include <iprt/param.h>
43#include <iprt/path.h>
44#include <iprt/process.h>
45#include <iprt/rand.h>
46#include <iprt/string.h>
47#include <iprt/stream.h>
48#include <iprt/system.h>
49#include <iprt/test.h>
50#include <iprt/time.h>
51#include <iprt/thread.h>
52#include <iprt/zero.h>
53
54
55/*********************************************************************************************************************************
56* Defined Constants And Macros *
57*********************************************************************************************************************************/
58
59
60/*********************************************************************************************************************************
61* Structures and Typedefs *
62*********************************************************************************************************************************/
63
64/** Forward declaration of the master. */
65typedef struct IOPERFMASTER *PIOPERFMASTER;
66
67/**
68 * I/O perf supported tests.
69 */
70typedef enum IOPERFTEST
71{
72 /** Invalid test handle. */
73 IOPERFTEST_INVALID = 0,
74 /** The test was disabled. */
75 IOPERFTEST_DISABLED,
76 IOPERFTEST_FIRST_WRITE,
77 IOPERFTEST_SEQ_READ,
78 IOPERFTEST_SEQ_WRITE,
79 IOPERFTEST_RND_READ,
80 IOPERFTEST_RND_WRITE,
81 IOPERFTEST_REV_READ,
82 IOPERFTEST_REV_WRITE,
83 IOPERFTEST_SEQ_READWRITE,
84 IOPERFTEST_RND_READWRITE,
85 /** Special shutdown test which lets the workers exit, must be LAST. */
86 IOPERFTEST_SHUTDOWN,
87 IOPERFTEST_32BIT_HACK = 0x7fffffff
88} IOPERFTEST;
89
90
91/**
92 * I/O perf test set preparation method.
93 */
94typedef enum IOPERFTESTSETPREP
95{
96 IOPERFTESTSETPREP_INVALID = 0,
97 /** Just create the file and don't set any sizes. */
98 IOPERFTESTSETPREP_JUST_CREATE,
99 /** Standard RTFileSetSize() call which might create a sparse file. */
100 IOPERFTESTSETPREP_SET_SZ,
101 /** Uses RTFileSetAllocationSize() to ensure storage is allocated for the file. */
102 IOPERFTESTSETPREP_SET_ALLOC_SZ,
103 /** 32bit hack. */
104 IOPERFTESTSETPREP_32BIT_HACK = 0x7fffffff
105} IOPERFTESTSETPREP;
106
107
108/**
109 * I/O perf job data.
110 */
111typedef struct IOPERFJOB
112{
113 /** Pointer to the master if multiple jobs are running. */
114 PIOPERFMASTER pMaster;
115 /** Job ID. */
116 uint32_t idJob;
117 /** The test this job is executing. */
118 volatile IOPERFTEST enmTest;
119 /** The thread executing the job. */
120 RTTHREAD hThread;
121 /** The I/O queue for the job. */
122 RTIOQUEUE hIoQueue;
123 /** The file path used. */
124 char *pszFilename;
125 /** The handle to use for the I/O queue. */
126 RTHANDLE Hnd;
127 /** Multi event semaphore to synchronise with other jobs. */
128 RTSEMEVENTMULTI hSemEvtMultiRendezvous;
129 /** The test set size. */
130 uint64_t cbTestSet;
131 /** Size of one I/O block. */
132 size_t cbIoBlock;
133 /** Maximum number of requests to queue. */
134 uint32_t cReqsMax;
135 /** Test dependent data. */
136 union
137 {
138 uint32_t uDummy;
139 } Tst;
140} IOPERFJOB;
141/** Pointer to an I/O Perf job. */
142typedef IOPERFJOB *PIOPERFJOB;
143
144
145/**
146 * I/O perf master instance coordinating the job execution.
147 */
148typedef struct IOPERFMASTER
149{
150 /** Event semaphore. */
151 /** Number of jobs. */
152 uint32_t cJobs;
153 /** Job instances, variable in size. */
154 IOPERFJOB aJobs[1];
155} IOPERFMASTER;
156
157
158enum
159{
160 kCmdOpt_First = 128,
161
162 kCmdOpt_FirstWrite = kCmdOpt_First,
163 kCmdOpt_NoFirstWrite,
164 kCmdOpt_SeqRead,
165 kCmdOpt_NoSeqRead,
166 kCmdOpt_SeqWrite,
167 kCmdOpt_NoSeqWrite,
168 kCmdOpt_RndRead,
169 kCmdOpt_NoRndRead,
170 kCmdOpt_RndWrite,
171 kCmdOpt_NoRndWrite,
172 kCmdOpt_RevRead,
173 kCmdOpt_NoRevRead,
174 kCmdOpt_RevWrite,
175 kCmdOpt_NoRevWrite,
176 kCmdOpt_SeqReadWrite,
177 kCmdOpt_NoSeqReadWrite,
178 kCmdOpt_RndReadWrite,
179 kCmdOpt_NoRndReadWrite,
180
181 kCmdOpt_End
182};
183
184
185/*********************************************************************************************************************************
186* Global Variables *
187*********************************************************************************************************************************/
188/** Command line parameters */
189static const RTGETOPTDEF g_aCmdOptions[] =
190{
191 { "--dir", 'd', RTGETOPT_REQ_STRING },
192 { "--relative-dir", 'r', RTGETOPT_REQ_NOTHING },
193 { "--enable-all", 'e', RTGETOPT_REQ_NOTHING },
194 { "--disable-all", 'z', RTGETOPT_REQ_NOTHING },
195
196 { "--jobs", 'j', RTGETOPT_REQ_UINT32 },
197 { "--io-engine", 'i', RTGETOPT_REQ_STRING },
198 { "--test-set-size", 's', RTGETOPT_REQ_UINT64 },
199 { "--block-size", 'b', RTGETOPT_REQ_UINT32 },
200
201 { "--first-write", kCmdOpt_FirstWrite, RTGETOPT_REQ_NOTHING },
202 { "--no-first-write", kCmdOpt_NoFirstWrite, RTGETOPT_REQ_NOTHING },
203 { "--seq-read", kCmdOpt_SeqRead, RTGETOPT_REQ_NOTHING },
204 { "--no-seq-read", kCmdOpt_NoSeqRead, RTGETOPT_REQ_NOTHING },
205 { "--seq-write", kCmdOpt_SeqWrite, RTGETOPT_REQ_NOTHING },
206 { "--no-seq-write", kCmdOpt_NoSeqWrite, RTGETOPT_REQ_NOTHING },
207 { "--rnd-read", kCmdOpt_RndRead, RTGETOPT_REQ_NOTHING },
208 { "--no-rnd-read", kCmdOpt_NoRndRead, RTGETOPT_REQ_NOTHING },
209 { "--rnd-write", kCmdOpt_RndWrite, RTGETOPT_REQ_NOTHING },
210 { "--no-rnd-write", kCmdOpt_NoRndWrite, RTGETOPT_REQ_NOTHING },
211 { "--rev-read", kCmdOpt_RevRead, RTGETOPT_REQ_NOTHING },
212 { "--no-rev-read", kCmdOpt_NoRevRead, RTGETOPT_REQ_NOTHING },
213 { "--rev-write", kCmdOpt_RevWrite, RTGETOPT_REQ_NOTHING },
214 { "--no-rev-write", kCmdOpt_NoRevWrite, RTGETOPT_REQ_NOTHING },
215 { "--seq-read-write", kCmdOpt_SeqReadWrite, RTGETOPT_REQ_NOTHING },
216 { "--no-seq-read-write", kCmdOpt_NoSeqReadWrite, RTGETOPT_REQ_NOTHING },
217 { "--rnd-read-write", kCmdOpt_RndReadWrite, RTGETOPT_REQ_NOTHING },
218 { "--no-rnd-read-write", kCmdOpt_NoRndReadWrite, RTGETOPT_REQ_NOTHING },
219
220 { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
221 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
222 { "--version", 'V', RTGETOPT_REQ_NOTHING },
223 { "--help", 'h', RTGETOPT_REQ_NOTHING } /* for Usage() */
224};
225
226/** The test handle. */
227static RTTEST g_hTest;
228/** Verbosity level. */
229static uint32_t g_uVerbosity = 0;
230/** Selected I/O engine for the tests, NULL means pick best default one. */
231static const char *g_pszIoEngine = NULL;
232/** Number of jobs to run concurrently. */
233static uint32_t g_cJobs = 1;
234/** Size of each test set (file) in bytes. */
235static uint64_t g_cbTestSet = _2G;
236/** Block size for each request. */
237static size_t g_cbIoBlock = _4K;
238/** Maximum number of concurrent requests for each job. */
239static uint32_t g_cReqsMax = 16;
240
241
242/** @name Configured tests, this must match the IOPERFTEST order.
243 * @{ */
244static IOPERFTEST g_aenmTests[] =
245{
246 IOPERFTEST_DISABLED, /** @< The invalid test value is disabled of course. */
247 IOPERFTEST_DISABLED,
248 IOPERFTEST_FIRST_WRITE,
249 IOPERFTEST_SEQ_READ,
250 IOPERFTEST_SEQ_WRITE,
251 IOPERFTEST_RND_READ,
252 IOPERFTEST_RND_WRITE,
253 IOPERFTEST_REV_READ,
254 IOPERFTEST_REV_WRITE,
255 IOPERFTEST_SEQ_READWRITE,
256 IOPERFTEST_RND_READWRITE,
257 IOPERFTEST_SHUTDOWN
258};
259/** The test index being selected next. */
260static uint32_t g_idxTest = 2;
261/** @} */
262
263/** Set if g_szDir and friends are path relative to CWD rather than absolute. */
264static bool g_fRelativeDir = false;
265/** The length of g_szDir. */
266static size_t g_cchDir;
267
268/** The test directory (absolute). This will always have a trailing slash. */
269static char g_szDir[RTPATH_BIG_MAX];
270
271
272/*********************************************************************************************************************************
273* Tests *
274*********************************************************************************************************************************/
275
276
277/**
278 * Selects the next test to run.
279 *
280 * @return Next test to run.
281 */
282static IOPERFTEST ioPerfTestSelectNext()
283{
284 AssertReturn(g_idxTest < RT_ELEMENTS(g_aenmTests), IOPERFTEST_SHUTDOWN);
285
286 while ( g_idxTest < RT_ELEMENTS(g_aenmTests)
287 && g_aenmTests[g_idxTest] != IOPERFTEST_DISABLED)
288 g_idxTest++;
289
290 AssertReturn(g_idxTest < RT_ELEMENTS(g_aenmTests), IOPERFTEST_SHUTDOWN);
291
292 return g_aenmTests[g_idxTest];
293}
294
295
296/**
297 * Synchronizes with the other jobs and waits for the current test to execute.
298 *
299 * @returns IPRT status.
300 * @param pJob The job data for the current worker.
301 */
302static int ioPerfJobSync(PIOPERFJOB pJob)
303{
304 if (pJob->pMaster)
305 {
306 /* Enter the rendevouzs semaphore. */
307 int rc = VINF_SUCCESS;
308
309 return rc;
310 }
311
312 /* Single threaded run, collect the results from our current test and select the next test. */
313 /** @todo Results and statistics collection. */
314 pJob->enmTest = ioPerfTestSelectNext();
315 return VINF_SUCCESS;
316}
317
318
319/**
320 * Sequential read test.
321 *
322 * @returns IPRT status code.
323 * @param pJob The job data for the current worker.
324 */
325static int ioPerfTestSeqRead(PIOPERFJOB pJob)
326{
327 RT_NOREF(pJob);
328 return VERR_NOT_IMPLEMENTED;
329}
330
331
332/**
333 * I/O perf job main work loop.
334 *
335 * @returns IPRT status code.
336 * @param pJob The job data for the current worker.
337 */
338static int ioPerfJobWorkLoop(PIOPERFJOB pJob)
339{
340 int rc = VINF_SUCCESS;
341 bool fShutdown = false;
342
343 do
344 {
345 /* Synchronize with the other jobs and the master. */
346 rc = ioPerfJobSync(pJob);
347 if (RT_FAILURE(rc))
348 break;
349
350 switch (pJob->enmTest)
351 {
352 case IOPERFTEST_FIRST_WRITE:
353 break;
354 case IOPERFTEST_SEQ_READ:
355 rc = ioPerfTestSeqRead(pJob);
356 break;
357 case IOPERFTEST_SEQ_WRITE:
358 break;
359 case IOPERFTEST_RND_READ:
360 break;
361 case IOPERFTEST_RND_WRITE:
362 break;
363 case IOPERFTEST_REV_READ:
364 break;
365 case IOPERFTEST_REV_WRITE:
366 break;
367 case IOPERFTEST_SEQ_READWRITE:
368 break;
369 case IOPERFTEST_RND_READWRITE:
370 break;
371 case IOPERFTEST_SHUTDOWN:
372 fShutdown = true;
373 break;
374 default:
375 AssertMsgFailed(("Invalid job: %d\n", pJob->enmTest));
376 }
377 } while ( RT_SUCCESS(rc)
378 && !fShutdown);
379
380 return rc;
381}
382
383
384/**
385 * Job thread entry point.
386 */
387static DECLCALLBACK(int) ioPerfJobThread(RTTHREAD hThrdSelf, void *pvUser)
388{
389 RT_NOREF(hThrdSelf);
390
391 PIOPERFJOB pJob = (PIOPERFJOB)pvUser;
392 return ioPerfJobWorkLoop(pJob);
393}
394
395
396/**
397 * Initializes the given job instance.
398 *
399 * @returns IPRT status code.
400 * @param pJob The job to initialize.
401 * @param pMaster The coordination master if any.
402 * @param idJob ID of the job.
403 * @param pszIoEngine I/O queue engine for this job, NULL for best default.
404 * @param pszTestDir The test directory to create the file in - requires a slash a the end.
405 * @param enmPrepMethod Test set preparation method to use.
406 * @param cbTestSet Size of the test set ofr this job.
407 * @param cbIoBlock I/O block size for the given job.
408 * @param cReqsMax Maximum number of concurrent requests for this job.
409 */
410static int ioPerfJobInit(PIOPERFJOB pJob, PIOPERFMASTER pMaster, uint32_t idJob,
411 const char *pszIoEngine, const char *pszTestDir,
412 IOPERFTESTSETPREP enmPrepMethod,
413 uint64_t cbTestSet, size_t cbIoBlock, uint32_t cReqsMax)
414{
415 pJob->pMaster = pMaster;
416 pJob->idJob = idJob;
417 pJob->enmTest = IOPERFTEST_INVALID;
418 pJob->hThread = NIL_RTTHREAD;
419 pJob->Hnd.enmType = RTHANDLETYPE_FILE;
420 pJob->cbTestSet = cbTestSet;
421 pJob->cbIoBlock = cbIoBlock;
422 pJob->cReqsMax = cReqsMax;
423
424 /* Create the file. */
425 int rc = VINF_SUCCESS;
426 pJob->pszFilename = RTStrAPrintf2("%sioperf-%u.file", pszTestDir, idJob);
427 if (RT_LIKELY(pJob->pszFilename))
428 {
429 rc = RTFileOpen(&pJob->Hnd.u.hFile, pJob->pszFilename, RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_READWRITE);
430 if (RT_SUCCESS(rc))
431 {
432 switch (enmPrepMethod)
433 {
434 case IOPERFTESTSETPREP_JUST_CREATE:
435 break;
436 case IOPERFTESTSETPREP_SET_SZ:
437 rc = RTFileSetSize(pJob->Hnd.u.hFile, pJob->cbTestSet);
438 break;
439 case IOPERFTESTSETPREP_SET_ALLOC_SZ:
440 rc = RTFileSetAllocationSize(pJob->Hnd.u.hFile, pJob->cbTestSet, RTFILE_ALLOC_SIZE_F_DEFAULT);
441 break;
442 default:
443 AssertMsgFailed(("Invalid file preparation method: %d\n", enmPrepMethod));
444 }
445
446 if (RT_SUCCESS(rc))
447 {
448 /* Create I/O queue. */
449 PCRTIOQUEUEPROVVTABLE pIoQProv = NULL;
450 if (pszIoEngine)
451 pIoQProv = RTIoQueueProviderGetBestForHndType(RTHANDLETYPE_FILE);
452 else
453 pIoQProv = RTIoQueueProviderGetById(pszIoEngine);
454
455 if (RT_LIKELY(pIoQProv))
456 {
457 rc = RTIoQueueCreate(&pJob->hIoQueue, pIoQProv, 0 /*fFlags*/, cReqsMax, cReqsMax);
458 if (RT_SUCCESS(rc))
459 {
460 /* Spin up the worker thread. */
461 if (pMaster)
462 rc = RTThreadCreateF(&pJob->hThread, ioPerfJobThread, pJob, 0,
463 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "ioperf-%u", idJob);
464
465 if (RT_SUCCESS(rc))
466 return VINF_SUCCESS;
467 }
468 }
469 else
470 rc = VERR_NOT_SUPPORTED;
471 }
472
473 RTFileClose(pJob->Hnd.u.hFile);
474 RTFileDelete(pJob->pszFilename);
475 }
476
477 RTStrFree(pJob->pszFilename);
478 }
479 else
480 rc = VERR_NO_STR_MEMORY;
481
482 return rc;
483}
484
485
486/**
487 * Teardown a job instance and free all associated resources.
488 *
489 * @returns IPRT status code.
490 * @param pJob The job to teardown.
491 */
492static int ioPerfJobTeardown(PIOPERFJOB pJob)
493{
494 int rc = RTThreadWait(pJob->hThread, RT_INDEFINITE_WAIT, NULL); AssertRC(rc); RT_NOREF(rc);
495
496 RTIoQueueDestroy(pJob->hIoQueue);
497 RTFileClose(pJob->Hnd.u.hFile);
498 RTFileDelete(pJob->pszFilename);
499 RTStrFree(pJob->pszFilename);
500 return VINF_SUCCESS;
501}
502
503
504/**
505 * Single job testing entry point.
506 *
507 * @returns IPRT status code.
508 */
509static int ioPerfDoTestSingle(void)
510{
511 IOPERFJOB Job;
512
513 int rc = ioPerfJobInit(&Job, NULL, 0, g_pszIoEngine,
514 g_szDir, IOPERFTESTSETPREP_SET_ALLOC_SZ,
515 g_cbTestSet, g_cbIoBlock, g_cReqsMax);
516 if (RT_SUCCESS(rc))
517 {
518 rc = ioPerfJobWorkLoop(&Job);
519 if (RT_SUCCESS(rc))
520 {
521 rc = ioPerfJobTeardown(&Job);
522 AssertRC(rc); RT_NOREF(rc);
523 }
524 }
525
526 return rc;
527}
528
529
530/**
531 * Multi job testing entry point.
532 *
533 * @returns IPRT status code.
534 */
535static int ioPerfDoTestMulti(void)
536{
537 return VERR_NOT_IMPLEMENTED;
538}
539
540
541/**
542 * Display the usage to @a pStrm.
543 */
544static void Usage(PRTSTREAM pStrm)
545{
546 char szExec[RTPATH_MAX];
547 RTStrmPrintf(pStrm, "usage: %s <-d <testdir>> [options]\n",
548 RTPathFilename(RTProcGetExecutablePath(szExec, sizeof(szExec))));
549 RTStrmPrintf(pStrm, "\n");
550 RTStrmPrintf(pStrm, "options: \n");
551
552 for (unsigned i = 0; i < RT_ELEMENTS(g_aCmdOptions); i++)
553 {
554 char szHelp[80];
555 const char *pszHelp;
556 switch (g_aCmdOptions[i].iShort)
557 {
558 case 'd': pszHelp = "The directory to use for testing. default: CWD/fstestdir"; break;
559 case 'r': pszHelp = "Don't abspath test dir (good for deep dirs). default: disabled"; break;
560 case 'e': pszHelp = "Enables all tests. default: -e"; break;
561 case 'z': pszHelp = "Disables all tests. default: -e"; break;
562 case 'v': pszHelp = "More verbose execution."; break;
563 case 'q': pszHelp = "Quiet execution."; break;
564 case 'h': pszHelp = "Displays this help and exit"; break;
565 case 'V': pszHelp = "Displays the program revision"; break;
566 default:
567 if (g_aCmdOptions[i].iShort >= kCmdOpt_First)
568 {
569 if (RTStrStartsWith(g_aCmdOptions[i].pszLong, "--no-"))
570 RTStrPrintf(szHelp, sizeof(szHelp), "Disables the '%s' test.", g_aCmdOptions[i].pszLong + 5);
571 else
572 RTStrPrintf(szHelp, sizeof(szHelp), "Enables the '%s' test.", g_aCmdOptions[i].pszLong + 2);
573 pszHelp = szHelp;
574 }
575 else
576 pszHelp = "Option undocumented";
577 break;
578 }
579 if ((unsigned)g_aCmdOptions[i].iShort < 127U)
580 {
581 char szOpt[64];
582 RTStrPrintf(szOpt, sizeof(szOpt), "%s, -%c", g_aCmdOptions[i].pszLong, g_aCmdOptions[i].iShort);
583 RTStrmPrintf(pStrm, " %-19s %s\n", szOpt, pszHelp);
584 }
585 else
586 RTStrmPrintf(pStrm, " %-19s %s\n", g_aCmdOptions[i].pszLong, pszHelp);
587 }
588}
589
590
591int main(int argc, char *argv[])
592{
593 /*
594 * Init IPRT and globals.
595 */
596 int rc = RTTestInitAndCreate("IoPerf", &g_hTest);
597 if (rc)
598 return rc;
599
600 /*
601 * Default values.
602 */
603 char szDefaultDir[32];
604 const char *pszDir = szDefaultDir;
605 RTStrPrintf(szDefaultDir, sizeof(szDefaultDir), "ioperfdir-%u" RTPATH_SLASH_STR, RTProcSelf());
606
607 RTGETOPTUNION ValueUnion;
608 RTGETOPTSTATE GetState;
609 RTGetOptInit(&GetState, argc, argv, g_aCmdOptions, RT_ELEMENTS(g_aCmdOptions), 1, 0 /* fFlags */);
610 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
611 {
612 switch (rc)
613 {
614 case 'd':
615 pszDir = ValueUnion.psz;
616 break;
617
618 case 'r':
619 g_fRelativeDir = true;
620 break;
621
622 case 'q':
623 g_uVerbosity = 0;
624 break;
625
626 case 'v':
627 g_uVerbosity++;
628 break;
629
630 case 'h':
631 Usage(g_pStdOut);
632 return RTEXITCODE_SUCCESS;
633
634 case 'V':
635 {
636 char szRev[] = "$Revision: 80032 $";
637 szRev[RT_ELEMENTS(szRev) - 2] = '\0';
638 RTPrintf(RTStrStrip(strchr(szRev, ':') + 1));
639 return RTEXITCODE_SUCCESS;
640 }
641
642 default:
643 return RTGetOptPrintError(rc, &ValueUnion);
644 }
645 }
646
647 /*
648 * Populate g_szDir.
649 */
650 if (!g_fRelativeDir)
651 rc = RTPathAbs(pszDir, g_szDir, sizeof(g_szDir));
652 else
653 rc = RTStrCopy(g_szDir, sizeof(g_szDir), pszDir);
654 if (RT_FAILURE(rc))
655 {
656 RTTestFailed(g_hTest, "%s(%s) failed: %Rrc\n", g_fRelativeDir ? "RTStrCopy" : "RTAbsPath", pszDir, rc);
657 return RTTestSummaryAndDestroy(g_hTest);
658 }
659 RTPathEnsureTrailingSeparator(g_szDir, sizeof(g_szDir));
660 g_cchDir = strlen(g_szDir);
661
662 /*
663 * Create the test directory with an 'empty' subdirectory under it,
664 * execute the tests, and remove directory when done.
665 */
666 RTTestBanner(g_hTest);
667 if (!RTPathExists(g_szDir))
668 {
669 /* The base dir: */
670 rc = RTDirCreate(g_szDir, 0755,
671 RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_DONT_SET | RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL);
672 if (RT_SUCCESS(rc))
673 {
674 RTTestIPrintf(RTTESTLVL_ALWAYS, "Test dir: %s\n", g_szDir);
675
676 if (g_cJobs == 1)
677 rc = ioPerfDoTestSingle();
678 else
679 rc = ioPerfDoTestMulti();
680
681 g_szDir[g_cchDir] = '\0';
682 rc = RTDirRemoveRecursive(g_szDir, RTDIRRMREC_F_CONTENT_AND_DIR | (g_fRelativeDir ? RTDIRRMREC_F_NO_ABS_PATH : 0));
683 if (RT_FAILURE(rc))
684 RTTestFailed(g_hTest, "RTDirRemoveRecursive(%s,) -> %Rrc\n", g_szDir, rc);
685 }
686 else
687 RTTestFailed(g_hTest, "RTDirCreate(%s) -> %Rrc\n", g_szDir, rc);
688 }
689 else
690 RTTestFailed(g_hTest, "Test directory already exists: %s\n", g_szDir);
691
692 return RTTestSummaryAndDestroy(g_hTest);
693}
694
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