* Write fraction (0.0 - 1.0)
* Threads
* Benchmark duration (seconds)
+ * Target operations per second (aggregate across all threads)
*/
#include <errno.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
+#include <math.h>
int opt_filesize, opt_filecount, opt_threads, opt_duration;
-double opt_writeratio;
+double opt_writeratio, opt_ops;
struct thread_state {
pthread_t thread;
pthread_mutex_t lock;
int thread_num;
int read_count, write_count;
- int64_t read_time, write_time;
+ double read_time, write_time, read_time2, write_time2;
};
static int64_t start_time;
#define MAX_THREADS 128
struct thread_state threads[MAX_THREADS];
+static double sq(double x)
+{
+ return x * x;
+}
+
+static double stddev(double x, double x2, int n)
+{
+ if (n < 2)
+ return 0;
+ return sqrt((x2 / n - sq(x / n)) * n / (n - 1));
+}
+
int64_t now_hires()
{
struct timespec time;
;
}
-#if 0
-void bench_write()
-{
- FILE *f = fopen("writetest", "wb");
- if (f == NULL) {
- perror("fopen");
- return;
- }
-
- char buf[4096];
- for (int i = 0; i < 16; i++) {
- int64_t start, end;
- start = now_hires();
- rewind(f);
- fwrite(buf, 1, sizeof(buf), f);
- fflush(f);
- end = now_hires();
- printf("Pass %d: Time = %"PRIi64"\n", i, end - start);
- }
-}
-#endif
-
void benchmark_op(struct thread_state *ts)
{
int64_t start, end;
end = now_hires();
pthread_mutex_lock(&ts->lock);
ts->read_count++;
- ts->read_time += (end - start);
+ ts->read_time += (end - start) / 1e9;
+ ts->read_time2 += sq((end - start) / 1e9);
pthread_mutex_unlock(&ts->lock);
} else {
/* Write */
end = now_hires();
pthread_mutex_lock(&ts->lock);
ts->write_count++;
- ts->write_time += (end - start);
+ ts->write_time += (end - start) / 1e9;
+ ts->write_time2 += sq((end - start) / 1e9);
pthread_mutex_unlock(&ts->lock);
}
}
{
struct thread_state *ts = (struct thread_state *)arg;
+ int target_delay = (opt_threads / opt_ops) * 1e6;
+
while (1) {
+ int64_t start = now_hires();
benchmark_op(ts);
- //sleep_micros(100000);
+ int64_t end = now_hires();
+
+ int elapsed = (end - start) / 1000;
+ if (elapsed < target_delay)
+ sleep_micros(target_delay - elapsed);
}
return NULL;
memset(&threads[i], 0, sizeof(struct thread_state));
threads[i].thread_num = i;
pthread_mutex_init(&threads[i].lock, NULL);
- printf("Launching thread %d...\n", i);
if (pthread_create(&threads[i].thread, NULL, benchmark_thread, &threads[i]) != 0) {
fprintf(stderr, "Error launching thread!\n");
exit(1);
pthread_join(threads[n].thread, &result);
}
-void reset_stats(int print)
+void reset_stats(int print, double duration)
{
int read_count = 0, write_count = 0;
- int64_t read_time = 0, write_time = 0;
+ double read_time = 0, write_time = 0, read_time2 = 0, write_time2 = 0;
for (int i = 0; i < opt_threads; i++) {
pthread_mutex_lock(&threads[i].lock);
write_count += threads[i].write_count;
read_time += threads[i].read_time;
write_time += threads[i].write_time;
+ read_time2 += threads[i].read_time2;
+ write_time2 += threads[i].write_time2;
threads[i].read_count = threads[i].write_count = 0;
threads[i].read_time = threads[i].write_time = 0;
pthread_mutex_unlock(&threads[i].lock);
}
if (print) {
- printf("read: [%d, %f]\n",
- read_count, read_time / 1e9 / read_count);
- printf("write: [%d, %f]\n",
- write_count, write_time / 1e9 / write_count);
+ printf("read: [%g, %f, %f]\n",
+ read_count / duration, read_time / read_count,
+ stddev(read_time, read_time2, read_count));
+ printf("write: [%g, %f, %f]\n",
+ write_count / duration, write_time / write_count,
+ stddev(write_time, write_time2, write_count));
printf("\n");
}
}
int main(int argc, char *argv[])
{
- if (argc != 6) {
+ if (argc != 7) {
fprintf(stderr, "Usage: TODO\n");
return 1;
}
opt_writeratio = atof(argv[3]);
opt_threads = atoi(argv[4]);
opt_duration = atoi(argv[5]);
+ opt_ops = atof(argv[6]);
srandom(time(NULL));
start_time = now_hires();
- printf("Testing with %d threads\n", opt_threads);
for (int i = 0; i < opt_threads; i++) {
launch_thread(i);
for (int i = 0; i < 4; i++) {
sleep_micros(opt_duration * 1000000 / 4);
- reset_stats(1);
+ reset_stats(1, opt_duration / 4.0);
}
return 0;