* Copyright 2002-2008, Axel DΓΆrfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
arbitrary bytes at arbitrary positions of a file previously created.
The idea is to be able to calculate the contents on each position
of the file. It currently only counts numbers, beginning from zero,
which is probably not a really good test.
But if there is a bug, it would be very likely to show up after some
thousand (or even million) runs.
Works only on little-endian processors, such as x86 (or else the partial
read numbers wouldn't be correctly compared).
Use the --help option to see how it's used.
*/
#include <File.h>
#include <StorageDefs.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define FILE_NAME "RANDOM_READ_TEST_FILE"
#define FILE_SIZE (1024 * 1024)
#define BUFFER_SIZE (64 * 1024)
#define NUMBER_OF_LOOPS 1000
#define MAX_FAULTS 10
typedef uint32 test_t;
void
createFile(const char *name, size_t size)
{
BFile file;
status_t status = file.SetTo(name,
B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
if (status < B_OK) {
fprintf(stderr, "Could not create test file: %s!\n", strerror(status));
return;
}
test_t max = size / sizeof(test_t);
for (uint32 i = 0; i < max; i++) {
if (file.Write(&i, sizeof(test_t)) != sizeof(test_t)) {
fprintf(stderr,"Could not create the whole test file!\n");
break;
}
}
}
void
readTest(const char *name, int32 loops)
{
BFile file;
status_t status = file.SetTo(name, B_READ_ONLY);
if (status < B_OK) {
fprintf(stderr, "Could not open test file! Run \"randomread create "
"[size]\" first.\n"
"This will create a file named \"%s\" in the current directory.\n",
name);
return;
}
off_t size;
if ((status = file.GetSize(&size)) < B_OK) {
fprintf(stderr, "Could not get file size: %s!\n", strerror(status));
return;
}
char *buffer = (char *)malloc(BUFFER_SIZE);
if (buffer == NULL) {
fprintf(stderr, "no memory to create read buffer.\n");
return;
}
srand(time(NULL));
int32 faults = 0;
for (int32 i = 0; i < loops; i++) {
off_t pos = rand() % size;
int32 bytes = (rand() % BUFFER_SIZE) + 4;
off_t max = size - pos;
if (max > bytes)
max = bytes;
else
bytes = max;
ssize_t bytesRead = file.ReadAt(pos, buffer, bytes);
if (bytesRead < B_OK) {
printf(" Could not read %ld bytes at offset %lld: %s\n",
bytes, pos, strerror(bytesRead));
} else if (bytesRead != max) {
printf(" Could only read %ld bytes instead of %ld at offset %lld\n",
bytesRead, bytes, pos);
}
off_t bufferPos = pos;
test_t num = bufferPos / sizeof(test_t);
int32 partial = bufferPos % sizeof(test_t);
if (partial) {
test_t read = *(test_t *)(buffer - partial);
bool correct;
switch (partial) {
case 1:
correct = (num & 0xffffff00) == (read & 0xffffff00);
break;
case 2:
correct = (num & 0xffff0000) == (read & 0xffff0000);
break;
case 3:
correct = (num & 0xff000000) == (read & 0xff000000);
break;
}
if (!correct) {
printf("[%lld,%ld] Bytes at %lld don't match (partial begin = "
"%ld, should be %08lx, is %08lx)!\n", pos, bytes,
bufferPos, partial, num, read);
faults++;
}
bufferPos += sizeof(test_t) - partial;
}
num++;
test_t *numBuffer = (test_t *)(buffer + sizeof(test_t) - partial);
for (; bufferPos < bytesRead - sizeof(test_t);
bufferPos += sizeof(test_t)) {
if (faults > MAX_FAULTS) {
printf("maximum number of faults reached, bail out.\n");
return;
}
if (num != *numBuffer) {
printf("[%lld,%ld] Bytes at %lld don't match (should be %08lx, "
"is %08lx)!\n", pos, bytes, bufferPos, num, *numBuffer);
faults++;
}
num++;
numBuffer++;
}
partial = bytesRead - bufferPos;
if (partial > 0) {
uint32 read = *numBuffer;
bool correct;
switch (partial) {
case 1:
correct = (num & 0x00ffffff) == (read & 0x00ffffff);
break;
case 2:
correct = (num & 0x0000ffff) == (read & 0x0000ffff);
break;
case 3:
correct = (num & 0x000000ff) == (read & 0x000000ff);
break;
}
if (!correct) {
printf("[%lld,%ld] Bytes at %lld don't match (partial end = "
"%ld, should be %08lx, is %08lx)!\n", pos, bytes,
bufferPos, partial, num, read);
faults++;
}
}
}
}
int
main(int argc, char **argv)
{
size_t size = FILE_SIZE;
int32 loops = NUMBER_OF_LOOPS;
bool create = false;
if (argv[1]) {
if (!strcmp(argv[1], "create")) {
create = true;
if (argv[2])
size = atol(argv[2]);
}
else if (isdigit(*argv[1]))
loops = atol(argv[1]);
else {
char *filename = strrchr(argv[0], '/')
? strrchr(argv[0] , '/') + 1 : argv[0];
printf("You can either create a test file or perform the test.\n"
" Create:\t%s create [filesize]\n"
" Test: \t%s [loops]\n\n"
"Default size = %d, loops = %d\n",
filename, filename, FILE_SIZE, NUMBER_OF_LOOPS);
return 0;
}
}
if (size == 0) {
fprintf(stderr, "%s: given file size too small, set to 1 MB.\n",
argv[0]);
size = FILE_SIZE;
}
if (create)
createFile(FILE_NAME, size);
else
readTest(FILE_NAME, loops);
return 0;
}