A few more updates to the mixed read/write microbenchmark.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Mon, 7 Feb 2011 18:02:04 +0000 (10:02 -0800)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Mon, 7 Feb 2011 18:02:04 +0000 (10:02 -0800)
microbench/CMakeLists.txt
microbench/mixedbench.c

index 33b4bd7..5a6a45f 100644 (file)
@@ -8,7 +8,7 @@ add_executable(statbench statbench.c)
 target_link_libraries(statbench pthread rt)
 
 add_executable(mixedbench mixedbench.c)
-target_link_libraries(mixedbench pthread rt)
+target_link_libraries(mixedbench pthread rt m)
 
 add_executable(lockmem lockmem.c)
 
index ae26e71..81e63cf 100644 (file)
@@ -8,6 +8,7 @@
  *   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;
@@ -38,6 +40,18 @@ 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;
@@ -68,28 +82,6 @@ void sleep_micros(int duration)
         ;
 }
 
-#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;
@@ -116,7 +108,8 @@ void benchmark_op(struct thread_state *ts)
         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 */
@@ -142,7 +135,8 @@ void benchmark_op(struct thread_state *ts)
         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);
     }
 }
@@ -151,9 +145,16 @@ void *benchmark_thread(void *arg)
 {
     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;
@@ -164,7 +165,6 @@ void launch_thread(int i)
     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);
@@ -177,10 +177,10 @@ void wait_thread(int n)
     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);
@@ -188,23 +188,27 @@ void reset_stats(int print)
         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;
     }
@@ -214,11 +218,11 @@ int main(int argc, char *argv[])
     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);
@@ -226,7 +230,7 @@ int main(int argc, char *argv[])
 
     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;