#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;
}