1 /* 2 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /*! Tests if the read functions of a file system work correctly by reading 7 arbitrary bytes at arbitrary positions of a file previously created. 8 9 The idea is to be able to calculate the contents on each position 10 of the file. It currently only counts numbers, beginning from zero, 11 which is probably not a really good test. 12 But if there is a bug, it would be very likely to show up after some 13 thousand (or even million) runs. 14 15 Works only on little-endian processors, such as x86 (or else the partial 16 read numbers wouldn't be correctly compared). 17 18 Use the --help option to see how it's used. 19 */ 20 21 #include <File.h> 22 #include <StorageDefs.h> 23 24 #include <stdlib.h> 25 #include <stdio.h> 26 #include <string.h> 27 #include <ctype.h> 28 29 #define FILE_NAME "RANDOM_READ_TEST_FILE" 30 #define FILE_SIZE (1024 * 1024) 31 #define BUFFER_SIZE (64 * 1024) 32 #define NUMBER_OF_LOOPS 1000 33 #define MAX_FAULTS 10 34 35 // currently only works with 4 byte values! 36 typedef uint32 test_t; 37 38 39 void 40 createFile(const char *name, size_t size) 41 { 42 BFile file; 43 status_t status = file.SetTo(name, 44 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 45 if (status < B_OK) { 46 fprintf(stderr, "Could not create test file: %s!\n", strerror(status)); 47 return; 48 } 49 50 test_t max = size / sizeof(test_t); 51 for (uint32 i = 0; i < max; i++) { 52 if (file.Write(&i, sizeof(test_t)) != sizeof(test_t)) { 53 fprintf(stderr,"Could not create the whole test file!\n"); 54 break; 55 } 56 } 57 } 58 59 60 void 61 readTest(const char *name, int32 loops) 62 { 63 BFile file; 64 status_t status = file.SetTo(name, B_READ_ONLY); 65 if (status < B_OK) { 66 fprintf(stderr, "Could not open test file! Run \"randomread create " 67 "[size]\" first.\n" 68 "This will create a file named \"%s\" in the current directory.\n", 69 name); 70 return; 71 } 72 73 off_t size; 74 if ((status = file.GetSize(&size)) < B_OK) { 75 fprintf(stderr, "Could not get file size: %s!\n", strerror(status)); 76 return; 77 } 78 79 char *buffer = (char *)malloc(BUFFER_SIZE); 80 if (buffer == NULL) { 81 fprintf(stderr, "no memory to create read buffer.\n"); 82 return; 83 } 84 srand(time(NULL)); 85 int32 faults = 0; 86 87 for (int32 i = 0; i < loops; i++) { 88 off_t pos = rand() % size; 89 // we are lazy tester, minimum read size is 4 bytes 90 int32 bytes = (rand() % BUFFER_SIZE) + 4; 91 off_t max = size - pos; 92 if (max > bytes) 93 max = bytes; 94 else 95 bytes = max; 96 97 ssize_t bytesRead = file.ReadAt(pos, buffer, bytes); 98 if (bytesRead < B_OK) { 99 printf(" Could not read %ld bytes at offset %lld: %s\n", 100 bytes, pos, strerror(bytesRead)); 101 } else if (bytesRead != max) { 102 printf(" Could only read %ld bytes instead of %ld at offset %lld\n", 103 bytesRead, bytes, pos); 104 } 105 106 // test contents 107 108 off_t bufferPos = pos; 109 test_t num = bufferPos / sizeof(test_t); 110 111 // check leading partial number 112 int32 partial = bufferPos % sizeof(test_t); 113 if (partial) { 114 test_t read = *(test_t *)(buffer - partial); 115 bool correct; 116 switch (partial) { 117 // byteorder little-endian 118 case 1: 119 correct = (num & 0xffffff00) == (read & 0xffffff00); 120 break; 121 case 2: 122 correct = (num & 0xffff0000) == (read & 0xffff0000); 123 break; 124 case 3: 125 correct = (num & 0xff000000) == (read & 0xff000000); 126 break; 127 } 128 if (!correct) { 129 printf("[%lld,%ld] Bytes at %lld don't match (partial begin = " 130 "%ld, should be %08lx, is %08lx)!\n", pos, bytes, 131 bufferPos, partial, num, read); 132 faults++; 133 } 134 bufferPos += sizeof(test_t) - partial; 135 } 136 num++; 137 test_t *numBuffer = (test_t *)(buffer + sizeof(test_t) - partial); 138 139 // test full numbers 140 for (; bufferPos < bytesRead - sizeof(test_t); 141 bufferPos += sizeof(test_t)) { 142 if (faults > MAX_FAULTS) { 143 printf("maximum number of faults reached, bail out.\n"); 144 return; 145 } 146 if (num != *numBuffer) { 147 printf("[%lld,%ld] Bytes at %lld don't match (should be %08lx, " 148 "is %08lx)!\n", pos, bytes, bufferPos, num, *numBuffer); 149 faults++; 150 } 151 num++; 152 numBuffer++; 153 } 154 155 // test last partial number 156 partial = bytesRead - bufferPos; 157 if (partial > 0) { 158 uint32 read = *numBuffer; 159 bool correct; 160 switch (partial) { 161 // byteorder little-endian 162 case 1: 163 correct = (num & 0x00ffffff) == (read & 0x00ffffff); 164 break; 165 case 2: 166 correct = (num & 0x0000ffff) == (read & 0x0000ffff); 167 break; 168 case 3: 169 correct = (num & 0x000000ff) == (read & 0x000000ff); 170 break; 171 } 172 if (!correct) { 173 printf("[%lld,%ld] Bytes at %lld don't match (partial end = " 174 "%ld, should be %08lx, is %08lx)!\n", pos, bytes, 175 bufferPos, partial, num, read); 176 faults++; 177 } 178 } 179 } 180 } 181 182 183 int 184 main(int argc, char **argv) 185 { 186 size_t size = FILE_SIZE; 187 int32 loops = NUMBER_OF_LOOPS; 188 bool create = false; 189 190 if (argv[1]) { 191 if (!strcmp(argv[1], "create")) { 192 create = true; 193 if (argv[2]) 194 size = atol(argv[2]); 195 } 196 else if (isdigit(*argv[1])) 197 loops = atol(argv[1]); 198 else { 199 // get a nice filename of the program 200 char *filename = strrchr(argv[0], '/') 201 ? strrchr(argv[0] , '/') + 1 : argv[0]; 202 203 printf("You can either create a test file or perform the test.\n" 204 " Create:\t%s create [filesize]\n" 205 " Test: \t%s [loops]\n\n" 206 "Default size = %d, loops = %d\n", 207 filename, filename, FILE_SIZE, NUMBER_OF_LOOPS); 208 209 return 0; 210 } 211 } 212 213 if (size == 0) { 214 fprintf(stderr, "%s: given file size too small, set to 1 MB.\n", 215 argv[0]); 216 size = FILE_SIZE; 217 } 218 219 if (create) 220 createFile(FILE_NAME, size); 221 else 222 readTest(FILE_NAME, loops); 223 224 return 0; 225 } 226