* Target operations per second (aggregate across all threads)
* Interval count (how many times to report results during the run)
* Directory size (number of files per numbered subdirectory)
+ * Read/write block size (0 for the entire file)
*/
#include <errno.h>
#include <unistd.h>
#include <math.h>
-int opt_filesize, opt_filecount, opt_threads, opt_duration, opt_intervals, opt_dirsize;
+int opt_filesize, opt_filecount, opt_threads, opt_duration, opt_intervals, opt_dirsize, opt_blocksize;
double opt_writeratio, opt_ops;
+int write_threads;
+
struct thread_state {
pthread_t thread;
pthread_mutex_t lock;
start = now_hires();
- char filename[256];
- int n = get_random(opt_filecount);
+ /* The space of all files is partitioned evenly based on the number of
+ * threads. Pick a file out of our particular partition. */
+ int thread_num, thread_count;
+ if (ts->thread_num >= write_threads) {
+ /* Read */
+ thread_num = ts->thread_num - write_threads;
+ thread_count = opt_threads - write_threads;
+ } else {
+ /* Write */
+ thread_num = ts->thread_num;
+ thread_count = write_threads;
+ }
+
+ int n = get_random(opt_filecount / thread_count);
+ n += thread_num * (opt_filecount / thread_count);
int n1 = n / opt_dirsize, n2 = n % opt_dirsize;
- sprintf(filename, "t%d/%d/%d", ts->thread_num, n1, n2);
+ char filename[256];
+ sprintf(filename, "%d/%d", n1, n2);
- double r = get_random(1000000) / 1e6;
+ /* If a smaller blocksize was requested, choose a random offset within the
+ * file to use. */
+ int offset = 0;
+ if (opt_blocksize > 0) {
+ offset = get_random(opt_filesize / opt_blocksize) * opt_blocksize;
+ }
- if (r >= opt_writeratio) {
+ if (ts->thread_num >= write_threads) {
/* Read */
FILE *f = fopen(filename, "rb");
if (f == NULL) {
- perror("fopen");
+ fprintf(stderr, "fopen(%s): %m\n", filename);
return;
}
+ if (offset != 0)
+ fseek(f, offset, SEEK_SET);
+
char buf[65536];
- while (fread(buf, 1, sizeof(buf), f) > 0) { }
+ int bytes_left = opt_blocksize > 0 ? opt_blocksize : opt_filesize;
+ while (bytes_left > 0) {
+ size_t read = fread(buf, 1, bytes_left < sizeof(buf)
+ ? bytes_left : sizeof(buf), f);
+ if (ferror(f))
+ return;
+ bytes_left -= read;
+ }
fclose(f);
end = now_hires();
pthread_mutex_unlock(&ts->lock);
} else {
/* Write */
- FILE *f = fopen(filename, "wb");
+ FILE *f = fopen(filename, "r+b");
if (f == NULL) {
- perror("fopen");
+ fprintf(stderr, "fopen(%s): %m\n", filename);
return;
}
+ if (offset != 0)
+ fseek(f, offset, SEEK_SET);
+
char buf[65536];
- int bytes_left = opt_filesize;
+ int bytes_left = opt_blocksize > 0 ? opt_blocksize : opt_filesize;
while (bytes_left > 0) {
size_t written = fwrite(buf, 1,
bytes_left < sizeof(buf)
write_time2 += threads[i].write_time2;
threads[i].read_count = threads[i].write_count = 0;
threads[i].read_time = threads[i].write_time = 0;
+ threads[i].read_time2 = threads[i].write_time2 = 0;
pthread_mutex_unlock(&threads[i].lock);
}
int main(int argc, char *argv[])
{
- if (argc != 9) {
+ if (argc != 10) {
fprintf(stderr, "Usage: TODO\n");
return 1;
}
opt_ops = atof(argv[6]);
opt_intervals = atoi(argv[7]);
opt_dirsize = atoi(argv[8]);
+ opt_blocksize = atoi(argv[9]);
srandom(time(NULL));
start_time = now_hires();
+ /* Partition threads into those that should do reads and those for writes,
+ * as close as possible to the desired allocation. */
+ write_threads = (int)round(opt_threads * opt_writeratio);
+ fprintf(stderr, "Using %d threads for reads, %d for writes\n",
+ opt_threads - write_threads, write_threads);
+
for (int i = 0; i < opt_threads; i++) {
launch_thread(i);
}