1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743 |
- /*++
- Copyright (c) 2013 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- filetest.c
- Abstract:
- This module implements the tests used to verify that basic file operations
- are working.
- Author:
- Evan Green 27-Sep-2013
- Environment:
- User Mode
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/lib/types.h>
- #include <assert.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <getopt.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/wait.h>
- #include <sys/time.h>
- #include <time.h>
- #include <unistd.h>
- //
- // --------------------------------------------------------------------- Macros
- //
- #define DEBUG_PRINT(...) \
- if (FileTestVerbosity >= TestVerbosityDebug) { \
- printf(__VA_ARGS__); \
- }
- #define PRINT(...) \
- if (FileTestVerbosity >= TestVerbosityNormal) { \
- printf(__VA_ARGS__); \
- }
- #define PRINT_ERROR(...) fprintf(stderr, "\nfiletest: " __VA_ARGS__)
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define FILE_TEST_VERSION_MAJOR 1
- #define FILE_TEST_VERSION_MINOR 0
- #define FILE_TEST_USAGE \
- "Usage: filetest [options] \n" \
- "This utility hammers on the file system. Options are:\n" \
- " -c, --file-count <count> -- Set the number of files to create.\n" \
- " -s, --file-size <size> -- Set the size of each file in bytes.\n" \
- " -i, --iterations <count> -- Set the number of operations to perform.\n" \
- " -p, --threads <count> -- Set the number of threads to spin up.\n" \
- " -r, --seed=int -- Set the random seed for deterministic results.\n" \
- " -t, --test -- Set the test to perform. Valid values are all, \n" \
- " consistency, concurrency, seek, streamseek, append, and \n" \
- " uninitialized.\n" \
- " --debug -- Print lots of information about what's happening.\n" \
- " --quiet -- Print only errors.\n" \
- " --no-cleanup -- Leave test files around for debugging.\n" \
- " --help -- Print this help text and exit.\n" \
- " --version -- Print the test version and exit.\n" \
- #define FILE_TEST_OPTIONS_STRING "c:s:i:t:p:r:ndqhV"
- #define FILE_TEST_CREATE_PERMISSIONS (S_IRUSR | S_IWUSR)
- #define DEFAULT_FILE_COUNT 20
- #define DEFAULT_FILE_SIZE (1024 * 17)
- #define DEFAULT_OPERATION_COUNT (DEFAULT_FILE_COUNT * 50)
- #define DEFAULT_THREAD_COUNT 1
- #define UNINITIALIZED_DATA_PATTERN 0xAB
- #define UNINITIALIZED_DATA_SEEK_MAX 0x200
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef enum _FILE_TEST_ACTION {
- FileTestActionWrite,
- FileTestActionRead,
- FileTestActionDelete,
- FileTestActionRename,
- FileTestActionCount
- } FILE_TEST_ACTION, *PFILE_TEST_ACTION;
- typedef enum _TEST_VERBOSITY {
- TestVerbosityQuiet,
- TestVerbosityNormal,
- TestVerbosityDebug
- } TEST_VERBOSITY, *PTEST_VERBOSITY;
- typedef enum _FILE_TEST_TYPE {
- FileTestAll,
- FileTestConsistency,
- FileTestSeek,
- FileTestStreamSeek,
- FileTestConcurrency,
- FileTestAppend,
- FileTestUninitializedData
- } FILE_TEST_TYPE, *PFILE_TEST_TYPE;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- ULONG
- RunFileConsistencyTest (
- INT FileCount,
- INT FileSize,
- INT Iterations
- );
- ULONG
- RunFileConcurrencyTest (
- INT FileCount,
- INT FileSize,
- INT Iterations
- );
- ULONG
- RunFileAppendTest (
- INT FileCount,
- INT FileSize,
- INT Iterations
- );
- ULONG
- RunFileSeekTest (
- INT BlockCount,
- INT BlockSize,
- INT Iterations
- );
- ULONG
- RunStreamSeekTest (
- INT BlockCount,
- INT BlockSize,
- INT Iterations
- );
- ULONG
- RunFileUninitializedDataTest (
- INT FileCount,
- INT FileSize,
- INT Iterations
- );
- ULONG
- PrintTestTime (
- struct timeval *StartTime
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Higher levels here print out more stuff.
- //
- TEST_VERBOSITY FileTestVerbosity = TestVerbosityNormal;
- //
- // Set this boolean to skip cleaning up files.
- //
- BOOL FileTestNoCleanup = FALSE;
- struct option FileTestLongOptions[] = {
- {"file-count", required_argument, 0, 'c'},
- {"file-size", required_argument, 0, 's'},
- {"iterations", required_argument, 0, 'i'},
- {"seed", required_argument, 0, 'r'},
- {"threads", required_argument, 0, 'p'},
- {"test", required_argument, 0, 't'},
- {"no-cleanup", no_argument, 0, 'n'},
- {"debug", no_argument, 0, 'd'},
- {"quiet", no_argument, 0, 'q'},
- {"help", no_argument, 0, 'h'},
- {"version", no_argument, 0, 'V'},
- {NULL, 0, 0, 0},
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- int
- main (
- int ArgumentCount,
- char **Arguments
- )
- /*++
- Routine Description:
- This routine implements the file test program.
- Arguments:
- ArgumentCount - Supplies the number of elements in the arguments array.
- Arguments - Supplies an array of strings. The array count is bounded by the
- previous parameter, and the strings are null-terminated.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR AfterScan;
- pid_t Child;
- INT ChildIndex;
- pid_t *Children;
- INT Failures;
- INT FileCount;
- INT FileSize;
- BOOL IsParent;
- INT Iterations;
- INT Option;
- INT Seed;
- INT Status;
- FILE_TEST_TYPE Test;
- INT Threads;
- Children = NULL;
- Failures = 0;
- FileCount = DEFAULT_FILE_COUNT;
- FileSize = DEFAULT_FILE_SIZE;
- Iterations = DEFAULT_OPERATION_COUNT;
- Seed = time(NULL) ^ getpid();
- Test = FileTestAll;
- Threads = DEFAULT_THREAD_COUNT;
- Status = 0;
- setvbuf(stdout, NULL, _IONBF, 0);
- setvbuf(stderr, NULL, _IONBF, 0);
- //
- // Process the control arguments.
- //
- while (TRUE) {
- Option = getopt_long(ArgumentCount,
- Arguments,
- FILE_TEST_OPTIONS_STRING,
- FileTestLongOptions,
- NULL);
- if (Option == -1) {
- break;
- }
- if ((Option == '?') || (Option == ':')) {
- Status = 1;
- goto MainEnd;
- }
- switch (Option) {
- case 'c':
- FileCount = strtol(optarg, &AfterScan, 0);
- if ((FileCount <= 0) || (AfterScan == optarg)) {
- PRINT_ERROR("Invalid file count %s.\n", optarg);
- Status = 1;
- goto MainEnd;
- }
- break;
- case 's':
- FileSize = strtol(optarg, &AfterScan, 0);
- if ((FileSize < 0) || (AfterScan == optarg)) {
- PRINT_ERROR("Invalid file size %s.\n", optarg);
- Status = 1;
- goto MainEnd;
- }
- break;
- case 'i':
- Iterations = strtol(optarg, &AfterScan, 0);
- if ((Iterations < 0) || (AfterScan == optarg)) {
- PRINT_ERROR("Invalid iteration count %s.\n", optarg);
- Status = 1;
- goto MainEnd;
- }
- break;
- case 'n':
- FileTestNoCleanup = TRUE;
- break;
- case 'p':
- Threads = strtol(optarg, &AfterScan, 0);
- if ((Threads <= 0) || (AfterScan == optarg)) {
- PRINT_ERROR("Invalid thread count %s.\n", optarg);
- Status = 1;
- goto MainEnd;
- }
- break;
- case 'r':
- Seed = strtol(optarg, &AfterScan, 0);
- if (AfterScan == optarg) {
- PRINT_ERROR("Invalid seed %s.\n", optarg);
- Status = 1;
- goto MainEnd;
- }
- break;
- case 't':
- if (strcasecmp(optarg, "all") == 0) {
- Test = FileTestAll;
- } else if (strcasecmp(optarg, "consistency") == 0) {
- Test = FileTestConsistency;
- } else if (strcasecmp(optarg, "seek") == 0) {
- Test = FileTestSeek;
- } else if (strcasecmp(optarg, "streamseek") == 0) {
- Test = FileTestStreamSeek;
- } else if (strcasecmp(optarg, "concurrency") == 0) {
- Test = FileTestConcurrency;
- } else if (strcasecmp(optarg, "append") == 0) {
- Test = FileTestAppend;
- } else if (strcasecmp(optarg, "uninitialized") == 0) {
- Test = FileTestUninitializedData;
- } else {
- PRINT_ERROR("Invalid test: %s.\n", optarg);
- Status = 1;
- goto MainEnd;
- }
- break;
- case 'd':
- FileTestVerbosity = TestVerbosityDebug;
- break;
- case 'q':
- FileTestVerbosity = TestVerbosityQuiet;
- break;
- case 'V':
- printf("Minoca filetest version %d.%d\n",
- FILE_TEST_VERSION_MAJOR,
- FILE_TEST_VERSION_MINOR);
- return 1;
- case 'h':
- printf(FILE_TEST_USAGE);
- return 1;
- default:
- assert(FALSE);
- Status = 1;
- goto MainEnd;
- }
- }
- srand(Seed);
- DEBUG_PRINT("Seed: %d.\n", Seed);
- IsParent = TRUE;
- if (Threads > 1) {
- Children = malloc(sizeof(pid_t) * (Threads - 1));
- if (Children == NULL) {
- Status = ENOMEM;
- goto MainEnd;
- }
- memset(Children, 0, sizeof(pid_t) * (Threads - 1));
- for (ChildIndex = 0; ChildIndex < Threads - 1; ChildIndex += 1) {
- Child = fork();
- //
- // If this is the child, break out and run the tests.
- //
- if (Child == 0) {
- srand(time(NULL) + ChildIndex);
- IsParent = FALSE;
- break;
- }
- Children[ChildIndex] = Child;
- }
- }
- //
- // Run the tests.
- //
- if ((Test == FileTestAll) || (Test == FileTestConsistency)) {
- Failures += RunFileConsistencyTest(FileCount, FileSize, Iterations);
- }
- if ((Test == FileTestAll) || (Test == FileTestSeek)) {
- Failures += RunFileSeekTest(FileCount, FileSize, Iterations);
- }
- if ((Test == FileTestAll) || (Test == FileTestStreamSeek)) {
- Failures += RunStreamSeekTest(FileCount, FileSize, Iterations);
- }
- if ((Test == FileTestAll) || (Test == FileTestConcurrency)) {
- Failures += RunFileConcurrencyTest(FileCount, FileSize, Iterations);
- }
- if ((Test == FileTestAll) || (Test == FileTestAppend)) {
- Failures += RunFileAppendTest(FileCount, FileSize, Iterations);
- }
- if ((Test == FileTestAll) || (Test == FileTestUninitializedData)) {
- Failures += RunFileUninitializedDataTest(FileCount,
- FileSize,
- Iterations);
- }
- //
- // Wait for any children.
- //
- if (IsParent != FALSE) {
- if (Threads > 1) {
- for (ChildIndex = 0; ChildIndex < Threads - 1; ChildIndex += 1) {
- Child = waitpid(Children[ChildIndex], &Status, 0);
- if (Child == -1) {
- PRINT_ERROR("Failed to wait for child %d: %s.\n",
- Children[ChildIndex],
- strerror(errno));
- Status = errno;
- } else {
- assert(Child == Children[ChildIndex]);
- if (!WIFEXITED(Status)) {
- PRINT_ERROR("Child %d returned with status %x\n",
- Status);
- Failures += 1;
- }
- Failures += WEXITSTATUS(Status);
- Status = 0;
- }
- }
- }
- //
- // If this is a child, just report back the number of failures to the
- // parent.
- //
- } else {
- if (Failures > 100) {
- exit(100);
- } else {
- exit(Failures);
- }
- }
- MainEnd:
- if (Children != NULL) {
- free(Children);
- }
- if (Status != 0) {
- PRINT_ERROR("Error: %d.\n", Status);
- }
- if (Failures != 0) {
- PRINT_ERROR("\n *** %d failures in filetest ***\n", Failures);
- return Failures;
- }
- return 0;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- ULONG
- RunFileConsistencyTest (
- INT FileCount,
- INT FileSize,
- INT Iterations
- )
- /*++
- Routine Description:
- This routine executes the file consistency test.
- Arguments:
- FileCount - Supplies the number of files to work with.
- FileSize - Supplies the size of each file.
- Iterations - Supplies the number of iterations to perform.
- Return Value:
- Returns the number of failures in the test suite.
- --*/
- {
- FILE_TEST_ACTION Action;
- ssize_t BytesComplete;
- ULONG Failures;
- INT File;
- PINT FileBuffer;
- INT FileIndex;
- CHAR FileName[16];
- PINT FileOffset;
- INT FillIndex;
- INT Iteration;
- INT MaxSimultaneousFiles;
- INT OpenFlags;
- INT Percent;
- pid_t Process;
- INT Result;
- INT SimultaneousFiles;
- struct timeval StartTime;
- INT TotalBytesComplete;
- Failures = 0;
- FileBuffer = NULL;
- FileOffset = NULL;
- //
- // Record the test start time.
- //
- Result = gettimeofday(&StartTime, NULL);
- if (Result != 0) {
- PRINT_ERROR("Failed to get time of day: %s.\n", strerror(errno));
- Failures += 1;
- goto RunFileConsistencyTestEnd;
- }
- //
- // Announce the test.
- //
- Process = getpid();
- PRINT("Process %d Running file consistency with %d files of %d bytes each. "
- "%d iterations.\n",
- Process,
- FileCount,
- FileSize,
- Iterations);
- Percent = Iterations / 100;
- if (Percent == 0) {
- Percent = 1;
- }
- MaxSimultaneousFiles = 0;
- SimultaneousFiles = 0;
- FileOffset = malloc(FileCount * sizeof(INT));
- if (FileOffset == NULL) {
- Failures += 1;
- goto RunFileConsistencyTestEnd;
- }
- for (FileIndex = 0; FileIndex < FileCount; FileIndex += 1) {
- FileOffset[FileIndex] = -1;
- }
- FileSize = ALIGN_RANGE_UP(FileSize, sizeof(INT));
- FileBuffer = malloc(FileSize);
- if (FileBuffer == NULL) {
- Failures += 1;
- goto RunFileConsistencyTestEnd;
- }
- //
- // Perform the file operations. This test writes an entire file with
- // incremental values and then tests that any file reads return the same
- // values.
- //
- for (Iteration = 0; Iteration < Iterations; Iteration += 1) {
- //
- // Pick a random file and a random action.
- //
- FileIndex = rand() % FileCount;
- snprintf(FileName,
- sizeof(FileName),
- "fot%x-%06x",
- Process & 0xFFFF,
- FileIndex);
- Action = rand() % FileTestActionRename;
- //
- // If the file has yet to be created, then the action must be write.
- //
- if (FileOffset[FileIndex] == -1) {
- Action = FileTestActionWrite;
- }
- switch (Action) {
- case FileTestActionWrite:
- if (FileOffset[FileIndex] == -1) {
- SimultaneousFiles += 1;
- if (SimultaneousFiles > MaxSimultaneousFiles) {
- MaxSimultaneousFiles = SimultaneousFiles;
- }
- }
- OpenFlags = O_WRONLY | O_CREAT;
- if ((rand() & 0x1) != 0) {
- OpenFlags |= O_TRUNC;
- }
- File = open(FileName, OpenFlags, FILE_TEST_CREATE_PERMISSIONS);
- if (File < 0) {
- PRINT_ERROR("Failed to open file %s (flags %x): %s.\n",
- FileName,
- OpenFlags,
- strerror(errno));
- Failures += 1;
- continue;
- }
- FileOffset[FileIndex] = rand();
- DEBUG_PRINT("Writing file %s, Value %x\n",
- FileName,
- FileOffset[FileIndex]);
- for (FillIndex = 0;
- FillIndex < FileSize / sizeof(INT);
- FillIndex += 1) {
- FileBuffer[FillIndex] = FileOffset[FileIndex] + FillIndex;
- }
- do {
- BytesComplete = write(File, FileBuffer, FileSize);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete != FileSize) {
- PRINT_ERROR("Write failed. Wrote %d of %d bytes: %s.\n",
- BytesComplete,
- FileSize,
- strerror(errno));
- Failures += 1;
- }
- if (close(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- }
- break;
- case FileTestActionRead:
- DEBUG_PRINT("Reading file %s, Value should be %x\n",
- FileName,
- FileOffset[FileIndex]);
- OpenFlags = O_RDONLY;
- if ((rand() & 0x1) != 0) {
- OpenFlags = O_RDWR;
- }
- File = open(FileName, OpenFlags);
- if (File < 0) {
- PRINT_ERROR("Failed to open file %s (flags %x): %s.\n",
- FileName,
- OpenFlags,
- strerror(errno));
- Failures += 1;
- continue;
- }
- for (FillIndex = 0;
- FillIndex < FileSize / sizeof(INT);
- FillIndex += 1) {
- FileBuffer[FillIndex] = 0xFEEEF00D;
- }
- TotalBytesComplete = 0;
- while (TotalBytesComplete < FileSize) {
- do {
- BytesComplete = read(File,
- FileBuffer + TotalBytesComplete,
- FileSize - TotalBytesComplete);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete <= 0) {
- PRINT_ERROR("Read failed. Read %d (%d total) of "
- "%d bytes: %s.\n",
- BytesComplete,
- TotalBytesComplete,
- FileSize,
- strerror(errno));
- Failures += 1;
- break;
- }
- TotalBytesComplete += BytesComplete;
- }
- for (FillIndex = 0;
- FillIndex < FileSize / sizeof(INT);
- FillIndex += 1) {
- if (FileBuffer[FillIndex] !=
- FileOffset[FileIndex] + FillIndex) {
- PRINT_ERROR("Read data file %s index %x came back %x, "
- "should have been %x.\n",
- FileName,
- FillIndex,
- FileBuffer[FillIndex],
- FileOffset[FileIndex] + FillIndex);
- Failures += 1;
- }
- }
- if (close(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- }
- break;
- case FileTestActionDelete:
- DEBUG_PRINT("Deleting file %s\n", FileName);
- if (unlink(FileName) != 0) {
- PRINT_ERROR("Failed to unlink %s: %s.\n",
- FileName,
- strerror(errno));
- Failures += 1;
- }
- FileOffset[FileIndex] = -1;
- SimultaneousFiles -= 1;
- break;
- default:
- assert(FALSE);
- break;
- }
- if ((Iteration % Percent) == 0) {
- PRINT("o");
- }
- }
- //
- // Clean up all files.
- //
- if (FileTestNoCleanup == FALSE) {
- for (FileIndex = 0; FileIndex < FileCount; FileIndex += 1) {
- if (FileOffset[FileIndex] != -1) {
- snprintf(FileName,
- sizeof(FileName),
- "fot%x-%06x",
- Process & 0xFFFF,
- FileIndex);
- if (unlink(FileName) != 0) {
- PRINT_ERROR("Failed to unlink %s: %s.\n",
- FileName,
- strerror(errno));
- Failures += 1;
- }
- }
- }
- }
- PRINT("\nMax usage: %d files, %I64d bytes.\n",
- MaxSimultaneousFiles,
- (ULONGLONG)MaxSimultaneousFiles * (ULONGLONG)FileSize);
- Failures += PrintTestTime(&StartTime);
- RunFileConsistencyTestEnd:
- if (FileOffset != NULL) {
- free(FileOffset);
- }
- if (FileBuffer != NULL) {
- free(FileBuffer);
- }
- return Failures;
- }
- ULONG
- RunFileConcurrencyTest (
- INT FileCount,
- INT FileSize,
- INT Iterations
- )
- /*++
- Routine Description:
- This routine executes the file concurrency test.
- Arguments:
- FileCount - Supplies the number of files to work with.
- FileSize - Supplies the size of each file.
- Iterations - Supplies the number of iterations to perform.
- Return Value:
- Returns the number of failures in the test suite.
- --*/
- {
- FILE_TEST_ACTION Action;
- unsigned ActionSeed;
- ssize_t BytesComplete;
- INT DestinationFileIndex;
- CHAR DestinationFileName[16];
- ULONG Failures;
- INT File;
- INT FileIndex;
- CHAR FileName[16];
- INT Iteration;
- INT Offset;
- INT OpenFlags;
- INT Percent;
- pid_t Process;
- INT Result;
- struct timeval StartTime;
- INT Value;
- Failures = 0;
- //
- // Record the test start time.
- //
- Result = gettimeofday(&StartTime, NULL);
- if (Result != 0) {
- PRINT_ERROR("Failed to get time of day: %s.\n", strerror(errno));
- Failures += 1;
- goto RunFileConcurrencyTestEnd;
- }
- //
- // Announce the test.
- //
- Process = getpid();
- PRINT("Process %d Running file concurrency test with %d files of %d bytes "
- "each. %d iterations.\n",
- Process,
- FileCount,
- FileSize,
- Iterations);
- Percent = Iterations / 100;
- if (Percent == 0) {
- Percent = 1;
- }
- FileSize = ALIGN_RANGE_UP(FileSize, sizeof(INT));
- //
- // Get a separate seed for the random actions.
- //
- ActionSeed = time(NULL);
- //
- // Perform the file operations.
- //
- for (Iteration = 0; Iteration < Iterations; Iteration += 1) {
- //
- // Pick a random file and a random action.
- //
- FileIndex = rand() % FileCount;
- snprintf(FileName,
- sizeof(FileName),
- "fct-%06x",
- FileIndex);
- Action = rand_r(&ActionSeed) % FileTestActionCount;
- switch (Action) {
- case FileTestActionWrite:
- Offset = rand() % FileSize;
- DEBUG_PRINT("Writing file %s, Offset %x\n", FileName, Offset);
- OpenFlags = O_WRONLY | O_CREAT;
- File = open(FileName, OpenFlags, FILE_TEST_CREATE_PERMISSIONS);
- if (File < 0) {
- PRINT_ERROR("Failed to open file %s (flags %x): %s.\n",
- FileName,
- OpenFlags,
- strerror(errno));
- Failures += 1;
- continue;
- }
- Result = lseek(File, Offset, SEEK_SET);
- if (Result < 0) {
- PRINT_ERROR("Seek on file %s offset %d failed.\n",
- FileName,
- Offset);
- Failures += 1;
- }
- do {
- BytesComplete = write(File, &Offset, 1);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete != 1) {
- PRINT_ERROR("Write failed. Wrote %d of %d bytes: %s.\n",
- BytesComplete,
- FileSize,
- strerror(errno));
- Failures += 1;
- }
- if (close(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- }
- break;
- case FileTestActionRead:
- Offset = rand() % FileSize;
- DEBUG_PRINT("Reading file %s, Offset %x\n", FileName, Offset);
- OpenFlags = O_RDWR | O_CREAT;
- File = open(FileName, OpenFlags, FILE_TEST_CREATE_PERMISSIONS);
- if (File < 0) {
- PRINT_ERROR("Failed to open file %s (flags %x): %s.\n",
- FileName,
- OpenFlags,
- strerror(errno));
- Failures += 1;
- continue;
- }
- Result = lseek(File, Offset, SEEK_SET);
- if (Result < 0) {
- PRINT_ERROR("Seek on file %s offset %d failed.\n",
- FileName,
- Offset);
- Failures += 1;
- }
- //
- // Reads are tricky as the file can be deleted and recreated by
- // other threads. At least validate that if the read succeeded the
- // byte should be zero or the low byte of the offset.
- //
- Value = 0;
- do {
- BytesComplete = read(File, &Value, 1);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete < 0) {
- PRINT_ERROR("Read failed. Read %d of 1 bytes: %s.\n",
- BytesComplete,
- strerror(errno));
- Failures += 1;
- break;
- }
- if ((BytesComplete == 1) &&
- (Value != 0) && (Value != (Offset & 0xFF))) {
- PRINT_ERROR("Error: read of file %s at offset %x turned up "
- "%x (should have been %x or 0).\n",
- FileName,
- Offset,
- Value,
- Offset & 0xFF);
- }
- if (close(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- }
- break;
- case FileTestActionDelete:
- DEBUG_PRINT("Deleting file %s\n", FileName);
- if (unlink(FileName) != 0) {
- if (errno != ENOENT) {
- PRINT_ERROR("Failed to unlink %s: %s.\n",
- FileName,
- strerror(errno));
- Failures += 1;
- }
- }
- break;
- case FileTestActionRename:
- //
- // Pick a random destination file.
- //
- DestinationFileIndex = rand() % FileCount;
- snprintf(DestinationFileName,
- sizeof(DestinationFileName),
- "fct-%06x",
- DestinationFileIndex);
- //
- // Rename the current file to the destination file.
- //
- DEBUG_PRINT("Renaming file %s to %s.\n",
- FileName,
- DestinationFileName);
- if (rename(FileName, DestinationFileName) != 0) {
- if (errno != ENOENT) {
- PRINT_ERROR("Failed to rename %s to %s: %s.\n",
- FileName,
- DestinationFileName,
- strerror(errno));
- Failures += 1;
- }
- }
- break;
- default:
- assert(FALSE);
- break;
- }
- if ((Iteration % Percent) == 0) {
- PRINT("c");
- }
- }
- //
- // Clean up. Sure, other threads could still be running the test, but they
- // should all clean up too.
- //
- if (FileTestNoCleanup == FALSE) {
- for (FileIndex = 0; FileIndex < FileCount; FileIndex += 1) {
- snprintf(FileName,
- sizeof(FileName),
- "fct-%06x",
- FileIndex);
- Result = unlink(FileName);
- if ((Result != 0) && (errno != ENOENT)) {
- PRINT_ERROR("Failed to unlink %s: %s.\n",
- FileName,
- strerror(errno));
- Failures += 1;
- }
- }
- }
- PRINT("\n");
- Failures += PrintTestTime(&StartTime);
- RunFileConcurrencyTestEnd:
- return Failures;
- }
- ULONG
- RunFileAppendTest (
- INT FileCount,
- INT FileSize,
- INT Iterations
- )
- /*++
- Routine Description:
- This routine executes the file append test.
- Arguments:
- FileCount - Supplies the number of files to work with.
- FileSize - Supplies the size of each file.
- Iterations - Supplies the number of iterations to perform.
- Return Value:
- Returns the number of failures in the test suite.
- --*/
- {
- FILE_TEST_ACTION Action;
- ssize_t BytesComplete;
- ULONG Failures;
- INT File;
- INT FileIndex;
- CHAR FileName[16];
- PINT FileOffset;
- INT Iteration;
- INT MaxSimultaneousFiles;
- LONG Offset;
- INT OpenFlags;
- INT Percent;
- pid_t Process;
- INT Result;
- INT SimultaneousFiles;
- struct timeval StartTime;
- INT TotalBytesComplete;
- INT Value;
- Failures = 0;
- FileOffset = NULL;
- //
- // Record the test start time.
- //
- Result = gettimeofday(&StartTime, NULL);
- if (Result != 0) {
- PRINT_ERROR("Failed to get time of day: %s.\n", strerror(errno));
- Failures += 1;
- goto RunFileAppendTestEnd;
- }
- //
- // Announce the test.
- //
- Process = getpid();
- PRINT("Process %d Running file append test with %d files of %d bytes each. "
- "%d iterations.\n",
- Process,
- FileCount,
- FileSize,
- Iterations);
- Percent = Iterations / 100;
- if (Percent == 0) {
- Percent = 1;
- }
- MaxSimultaneousFiles = 0;
- SimultaneousFiles = 0;
- FileOffset = malloc(FileCount * sizeof(INT));
- if (FileOffset == NULL) {
- Failures += 1;
- goto RunFileAppendTestEnd;
- }
- for (FileIndex = 0; FileIndex < FileCount; FileIndex += 1) {
- FileOffset[FileIndex] = 0;
- }
- FileSize = ALIGN_RANGE_UP(FileSize, sizeof(INT));
- //
- // Perform the file operations.
- //
- for (Iteration = 0; Iteration < Iterations; Iteration += 1) {
- //
- // Pick a random file and a random action.
- //
- FileIndex = rand() % FileCount;
- snprintf(FileName,
- sizeof(FileName),
- "fat%x-%06x",
- Process & 0xFFFF,
- FileIndex);
- Action = rand() % FileTestActionRename;
- //
- // If the file has yet to be created, then the action must be write.
- //
- if (FileOffset[FileIndex] == 0) {
- Action = FileTestActionWrite;
- }
- //
- // If the file shouldn't grow anymore, change writes into reads.
- //
- if ((FileOffset[FileIndex] > FileSize) &&
- (Action == FileTestActionWrite)) {
- Action = FileTestActionRead;
- }
- switch (Action) {
- case FileTestActionWrite:
- OpenFlags = O_WRONLY | O_APPEND;
- if (FileOffset[FileIndex] == 0) {
- OpenFlags |= O_CREAT | O_EXCL;
- SimultaneousFiles += 1;
- if (SimultaneousFiles > MaxSimultaneousFiles) {
- MaxSimultaneousFiles = SimultaneousFiles;
- }
- }
- DEBUG_PRINT("Writing file %s, Value %x\n",
- FileName,
- FileOffset[FileIndex]);
- File = open(FileName, OpenFlags, FILE_TEST_CREATE_PERMISSIONS);
- if (File < 0) {
- PRINT_ERROR("Failed to open file %s (flags %x): %s.\n",
- FileName,
- OpenFlags,
- strerror(errno));
- Failures += 1;
- continue;
- }
- //
- // Seek somewhere to try and throw it off.
- //
- Result = lseek(File, rand(), SEEK_SET);
- if (Result < 0) {
- PRINT_ERROR("Seek failed. Result %d: %s.\n",
- Result,
- strerror(errno));
- Failures += 1;
- }
- Value = FileOffset[FileIndex];
- FileOffset[FileIndex] += 1;
- do {
- BytesComplete = write(File, &Value, sizeof(INT));
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete != sizeof(INT)) {
- PRINT_ERROR("Write failed. Wrote %d of %d bytes: %s.\n",
- BytesComplete,
- sizeof(INT),
- strerror(errno));
- Failures += 1;
- }
- if (close(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- }
- break;
- case FileTestActionRead:
- if (FileOffset[FileIndex] == 0) {
- DEBUG_PRINT("Skipping read from empty file %s.\n", FileName);
- continue;
- }
- Offset = (rand() % FileOffset[FileIndex]) * sizeof(INT);
- DEBUG_PRINT("Reading file %s offset %x, Value should be %x\n",
- FileName,
- Offset,
- Offset / sizeof(INT));
- OpenFlags = O_RDONLY;
- if ((rand() & 0x1) != 0) {
- OpenFlags = O_RDWR;
- }
- File = open(FileName, OpenFlags);
- if (File < 0) {
- PRINT_ERROR("Failed to open file %s (flags %x): %s.\n",
- FileName,
- OpenFlags,
- strerror(errno));
- Failures += 1;
- continue;
- }
- Result = lseek(File, Offset, SEEK_SET);
- if (Result < 0) {
- PRINT_ERROR("Seek failed. Result %d: %s.\n",
- Result,
- strerror(errno));
- Failures += 1;
- }
- Value = 0;
- TotalBytesComplete = 0;
- while (TotalBytesComplete < sizeof(INT)) {
- do {
- BytesComplete = read(File,
- (PVOID)(&Value) + TotalBytesComplete,
- sizeof(INT) - TotalBytesComplete);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete <= 0) {
- PRINT_ERROR("Read failed. Read %d (%d total) of "
- "%d bytes: %s.\n",
- BytesComplete,
- TotalBytesComplete,
- sizeof(INT),
- strerror(errno));
- Failures += 1;
- break;
- }
- TotalBytesComplete += BytesComplete;
- }
- if (Value != (Offset / sizeof(INT))) {
- PRINT_ERROR("Read append data file %s offset %x came back %x, "
- "should have been %x.\n",
- FileName,
- Offset,
- Value,
- Offset / sizeof(INT));
- Failures += 1;
- }
- if (close(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- }
- break;
- case FileTestActionDelete:
- DEBUG_PRINT("Deleting file %s\n", FileName);
- if (unlink(FileName) != 0) {
- PRINT_ERROR("Failed to unlink %s: %s.\n",
- FileName,
- strerror(errno));
- Failures += 1;
- }
- FileOffset[FileIndex] = 0;
- SimultaneousFiles -= 1;
- break;
- default:
- assert(FALSE);
- break;
- }
- if ((Iteration % Percent) == 0) {
- PRINT("a");
- }
- }
- //
- // Clean up all files.
- //
- if (FileTestNoCleanup == FALSE) {
- for (FileIndex = 0; FileIndex < FileCount; FileIndex += 1) {
- if (FileOffset[FileIndex] != 0) {
- snprintf(FileName,
- sizeof(FileName),
- "fat%x-%06x",
- Process & 0xFFFF,
- FileIndex);
- if (unlink(FileName) != 0) {
- PRINT_ERROR("Failed to unlink %s: %s.\n",
- FileName,
- strerror(errno));
- Failures += 1;
- }
- }
- }
- }
- PRINT("\nMax usage: %d files, %I64d bytes.\n",
- MaxSimultaneousFiles,
- (ULONGLONG)MaxSimultaneousFiles * (ULONGLONG)FileSize);
- Failures += PrintTestTime(&StartTime);
- RunFileAppendTestEnd:
- if (FileOffset != NULL) {
- free(FileOffset);
- }
- return Failures;
- }
- ULONG
- RunFileSeekTest (
- INT BlockCount,
- INT BlockSize,
- INT Iterations
- )
- /*++
- Routine Description:
- This routine executes the file seek test.
- Arguments:
- BlockCount - Supplies the number of blocks to play with in the file.
- BlockSize - Supplies the size of each block.
- Iterations - Supplies the number of iterations to perform.
- Return Value:
- Returns the number of failures in the test suite.
- --*/
- {
- FILE_TEST_ACTION Action;
- INT BlockErrorCount;
- INT BlockIndex;
- ssize_t BytesComplete;
- ULONG Failures;
- INT File;
- PINT FileBuffer;
- CHAR FileName[10];
- PINT FileOffset;
- INT FillIndex;
- INT Iteration;
- INT MaxBlock;
- INT OpenFlags;
- INT Percent;
- pid_t Process;
- INT Result;
- struct timeval StartTime;
- INT TotalBytesComplete;
- Failures = 0;
- FileBuffer = NULL;
- FileOffset = NULL;
- //
- // Record the test start time.
- //
- Result = gettimeofday(&StartTime, NULL);
- if (Result != 0) {
- PRINT_ERROR("Failed to get time of day: %s.\n", strerror(errno));
- Failures += 1;
- goto RunFileSeekTestEnd;
- }
- //
- // Announce the test.
- //
- Process = getpid();
- PRINT("Process %d Running file seek test with %d blocks of %d bytes each. "
- "%d iterations.\n",
- Process,
- BlockCount,
- BlockSize,
- Iterations);
- Percent = Iterations / 100;
- if (Percent == 0) {
- Percent = 1;
- }
- MaxBlock = -1;
- FileOffset = malloc(BlockCount * sizeof(INT));
- if (FileOffset == NULL) {
- Failures += 1;
- goto RunFileSeekTestEnd;
- }
- for (BlockIndex = 0; BlockIndex < BlockCount; BlockIndex += 1) {
- FileOffset[BlockIndex] = -1;
- }
- BlockSize = ALIGN_RANGE_UP(BlockSize, sizeof(INT));
- FileBuffer = malloc(BlockSize);
- if (FileBuffer == NULL) {
- Failures += 1;
- goto RunFileSeekTestEnd;
- }
- //
- // Open up the file.
- //
- snprintf(FileName, sizeof(FileName), "ft%x", Process & 0xFFFF);
- OpenFlags = O_RDWR | O_CREAT | O_TRUNC;
- File = open(FileName, OpenFlags, FILE_TEST_CREATE_PERMISSIONS);
- if (File < 0) {
- PRINT_ERROR("Failed to open file %s (flags %x): %s.\n",
- FileName,
- OpenFlags,
- strerror(errno));
- Failures += 1;
- goto RunFileSeekTestEnd;
- }
- //
- // Perform the file operations.
- //
- for (Iteration = 0; Iteration < Iterations; Iteration += 1) {
- //
- // Pick a random block and a random action.
- //
- BlockIndex = rand() % BlockCount;
- Action = rand() % FileTestActionDelete;
- //
- // A read beyond the end of the file so far won't work, so change it
- // into a write.
- //
- if ((Action == FileTestActionRead) && (BlockIndex > MaxBlock)) {
- Action = FileTestActionWrite;
- }
- //
- // Seek to the right spot.
- //
- Result = lseek(File,
- (ULONGLONG)BlockIndex * (ULONGLONG)BlockSize,
- SEEK_SET);
- if (Result < 0) {
- PRINT_ERROR("Failed to seek to offset %I64x: %s.\n",
- (ULONGLONG)BlockIndex * (ULONGLONG)BlockSize,
- strerror(errno));
- Failures += 1;
- FileOffset[BlockIndex] = -1;
- continue;
- }
- switch (Action) {
- case FileTestActionWrite:
- if (FileOffset[BlockIndex] == -1) {
- if (MaxBlock < BlockIndex) {
- MaxBlock = BlockIndex;
- }
- }
- FileOffset[BlockIndex] = rand();
- DEBUG_PRINT("Writing block %d, Value %x\n",
- BlockIndex,
- FileOffset[BlockIndex]);
- for (FillIndex = 0;
- FillIndex < BlockSize / sizeof(INT);
- FillIndex += 1) {
- FileBuffer[FillIndex] = FileOffset[BlockIndex] + FillIndex;
- }
- do {
- BytesComplete = write(File, FileBuffer, BlockSize);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete != BlockSize) {
- PRINT_ERROR("Write failed. Wrote %d of %d bytes: %s.\n",
- BytesComplete,
- BlockSize,
- strerror(errno));
- Failures += 1;
- }
- break;
- case FileTestActionRead:
- DEBUG_PRINT("Reading block %d, Value should be %x\n",
- BlockIndex,
- FileOffset[BlockIndex]);
- for (FillIndex = 0;
- FillIndex < BlockSize / sizeof(INT);
- FillIndex += 1) {
- FileBuffer[FillIndex] = 0xFEEEF00D;
- }
- TotalBytesComplete = 0;
- while (TotalBytesComplete < BlockSize) {
- do {
- BytesComplete = read(File,
- FileBuffer + TotalBytesComplete,
- BlockSize - TotalBytesComplete);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete <= 0) {
- PRINT_ERROR("Read failed. Read %d (%d total) of "
- "%d bytes: %s.\n",
- BytesComplete,
- TotalBytesComplete,
- BlockSize,
- strerror(errno));
- Failures += 1;
- break;
- }
- TotalBytesComplete += BytesComplete;
- }
- BlockErrorCount = 0;
- for (FillIndex = 0;
- FillIndex < BlockSize / sizeof(INT);
- FillIndex += 1) {
- //
- // If the file was never written before, it should be all
- // zeroes.
- //
- if (FileOffset[BlockIndex] == -1) {
- if (FileBuffer[FillIndex] != 0) {
- PRINT_ERROR("Read data block %d index %x came back %x, "
- "should have been zero.\n",
- BlockIndex,
- FillIndex,
- FileBuffer[FillIndex]);
- Failures += 1;
- BlockErrorCount += 1;
- }
- //
- // If the file was written before, validate that the data is
- // still there and correct.
- //
- } else if (FileBuffer[FillIndex] !=
- FileOffset[BlockIndex] + FillIndex) {
- PRINT_ERROR("Read data block %d index %x came back %x, "
- "should have been %x.\n",
- BlockIndex,
- FillIndex,
- FileBuffer[FillIndex],
- FileOffset[BlockIndex] + FillIndex);
- Failures += 1;
- BlockErrorCount += 1;
- }
- if (BlockErrorCount > 15) {
- PRINT_ERROR("...you get the idea...\n");
- break;
- }
- }
- break;
- default:
- assert(FALSE);
- break;
- }
- if ((Iteration % Percent) == 0) {
- PRINT("s");
- }
- }
- if (FileTestNoCleanup == FALSE) {
- DEBUG_PRINT("Deleting file %s\n", FileName);
- if (unlink(FileName) != 0) {
- PRINT_ERROR("Failed to unlink %s: %s.\n",
- FileName,
- strerror(errno));
- Failures += 1;
- }
- }
- if (close(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- }
- PRINT("\nMax block: %d, %I64d bytes.\n",
- MaxBlock,
- (ULONGLONG)MaxBlock * (ULONGLONG)BlockSize);
- Failures += PrintTestTime(&StartTime);
- RunFileSeekTestEnd:
- if (FileOffset != NULL) {
- free(FileOffset);
- }
- if (FileBuffer != NULL) {
- free(FileBuffer);
- }
- return Failures;
- }
- ULONG
- RunStreamSeekTest (
- INT BlockCount,
- INT BlockSize,
- INT Iterations
- )
- /*++
- Routine Description:
- This routine executes the stream seek test, which is the same as the file
- seek test except it uses streams instead of raw file descriptors..
- Arguments:
- BlockCount - Supplies the number of blocks to play with in the file.
- BlockSize - Supplies the size of each block.
- Iterations - Supplies the number of iterations to perform.
- Return Value:
- Returns the number of failures in the test suite.
- --*/
- {
- FILE_TEST_ACTION Action;
- INT BlockErrorCount;
- INT BlockIndex;
- ssize_t BytesComplete;
- ULONG Failures;
- FILE *File;
- PINT FileBuffer;
- CHAR FileName[10];
- PINT FileOffset;
- INT FillIndex;
- INT Iteration;
- INT MaxBlock;
- INT Percent;
- pid_t Process;
- INT Result;
- struct timeval StartTime;
- INT TotalBytesComplete;
- Failures = 0;
- FileBuffer = NULL;
- FileOffset = NULL;
- //
- // Record the test start time.
- //
- Result = gettimeofday(&StartTime, NULL);
- if (Result != 0) {
- PRINT_ERROR("Failed to get time of day: %s.\n", strerror(errno));
- Failures += 1;
- goto RunStreamSeekTestEnd;
- }
- //
- // Announce the test.
- //
- Process = getpid();
- PRINT("Process %d Running stream seek test with %d blocks of %d bytes "
- "each. %d iterations.\n",
- Process,
- BlockCount,
- BlockSize,
- Iterations);
- Percent = Iterations / 100;
- if (Percent == 0) {
- Percent = 1;
- }
- MaxBlock = -1;
- FileOffset = malloc(BlockCount * sizeof(INT));
- if (FileOffset == NULL) {
- Failures += 1;
- goto RunStreamSeekTestEnd;
- }
- for (BlockIndex = 0; BlockIndex < BlockCount; BlockIndex += 1) {
- FileOffset[BlockIndex] = -1;
- }
- BlockSize = ALIGN_RANGE_UP(BlockSize, sizeof(INT));
- FileBuffer = malloc(BlockSize);
- if (FileBuffer == NULL) {
- Failures += 1;
- goto RunStreamSeekTestEnd;
- }
- //
- // Open up the file.
- //
- snprintf(FileName, sizeof(FileName), "st%x", Process & 0xFFFF);
- File = fopen(FileName, "w+");
- if (File == NULL) {
- PRINT_ERROR("Failed to open file %s (mode %s): %s.\n",
- FileName,
- "w+",
- strerror(errno));
- Failures += 1;
- goto RunStreamSeekTestEnd;
- }
- //
- // Perform the file operations.
- //
- for (Iteration = 0; Iteration < Iterations; Iteration += 1) {
- //
- // Pick a random block and a random action.
- //
- BlockIndex = rand() % BlockCount;
- Action = rand() % FileTestActionDelete;
- //
- // A read beyond the end of the file so far won't work, so change it
- // into a write.
- //
- if ((Action == FileTestActionRead) && (BlockIndex > MaxBlock)) {
- Action = FileTestActionWrite;
- }
- //
- // Seek to the right spot.
- //
- Result = fseeko64(File,
- (ULONGLONG)BlockIndex * (ULONGLONG)BlockSize,
- SEEK_SET);
- if (Result < 0) {
- PRINT_ERROR("Failed to seek to offset %I64x: %s.\n",
- (ULONGLONG)BlockIndex * (ULONGLONG)BlockSize,
- strerror(errno));
- Failures += 1;
- FileOffset[BlockIndex] = -1;
- continue;
- }
- switch (Action) {
- case FileTestActionWrite:
- if (FileOffset[BlockIndex] == -1) {
- if (MaxBlock < BlockIndex) {
- MaxBlock = BlockIndex;
- }
- }
- FileOffset[BlockIndex] = rand();
- DEBUG_PRINT("Writing block %d, Value %x\n",
- BlockIndex,
- FileOffset[BlockIndex]);
- for (FillIndex = 0;
- FillIndex < BlockSize / sizeof(INT);
- FillIndex += 1) {
- FileBuffer[FillIndex] = FileOffset[BlockIndex] + FillIndex;
- }
- BytesComplete = fwrite(FileBuffer, 1, BlockSize, File);
- if (BytesComplete != BlockSize) {
- PRINT_ERROR("Write failed. Wrote %d of %d bytes: %s.\n",
- BytesComplete,
- BlockSize,
- strerror(errno));
- Failures += 1;
- }
- break;
- case FileTestActionRead:
- DEBUG_PRINT("Reading block %d, Value should be %x\n",
- BlockIndex,
- FileOffset[BlockIndex]);
- for (FillIndex = 0;
- FillIndex < BlockSize / sizeof(INT);
- FillIndex += 1) {
- FileBuffer[FillIndex] = 0xFEEEF00D;
- }
- TotalBytesComplete = 0;
- while (TotalBytesComplete < BlockSize) {
- BytesComplete = fread(FileBuffer + TotalBytesComplete,
- 1,
- BlockSize - TotalBytesComplete,
- File);
- if (BytesComplete <= 0) {
- PRINT_ERROR("Read failed. Read %d (%d total) of "
- "%d bytes: %s.\n",
- BytesComplete,
- TotalBytesComplete,
- BlockSize,
- strerror(errno));
- Failures += 1;
- break;
- }
- TotalBytesComplete += BytesComplete;
- }
- BlockErrorCount = 0;
- for (FillIndex = 0;
- FillIndex < BlockSize / sizeof(INT);
- FillIndex += 1) {
- //
- // If the file was never written before, it should be all
- // zeroes.
- //
- if (FileOffset[BlockIndex] == -1) {
- if (FileBuffer[FillIndex] != 0) {
- PRINT_ERROR("Read data block %d index %x came back %x, "
- "should have been zero.\n",
- BlockIndex,
- FillIndex,
- FileBuffer[FillIndex]);
- Failures += 1;
- BlockErrorCount += 1;
- }
- //
- // If the file was written before, validate that the data is
- // still there and correct.
- //
- } else if (FileBuffer[FillIndex] !=
- FileOffset[BlockIndex] + FillIndex) {
- PRINT_ERROR("Read data block %d index %x came back %x, "
- "should have been %x.\n",
- BlockIndex,
- FillIndex,
- FileBuffer[FillIndex],
- FileOffset[BlockIndex] + FillIndex);
- Failures += 1;
- BlockErrorCount += 1;
- }
- if (BlockErrorCount > 15) {
- PRINT_ERROR("...you get the idea...\n");
- break;
- }
- }
- break;
- default:
- assert(FALSE);
- break;
- }
- if ((Iteration % Percent) == 0) {
- PRINT("S");
- }
- }
- if (FileTestNoCleanup == FALSE) {
- DEBUG_PRINT("Deleting file %s\n", FileName);
- if (unlink(FileName) != 0) {
- PRINT_ERROR("Failed to unlink %s: %s.\n",
- FileName,
- strerror(errno));
- Failures += 1;
- }
- }
- if (fclose(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- }
- PRINT("\nMax block: %d, %I64d bytes.\n",
- MaxBlock,
- (ULONGLONG)MaxBlock * (ULONGLONG)BlockSize);
- Failures += PrintTestTime(&StartTime);
- RunStreamSeekTestEnd:
- if (FileOffset != NULL) {
- free(FileOffset);
- }
- if (FileBuffer != NULL) {
- free(FileBuffer);
- }
- return Failures;
- }
- ULONG
- RunFileUninitializedDataTest (
- INT FileCount,
- INT FileSize,
- INT Iterations
- )
- /*++
- Routine Description:
- This routine executes the file uninitialized data test.
- Arguments:
- FileCount - Supplies the number of files to work with.
- FileSize - Supplies the size of each file.
- Iterations - Supplies the number of iterations to perform.
- Return Value:
- Returns the number of failures in the test suite.
- --*/
- {
- size_t ArraySize;
- ssize_t BytesComplete;
- INT Expected;
- ULONG Failures;
- INT File;
- INT FileIndex;
- CHAR FileName[16];
- PBYTE *FileState;
- INT Iteration;
- ULONGLONG Offset;
- INT OpenFlags;
- INT Percent;
- pid_t Process;
- INT Result;
- off_t ResultOffset;
- INT Seek;
- struct timeval StartTime;
- PCHAR UninitializedDataBuffer;
- INT UninitializedDataSize;
- INT Value;
- Failures = 0;
- FileState = NULL;
- UninitializedDataBuffer = NULL;
- //
- // Record the test start time.
- //
- Result = gettimeofday(&StartTime, NULL);
- if (Result != 0) {
- PRINT_ERROR("Failed to get time of day: %s.\n", strerror(errno));
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- //
- // Announce the test.
- //
- Process = getpid();
- PRINT("Process %d Running file uninitialized data test with %d files of "
- "%d bytes each. %d iterations.\n",
- Process,
- FileCount,
- FileSize,
- Iterations);
- Percent = Iterations / 100;
- if (Percent == 0) {
- Percent = 1;
- }
- FileSize = ALIGN_RANGE_UP(FileSize, sizeof(INT));
- //
- // Before starting this test, create a big file with distinct byte pattern
- // and flush it to disk and then delete it. After this any clusters
- // allocated by the test will have the pattern in the unmodified portions.
- // If the system is working correctly, this pattern should never be read.
- //
- PRINT("Scribbling the pattern 0x%x over the disk.\n",
- UNINITIALIZED_DATA_PATTERN);
- UninitializedDataSize = FileSize * FileCount;
- UninitializedDataBuffer = malloc(UninitializedDataSize);
- if (UninitializedDataBuffer == NULL) {
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- for (FileIndex = 0; FileIndex < UninitializedDataSize; FileIndex += 1) {
- UninitializedDataBuffer[FileIndex] = (CHAR)UNINITIALIZED_DATA_PATTERN;
- }
- snprintf(FileName, sizeof(FileName), "fudt-init%x", Process & 0xFFFF);
- OpenFlags = O_WRONLY | O_CREAT;
- File = open(FileName, OpenFlags, FILE_TEST_CREATE_PERMISSIONS);
- if (File < 0) {
- PRINT_ERROR("Filed to open file %s (flags %x): %s.\n",
- FileName,
- OpenFlags,
- strerror(errno));
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- DEBUG_PRINT("Writing file %s\n", FileName);
- do {
- BytesComplete = write(File,
- UninitializedDataBuffer,
- UninitializedDataSize);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete != UninitializedDataSize) {
- PRINT_ERROR("Write to %s failed. Wrote %d of %d bytes: %s.\n",
- FileName,
- BytesComplete,
- UninitializedDataSize,
- strerror(errno));
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- //
- // Now flush the file to make sure the bytes make it to disk.
- //
- DEBUG_PRINT("Flushing file %s\n", FileName);
- Result = fsync(File);
- if (Result < 0) {
- PRINT_ERROR("Flush of %s failed: %s.\n", FileName, strerror(errno));
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- //
- // Close, truncate and unlink the file to free up the clusters.
- //
- DEBUG_PRINT("Closing file %s\n", FileName);
- if (close(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- DEBUG_PRINT("Opening file for truncate %s\n", FileName);
- OpenFlags = O_TRUNC;
- File = open(FileName, OpenFlags, FILE_TEST_CREATE_PERMISSIONS);
- if (File < 0) {
- PRINT_ERROR("Failed to open file %s for truncate: %s.\n",
- FileName,
- strerror(errno));
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- DEBUG_PRINT("Closing file %s\n", FileName);
- if (close(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- DEBUG_PRINT("Deleting file %s\n", FileName);
- Result = unlink(FileName);
- if (Result != 0) {
- PRINT_ERROR("Failed to unlink %s: %s.\n",
- FileName,
- strerror(errno));
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- //
- // Create an array to hold the expected state for each file.
- //
- FileState = malloc(FileCount * sizeof(PBYTE));
- if (FileState == NULL) {
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- memset(FileState, 0, FileCount * sizeof(PBYTE));
- //
- // Perform the file operations.
- //
- PRINT("Starting tests.\n");
- for (Iteration = 0; Iteration < Iterations; Iteration += 1) {
- //
- // Pick a random file and a random action.
- //
- FileIndex = rand() % FileCount;
- snprintf(FileName,
- sizeof(FileName),
- "fudt%x-%06x",
- Process & 0xFFFF,
- FileIndex);
- //
- // If the file is yet to be created, then write to the first byte and
- // the last byte and do some flushes to make sure partial pages are
- // handled correctly.
- //
- if (FileState[FileIndex] == 0) {
- ArraySize = FileSize + UNINITIALIZED_DATA_SEEK_MAX + 1;
- FileState[FileIndex] = malloc(ArraySize);
- memset(FileState[FileIndex], 0, ArraySize);
- OpenFlags = O_RDWR | O_CREAT;
- File = open(FileName, OpenFlags, FILE_TEST_CREATE_PERMISSIONS);
- if (File < 0) {
- PRINT_ERROR("Failed to open file %s (flags %x): %s.\n",
- FileName,
- OpenFlags,
- strerror(errno));
- Failures += 1;
- continue;
- }
- //
- // Write the first byte of the file and flush it.
- //
- Offset = 0;
- Result = lseek(File, Offset, SEEK_SET);
- if (Result < 0) {
- PRINT_ERROR("Seek on file %s offset 0x%I64x failed.\n",
- FileName,
- Offset);
- Failures += 1;
- }
- DEBUG_PRINT("Writing file %s, Offset 0x%I64x\n", FileName, Offset);
- do {
- BytesComplete = write(File, &Offset, 1);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete != 1) {
- PRINT_ERROR("Write failed. Wrote %d of %d bytes: %s.\n",
- BytesComplete,
- FileSize,
- strerror(errno));
- Failures += 1;
- }
- FileState[FileIndex][Offset] = 1;
- DEBUG_PRINT("Flushing file %s\n", FileName);
- Result = fsync(File);
- if (Result < 0) {
- PRINT_ERROR("Flush of %s failed: %s.\n", FileName,
- strerror(errno));
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- //
- // Write the second byte of the file and the last byte and then
- // flush it.
- //
- Offset = 2;
- Result = lseek(File, Offset, SEEK_SET);
- if (Result < 0) {
- PRINT_ERROR("Seek on file %s offset 0x%I64x failed.\n",
- FileName,
- Offset);
- Failures += 1;
- }
- DEBUG_PRINT("Writing file %s, Offset 0x%I64x\n", FileName, Offset);
- do {
- BytesComplete = write(File, &Offset, 1);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete != 1) {
- PRINT_ERROR("Write failed. Wrote %d of %d bytes: %s.\n",
- BytesComplete,
- FileSize,
- strerror(errno));
- Failures += 1;
- }
- FileState[FileIndex][Offset] = 1;
- Offset = FileSize - 1;
- Result = lseek(File, Offset, SEEK_SET);
- if (Result < 0) {
- PRINT_ERROR("Seek on file %s offset 0x%I64x failed.\n",
- FileName,
- Offset);
- Failures += 1;
- }
- DEBUG_PRINT("Writing file %s, Offset 0x%I64x\n", FileName, Offset);
- do {
- BytesComplete = write(File, &Offset, 1);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete != 1) {
- PRINT_ERROR("Write failed. Wrote %d of %d bytes: %s.\n",
- BytesComplete,
- FileSize,
- strerror(errno));
- Failures += 1;
- }
- FileState[FileIndex][Offset] = 1;
- DEBUG_PRINT("Flushing file %s\n", FileName);
- Result = fsync(File);
- if (Result < 0) {
- PRINT_ERROR("Flush of %s failed: %s.\n", FileName,
- strerror(errno));
- Failures += 1;
- goto RunFileUninitializedDataTestEnd;
- }
- //
- // Now read the second byte again. Flushing out the last byte of
- // the file should not have zero'd out the remainder of the first
- // page. This read is here to make sure things are correct.
- //
- Offset = 2;
- Result = lseek(File, Offset, SEEK_SET);
- if (Result < 0) {
- PRINT_ERROR("Seek on file %s offset 0x%I64x failed.\n",
- FileName,
- Offset);
- Failures += 1;
- }
- Value = 0;
- DEBUG_PRINT("Reading file %s, Offset 0x%I64x\n", FileName, Offset);
- do {
- BytesComplete = read(File, &Value, 1);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete < 0) {
- PRINT_ERROR("Read failed. Read %d of 1 bytes: %s.\n",
- BytesComplete,
- strerror(errno));
- Failures += 1;
- break;
- }
- if ((BytesComplete == 1) &&
- (((FileState[FileIndex][Offset] == 0) && (Value != 0)) ||
- ((FileState[FileIndex][Offset] == 1) &&
- (Value != (Offset & 0xFF))))) {
- PRINT_ERROR("Error: initial read of file %s at offset 0x%I64x "
- "turned up %x (should have been %x or 0).\n",
- FileName,
- Offset,
- Value,
- Offset & 0xFF);
- }
- FileState[FileIndex][Offset] = 1;
- if (close(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- }
- }
- //
- // Picks a random spot and writes a byte. Then read a few bytes after
- // that to make sure the expected value is there.
- //
- Offset = rand() % FileSize;
- if ((Offset & 0xFF) == UNINITIALIZED_DATA_PATTERN) {
- Offset += 1;
- }
- DEBUG_PRINT("Writing file %s, Offset 0x%I64x\n", FileName, Offset);
- OpenFlags = O_RDWR | O_CREAT;
- File = open(FileName, OpenFlags, FILE_TEST_CREATE_PERMISSIONS);
- if (File < 0) {
- PRINT_ERROR("Failed to open file %s (flags %x): %s.\n",
- FileName,
- OpenFlags,
- strerror(errno));
- Failures += 1;
- continue;
- }
- ResultOffset = lseek(File, Offset, SEEK_SET);
- if (ResultOffset != Offset) {
- PRINT_ERROR("Seek on file %s offset 0x%I64x failed: got 0x%I64x\n",
- FileName,
- Offset,
- ResultOffset);
- Failures += 1;
- }
- do {
- BytesComplete = write(File, &Offset, 1);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete != 1) {
- PRINT_ERROR("Write failed. Wrote %d of %d bytes: %s.\n",
- BytesComplete,
- FileSize,
- strerror(errno));
- Failures += 1;
- }
- FileState[FileIndex][Offset] = 1;
- //
- // Now seek forward a bit and read.
- //
- Seek = rand() % UNINITIALIZED_DATA_SEEK_MAX;
- Offset = lseek(File, Seek, SEEK_CUR);
- if (Offset == (ULONGLONG)-1) {
- PRINT_ERROR("Seek on file %s failed to seek %d from current.\n",
- FileName,
- Seek);
- Failures += 1;
- }
- //
- // Reads are tricky as the file can be deleted and recreated by
- // other threads. At least validate that if the read succeeded the
- // byte should be zero or the low byte of the offset.
- //
- Value = 0;
- DEBUG_PRINT("Reading file %s, Offset 0x%I64x\n", FileName, Offset);
- do {
- BytesComplete = read(File, &Value, 1);
- } while ((BytesComplete < 0) && (errno == EINTR));
- if (BytesComplete < 0) {
- PRINT_ERROR("Read failed. Read %d of 1 bytes: %s.\n",
- BytesComplete,
- strerror(errno));
- Failures += 1;
- break;
- }
- Expected = 0;
- if (FileState[FileIndex][Offset] != 0) {
- Expected = (Offset & 0xFF);
- }
- if ((BytesComplete == 1) && (Value != Expected)) {
- PRINT_ERROR("Error: Read of file %s at offset 0x%I64x turned up "
- "%x (should have been %x).\n",
- FileName,
- Offset,
- Value,
- Expected);
- }
- if (close(File) != 0) {
- PRINT_ERROR("Failed to close: %s.\n", strerror(errno));
- Failures += 1;
- }
- if ((Iteration % Percent) == 0) {
- PRINT("u");
- }
- }
- //
- // Clean up. Sure, other threads could still be running the test, but they
- // should all clean up too.
- //
- if (FileTestNoCleanup == FALSE) {
- for (FileIndex = 0; FileIndex < FileCount; FileIndex += 1) {
- snprintf(FileName,
- sizeof(FileName),
- "fudt%x-%06x",
- Process & 0xFFFF,
- FileIndex);
- Result = unlink(FileName);
- if ((Result != 0) && (errno != ENOENT)) {
- PRINT_ERROR("Failed to unlink %s: %s.\n",
- FileName,
- strerror(errno));
- Failures += 1;
- }
- }
- }
- PRINT("\n");
- Failures += PrintTestTime(&StartTime);
- RunFileUninitializedDataTestEnd:
- if (FileState != NULL) {
- for (FileIndex = 0; FileIndex < FileCount; FileIndex += 1) {
- if (FileState[FileIndex] != NULL) {
- free(FileState[FileIndex]);
- }
- }
- free(FileState);
- }
- if (UninitializedDataBuffer != NULL) {
- free(UninitializedDataBuffer);
- }
- return Failures;
- }
- ULONG
- PrintTestTime (
- struct timeval *StartTime
- )
- /*++
- Routine Description:
- This routine prints the total time it took to run the test, given the
- starting time of the test.
- Arguments:
- StartTime - Supplies a pointer to the test's start time.
- Return Value:
- Returns the number of failures.
- --*/
- {
- struct timeval EndTime;
- ULONG Failures;
- INT Result;
- struct timeval TotalTime;
- Failures = 0;
- //
- // Record the end time and display the total time, in seconds.
- //
- Result = gettimeofday(&EndTime, NULL);
- if (Result != 0) {
- PRINT_ERROR("Failed to get time of day: %s.\n", strerror(errno));
- Failures += 1;
- goto PrintTestTimeEnd;
- }
- TotalTime.tv_sec = EndTime.tv_sec - StartTime->tv_sec;
- TotalTime.tv_usec = EndTime.tv_usec - StartTime->tv_usec;
- if (TotalTime.tv_usec < 0) {
- TotalTime.tv_sec -= 1;
- TotalTime.tv_usec += 1000000;
- }
- PRINT("Time: %lld.%06d seconds.\n",
- (long long)TotalTime.tv_sec,
- TotalTime.tv_usec);
- PrintTestTimeEnd:
- return Failures;
- }
|