#!/bin/bash

###SHELLPACK preamble bonnie-install 1.03e
WEB_LOCATION="http://www.coker.com.au/bonnie++"
MIRROR_LOCATION="$WEBROOT/bonnie"

###SHELLPACK parseargBegin
###SHELLPACK parseargEnd

rm -rf $SHELLPACK_SOURCES/bonnie-${VERSION}
###SHELLPACK sources_fetch bonnie%2B%2B-${VERSION}.tgz bonnie-$VERSION

###SHELLPACK build_start bonnie-$VERSION

# Patch bonnie to support printing detailed IO timings
###SHELLPACK self_extract bonnie-detailed-io-report.patch
patch -p1 <$SHELLPACK_TEMP/bonnie-detailed-io-report.patch || die "Failed to apply detailed IO patch"

###SHELLPACK build_configure bonnie-${VERSION}
###SHELLPACK make_make_install

exit $SHELLPACK_SUCCESS

==== BEGIN bonnie-detailed-io-report.patch ====
diff -rupNX /crypted/home/jack/.kerndiffexclude bonnie++-1.03e/bon_file.cpp bonnie++-1.03e-1-detailwrite/bon_file.cpp
--- bonnie++-1.03e/bon_file.cpp	2008-01-27 05:29:34.000000000 +0100
+++ bonnie++-1.03e-1-detailwrite/bon_file.cpp	2018-05-31 16:05:54.735082471 +0200
@@ -9,10 +9,12 @@
 #endif
 #include <string.h>
 #include <stdlib.h>
+#include <limits.h>
 #include <sys/stat.h>
 
 #include "bon_file.h"
 #include "bon_time.h"
+#include "global.h"
 
 CPCCHAR rand_chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
@@ -251,8 +253,11 @@ int COpenTest::create_a_link(const char
 }
 
 int COpenTest::create(CPCCHAR dirname, BonTimer &timer, int num, int max_size
-                    , int min_size, int num_directories, bool do_random)
+                    , int min_size, int num_directories, bool do_random,
+		    bool detail)
 {
+  UsecTimer optimer;
+
   if(num_directories >= 100000)
   {
     fprintf(stderr, "Can't have more than 99,999 directories.\n");
@@ -313,6 +318,7 @@ int COpenTest::create(CPCCHAR dirname, B
   }
 
   timer.timestamp();
+  optimer.timestamp();
   for(i = 0; i < m_number; i++)
   {
     if(*m_exit)
@@ -344,16 +350,22 @@ int COpenTest::create(CPCCHAR dirname, B
       if(create_a_file(m_file_names[i], m_buf, size, m_dirIndex ? m_dirIndex[i] : 0))
         return -1;
     }
+    if (detail)
+      fprintf(globals.report_log, "%s %llu\n", do_random ? "cr" : "cs", optimer.get_usec_delta_stamp());
   }
   timer.get_delta_t(do_random ? CreateRand : CreateSeq);
   return 0;
 }
 
-int COpenTest::delete_random(BonTimer &timer)
+int COpenTest::delete_random(BonTimer &timer, bool detail)
 {
+  int i;
+  UsecTimer optimer;
+
   random_sort();
   timer.timestamp();
-  int i;
+  optimer.timestamp();
+
   for(i = 0; i < m_number; i++)
   {
     if(unlink(m_file_names[i]))
@@ -369,6 +381,8 @@ int COpenTest::delete_random(BonTimer &t
         m_sync_dir = false;
       }
     }
+    if (detail)
+      fprintf(globals.report_log, "dr %llu\n", optimer.get_usec_delta_stamp());
   }
   if(m_number_directories > 1)
   {
@@ -405,8 +419,10 @@ int COpenTest::delete_random(BonTimer &t
   return 0;
 }
 
-int COpenTest::delete_sequential(BonTimer &timer)
+int COpenTest::delete_sequential(BonTimer &timer, bool detail)
 {
+  UsecTimer optimer;
+
   timer.timestamp();
   int count = 0;
   for(int i = 0; i < m_number_directories; i++)
@@ -454,6 +470,7 @@ int COpenTest::delete_sequential(BonTime
     }
     dirent *file_ent;
 
+    optimer.timestamp();
     while((file_ent = readdir(d)) != NULL)
     {
       if(file_ent->d_name[0] != '.')
@@ -474,6 +491,8 @@ int COpenTest::delete_sequential(BonTime
           }
         }
         count++;
+        if (detail)
+          fprintf(globals.report_log, "ds %llu\n", optimer.get_usec_delta_stamp());
       }
     }
     closedir(d);
@@ -555,25 +574,33 @@ int COpenTest::stat_file(CPCCHAR file)
   return 0;
 }
 
-int COpenTest::stat_random(BonTimer &timer)
+int COpenTest::stat_random(BonTimer &timer, bool detail)
 {
+  UsecTimer optimer;
+
   random_sort();
   timer.timestamp();
+  optimer.timestamp();
 
   int i;
   for(i = 0; i < m_number; i++)
   {
     if(-1 == stat_file(m_file_names[i]))
       return -1;
+    if (detail)
+      fprintf(globals.report_log, "sr %llu\n", optimer.get_usec_delta_stamp());
   }
   timer.get_delta_t(StatRand);
   return 0;
 }
 
-int COpenTest::stat_sequential(BonTimer &timer)
+int COpenTest::stat_sequential(BonTimer &timer, bool detail)
 {
-  timer.timestamp();
+  UsecTimer optimer;
   int count = 0;
+
+  timer.timestamp();
+
   for(int i = 0; i < m_number_directories; i++)
   {
     char buf[6];
@@ -638,6 +665,7 @@ int COpenTest::stat_sequential(BonTimer
       return -1;
     }
     dirent *file_ent;
+    optimer.timestamp();
     while((file_ent = readdir(d)) != NULL)
     {
       if(*m_exit)
@@ -661,6 +689,8 @@ int COpenTest::stat_sequential(BonTimer
           return -1;
         }
         count++;
+        if (detail)
+          fprintf(globals.report_log, "ss %llu\n", optimer.get_usec_delta_stamp());
       }
     }
     closedir(d);
diff -rupNX /crypted/home/jack/.kerndiffexclude bonnie++-1.03e/bon_file.h bonnie++-1.03e-1-detailwrite/bon_file.h
--- bonnie++-1.03e/bon_file.h	2001-01-01 03:50:24.000000000 +0100
+++ bonnie++-1.03e-1-detailwrite/bon_file.h	2018-03-07 14:42:45.016801454 +0100
@@ -13,11 +13,12 @@ public:
   ~COpenTest();
 
   int create(CPCCHAR dirname, BonTimer &timer, int num, int max_size
-                    , int min_size, int num_directories, bool do_random);
-  int delete_random(BonTimer &timer);
-  int delete_sequential(BonTimer &timer);
-  int stat_random(BonTimer &timer);
-  int stat_sequential(BonTimer &timer);
+                    , int min_size, int num_directories, bool do_random,
+                    bool detail);
+  int delete_random(BonTimer &timer, bool detail);
+  int delete_sequential(BonTimer &timer, bool detail);
+  int stat_random(BonTimer &timer, bool detail);
+  int stat_sequential(BonTimer &timer, bool detail);
 
 private:
   void make_names(bool do_random);
diff -rupNX /crypted/home/jack/.kerndiffexclude bonnie++-1.03e/bon_io.cpp bonnie++-1.03e-1-detailwrite/bon_io.cpp
--- bonnie++-1.03e/bon_io.cpp	2008-09-26 05:19:38.000000000 +0200
+++ bonnie++-1.03e-1-detailwrite/bon_io.cpp	2018-06-01 16:12:06.380747970 +0200
@@ -17,6 +17,7 @@
 #include "bon_io.h"
 #include "semaphore.h"
 #include "bon_time.h"
+#include "global.h"
 
 #include "forkit.h"
 
@@ -46,21 +47,34 @@ void seeker(Fork *f, PVOID param, int)
   char ticket;
   int rc;
   int lseek_count = 0;
+  char report_buf[32];
+  int report_fd = fileno(globals.report_log);
+  UsecTimer optimer;
 
   rc = f->Read(&ticket, 1, 0);
 
   file->getTimer().timestamp();
   seeker_report.StartTime = file->getTimer().get_cur_time();
 
+  optimer.timestamp();
   if(rc == 1 && ticket) do
   {
     bool update;
+
     if( (lseek_count++ % UpdateSeek) == 0)
       update = true;
     else
       update = false;
     if(file->doseek(rand() % num_chunks, update) )
       exit(1);
+    if (!(lseek_count % globals.report_interval)) {
+      /*
+       * This happens in parallel from different processes. Avoid C buffered
+       * IO to scramble the output.
+       */
+      sprintf(report_buf, "sk %llu\n", optimer.get_usec_delta_stamp());
+      write(report_fd, report_buf, strlen(report_buf));
+    }
   }
   while((rc = f->Read(&ticket, 1, 0)) == 1 && ticket);
 
@@ -78,7 +92,7 @@ void seeker(Fork *f, PVOID param, int)
   }
 }
 
-int CFileOp::seek_test(bool quiet, Semaphore &s)
+int CFileOp::seek_test()
 {
   char   seek_tickets[SeekProcCount + Seeks];
   int next;
@@ -90,9 +104,9 @@ int CFileOp::seek_test(bool quiet, Semap
   f.go(seeker, this, SeekProcCount);
 
   sleep(5);
-  if(s.decrement_and_wait(Lseek))
+  if(globals.sem.decrement_and_wait(Lseek))
     return 1;
-  if(!quiet) fprintf(stderr, "start 'em...");
+  if(!globals.quiet) fprintf(stderr, "start 'em...");
   if(f.Write(seek_tickets, sizeof(seek_tickets)) != int(sizeof(seek_tickets)) )
   {
     fprintf(stderr, "Can't write tickets.\n");
@@ -125,9 +139,9 @@ int CFileOp::seek_test(bool quiet, Semap
     if(wait(&status) == -1)
 #endif
       return io_error("wait");
-    if(!quiet) fprintf(stderr, "done...");
+    if(!globals.quiet) fprintf(stderr, "done...");
   } /* for each child */
-  if(!quiet) fprintf(stderr, "\n");
+  if(!globals.quiet) fprintf(stderr, "\n");
   return 0;
 }
 
diff -rupNX /crypted/home/jack/.kerndiffexclude bonnie++-1.03e/bon_io.h bonnie++-1.03e-1-detailwrite/bon_io.h
--- bonnie++-1.03e/bon_io.h	2008-09-26 05:19:38.000000000 +0200
+++ bonnie++-1.03e-1-detailwrite/bon_io.h	2018-03-08 18:06:17.805375244 +0100
@@ -1,6 +1,8 @@
 #ifndef BON_FILE
 #define BON_FILE
 
+#include <limits.h>
+
 #include "bonnie.h"
 class Semaphore;
 class BonTimer;
@@ -17,7 +19,7 @@ public:
   int read_block(PVOID buf);
   int seek(int offset, int whence);
   int doseek(long where, bool update);
-  int seek_test(bool quiet, Semaphore &s);
+  int seek_test();
   void close();
   // reopen a file, bools for whether the file should be unlink()'d and
   // creat()'d and for whether fopen should be used
diff -rupNX /crypted/home/jack/.kerndiffexclude bonnie++-1.03e/bonnie++.cpp bonnie++-1.03e-1-detailwrite/bonnie++.cpp
--- bonnie++-1.03e/bonnie++.cpp	2008-09-26 05:19:38.000000000 +0200
+++ bonnie++-1.03e-1-detailwrite/bonnie++.cpp	2018-06-01 18:10:11.285334638 +0200
@@ -41,6 +41,7 @@
 #include <string.h>
 #include <sys/utsname.h>
 #include <signal.h>
+#include "global.h"
 
 #ifdef AIX_MEM_SIZE
 #include <cf.h>
@@ -50,76 +51,13 @@
 
 void usage();
 
-class CGlobalItems
-{
-public:
-  bool quiet;
-  bool fast;
-  bool sync_bonnie;
-  bool use_direct_io;
-  BonTimer timer;
-  int ram;
-  Semaphore sem;
-  char *name;
-  bool bufSync;
-  int  chunk_bits;
-  int chunk_size() const { return m_chunk_size; }
-  bool *doExit;
-  void set_chunk_size(int size)
-    { delete m_buf; pa_new(size, m_buf, m_buf_pa); m_chunk_size = size; }
-
-  // Return the page-aligned version of the local buffer
-  char *buf() { return m_buf_pa; }
-
-  CGlobalItems(bool *exitFlag);
-  ~CGlobalItems() { delete name; delete m_buf; }
-
-  void decrement_and_wait(int nr_sem);
-
-  void SetName(CPCCHAR path)
-  {
-    delete name;
-    name = new char[strlen(path) + 15];
-#ifdef OS2
-    ULONG myPid = 0;
-    DosQuerySysInfo(QSV_FOREGROUND_PROCESS, QSV_FOREGROUND_PROCESS
-                  , &myPid, sizeof(myPid));
-#else
-    pid_t myPid = getpid();
-#endif
-    sprintf(name, "%s/Bonnie.%d", path, int(myPid));
-  }
-private:
-  int m_chunk_size;
-  char *m_buf;     // Pointer to the entire buffer
-  char *m_buf_pa;  // Pointer to the page-aligned version of the same buffer
-
-  CGlobalItems(const CGlobalItems &f);
-  CGlobalItems & operator =(const CGlobalItems &f);
-
-  // Implement a page-aligned version of new.
-  // 'p' is the pointer created
-  // 'page_aligned_p' is the page-aligned pointer created
-  void pa_new(unsigned int num_bytes, char *&p, char *&page_aligned_p)
-  {
-#ifdef NON_UNIX
-    SYSTEM_INFO system_info;
-    GetSystemInfo(&system_info);
-    long page_size = system_info.dwPageSize;
-#else
-    int page_size = getpagesize();
-#endif
-    p = ::new char [num_bytes + page_size];
-
-    page_aligned_p = (char *)((((unsigned long)p + page_size - 1) / page_size) * page_size);
-  }
-};
-
 CGlobalItems::CGlobalItems(bool *exitFlag)
  : quiet(false)
  , fast(false)
  , sync_bonnie(false)
  , use_direct_io(false)
+ , report_interval(UINT_MAX)
+ , report_log(stdout)
  , timer()
  , ram(0)
  , sem(SemKey, TestCount)
@@ -142,11 +80,12 @@ void CGlobalItems::decrement_and_wait(in
 }
 
 int TestDirOps(int directory_size, int max_size, int min_size
-             , int num_directories, CGlobalItems &globals);
-int TestFileOps(int file_size, CGlobalItems &globals);
+             , int num_directories);
+int TestFileOps(int file_size);
 
 static bool exitNow;
 static bool already_printed_error;
+CGlobalItems globals(&exitNow);
 
 #ifdef USE_SA_SIGACTION
 #define SIGNAL_NUMBER siginf->si_signo
@@ -181,7 +120,6 @@ int main(int argc, char *argv[])
   int    count = -1;
   const char * machine = NULL;
   char *userName = NULL, *groupName = NULL;
-  CGlobalItems globals(&exitNow);
   bool setSize = false;
 
   exitNow = false;
@@ -235,7 +173,7 @@ int main(int argc, char *argv[])
 #endif
 
   int int_c;
-  while(-1 != (int_c = getopt(argc, argv, "bd:fg:m:n:p:qr:s:u:x:yD")) )
+  while(-1 != (int_c = getopt(argc, argv, "bd:fg:m:n:p:qr:s:u:x:yDR:l:")) )
   {
     switch(char(int_c))
     {
@@ -329,6 +267,16 @@ int main(int argc, char *argv[])
                         /* open file descriptor with direct I/O */
         globals.use_direct_io = true;
       break;
+      case 'R':
+	globals.report_interval = strtol(optarg, NULL, 10);
+      break;
+      case 'l':
+        globals.report_log = fopen(optarg, "a");
+        if (!globals.report_log) {
+          fprintf(stderr, "Cannot open log file\n");
+          usage();
+        }
+      break;
     }
   }
   if(optind < argc)
@@ -425,10 +373,10 @@ int main(int argc, char *argv[])
   {
     globals.timer.Initialize();
     int rc;
-    rc = TestFileOps(file_size, globals);
+    rc = TestFileOps(file_size);
     if(rc) return rc;
     rc = TestDirOps(directory_size, directory_max_size, directory_min_size
-                  , num_directories, globals);
+                  , num_directories);
     if(rc) return rc;
     // if we are only doing one test run then print a plain-text version of
     // the results before printing a csv version.
@@ -450,7 +398,7 @@ int main(int argc, char *argv[])
 }
 
 int
-TestFileOps(int file_size, CGlobalItems &globals)
+TestFileOps(int file_size)
 {
   if(file_size)
   {
@@ -460,6 +408,7 @@ TestFileOps(int file_size, CGlobalItems
     char  *buf = globals.buf();
     int    bufindex;
     int    i;
+    UsecTimer optimer;
 
     if(globals.ram && file_size < globals.ram * 2)
     {
@@ -482,6 +431,7 @@ TestFileOps(int file_size, CGlobalItems
     if(!globals.fast)
     {
       globals.decrement_and_wait(Putc);
+      optimer.timestamp();
       // Fill up a file, writing it a char at a time with the stdio putc() call
       if(!globals.quiet) fprintf(stderr, "Writing with putc()...");
       for(words = 0; words < num_chunks; words++)
@@ -490,6 +440,8 @@ TestFileOps(int file_size, CGlobalItems
           return 1;
         if(exitNow)
           return EXIT_CTRL_C;
+        if (!((words+1) % globals.report_interval))
+          fprintf(globals.report_log, "pc %llu\n", optimer.get_usec_delta_stamp());
       }
       fflush(NULL);
       /*
@@ -507,6 +459,7 @@ TestFileOps(int file_size, CGlobalItems
     if(!globals.quiet) fprintf(stderr, "Writing intelligently...");
     memset(buf, 0, globals.chunk_size());
     globals.timer.timestamp();
+    optimer.timestamp();
     bufindex = 0;
     // for the number of chunks of file data
     for(i = 0; i < num_chunks; i++)
@@ -518,6 +471,8 @@ TestFileOps(int file_size, CGlobalItems
       bufindex = (bufindex + 1) % globals.chunk_size();
       if(file.write_block(PVOID(buf)) == -1)
         return io_error("write(2)");
+      if (!((i+1) % globals.report_interval))
+        fprintf(globals.report_log, "wr %llu\n", optimer.get_usec_delta_stamp());
     }
     file.close();
     globals.timer.get_delta_t(FastWrite);
@@ -535,6 +490,7 @@ TestFileOps(int file_size, CGlobalItems
     globals.decrement_and_wait(ReWrite);
     if(!globals.quiet) fprintf(stderr, "Rewriting...");
     globals.timer.timestamp();
+    optimer.timestamp();
     bufindex = 0;
     for(words = 0; words < num_chunks; words++)
     { // for each chunk in the file
@@ -549,6 +505,8 @@ TestFileOps(int file_size, CGlobalItems
         return io_error("re write(2)");
       if(exitNow)
         return EXIT_CTRL_C;
+      if (!((words+1) % globals.report_interval))
+        fprintf(globals.report_log, "rw %llu\n", optimer.get_usec_delta_stamp());
     }
     file.close();
     globals.timer.get_delta_t(ReWrite);
@@ -563,6 +521,7 @@ TestFileOps(int file_size, CGlobalItems
       globals.decrement_and_wait(Getc);
       if(!globals.quiet) fprintf(stderr, "Reading with getc()...");
       globals.timer.timestamp();
+      optimer.timestamp();
 
       for(words = 0; words < num_chunks; words++)
       {
@@ -570,6 +529,8 @@ TestFileOps(int file_size, CGlobalItems
           return 1;
         if(exitNow)
           return EXIT_CTRL_C;
+        if (!((words+1) % globals.report_interval))
+          fprintf(globals.report_log, "gc %llu\n", optimer.get_usec_delta_stamp());
       }
 
       file.close();
@@ -585,19 +546,27 @@ TestFileOps(int file_size, CGlobalItems
     globals.decrement_and_wait(FastRead);
     if(!globals.quiet) fprintf(stderr, "Reading intelligently...");
     globals.timer.timestamp();
+    optimer.timestamp();
     for(i = 0; i < num_chunks; i++)
     { /* per block */
       if ((words = file.read_block(PVOID(buf))) == -1)
         return io_error("read(2)");
       if(exitNow)
         return EXIT_CTRL_C;
+      if (!((i+1) % globals.report_interval))
+        fprintf(globals.report_log, "rd %llu\n", optimer.get_usec_delta_stamp());
     } /* per block */
     file.close();
     globals.timer.get_delta_t(FastRead);
     if(!globals.quiet) fprintf(stderr, "done\n");
+    /*
+     * Flush report_log, seek test is going to append from different
+     * processes.
+     */
+    fflush(globals.report_log);
 
     globals.timer.timestamp();
-    if(file.seek_test(globals.quiet, globals.sem))
+    if(file.seek_test())
       return 1;
 
     /*
@@ -623,7 +592,7 @@ TestFileOps(int file_size, CGlobalItems
 
 int
 TestDirOps(int directory_size, int max_size, int min_size
-         , int num_directories, CGlobalItems &globals)
+         , int num_directories)
 {
   COpenTest open_test(globals.chunk_size(), globals.bufSync, globals.doExit);
   if(!directory_size)
@@ -653,30 +622,32 @@ TestDirOps(int directory_size, int max_s
   globals.decrement_and_wait(CreateSeq);
   if(!globals.quiet) fprintf(stderr, "Create files in sequential order...");
   if(open_test.create(globals.name, globals.timer, directory_size
-                    , max_size, min_size, num_directories, false))
+                    , max_size, min_size, num_directories, false,
+                    globals.report_interval != UINT_MAX))
     return 1;
   globals.decrement_and_wait(StatSeq);
   if(!globals.quiet) fprintf(stderr, "done.\nStat files in sequential order...");
-  if(open_test.stat_sequential(globals.timer))
+  if(open_test.stat_sequential(globals.timer, globals.report_interval != UINT_MAX))
     return 1;
   globals.decrement_and_wait(DelSeq);
   if(!globals.quiet) fprintf(stderr, "done.\nDelete files in sequential order...");
-  if(open_test.delete_sequential(globals.timer))
+  if(open_test.delete_sequential(globals.timer, globals.report_interval != UINT_MAX))
     return 1;
   if(!globals.quiet) fprintf(stderr, "done.\n");
 
   globals.decrement_and_wait(CreateRand);
   if(!globals.quiet) fprintf(stderr, "Create files in random order...");
   if(open_test.create(globals.name, globals.timer, directory_size
-                    , max_size, min_size, num_directories, true))
+                    , max_size, min_size, num_directories, true,
+                    globals.report_interval != UINT_MAX))
     return 1;
   globals.decrement_and_wait(StatRand);
   if(!globals.quiet) fprintf(stderr, "done.\nStat files in random order...");
-  if(open_test.stat_random(globals.timer))
+  if(open_test.stat_random(globals.timer, globals.report_interval != UINT_MAX))
     return 1;
   globals.decrement_and_wait(DelRand);
   if(!globals.quiet) fprintf(stderr, "done.\nDelete files in random order...");
-  if(open_test.delete_random(globals.timer))
+  if(open_test.delete_random(globals.timer, globals.report_interval != UINT_MAX))
     return 1;
   if(!globals.quiet) fprintf(stderr, "done.\n");
   return 0;
@@ -691,7 +662,8 @@ usage()
     "                [-m machine-name]\n"
     "                [-r ram-size-in-MiB]\n"
     "                [-x number-of-tests] [-u uid-to-use:gid-to-use] [-g gid-to-use]\n"
-    "                [-q] [-f] [-b] [-D] [-p processes | -y]\n"
+    "                [-q] [-f] [-b] [-D] [-p processes | -y] [-R report-interval]\n"
+    "                [-l log-file]\n"
     "\nVersion: " BON_VERSION "\n");
   exit(1);
 }
diff -rupNX /crypted/home/jack/.kerndiffexclude bonnie++-1.03e/bon_time.cpp bonnie++-1.03e-1-detailwrite/bon_time.cpp
--- bonnie++-1.03e/bon_time.cpp	2003-01-08 23:39:12.000000000 +0100
+++ bonnie++-1.03e-1-detailwrite/bon_time.cpp	2018-03-07 16:59:39.635634403 +0100
@@ -404,3 +404,21 @@ BonTimer::DoReport(CPCCHAR machine, int
   return 0;
 }
 
+void UsecTimer::timestamp(void)
+{
+  if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
+    io_error("clock_gettime", true);
+}
+
+unsigned long long UsecTimer::get_usec_delta_stamp(void)
+{
+  struct timespec cur;
+  unsigned long long ret;
+
+  if (clock_gettime(CLOCK_MONOTONIC, &cur) < 0)
+    io_error("clock_gettime", true);
+  ret = ((unsigned long long)(cur.tv_sec - ts.tv_sec))*1000000 +
+	(cur.tv_nsec - ts.tv_nsec) / 1000;
+  ts = cur;
+  return ret;
+}
diff -rupNX /crypted/home/jack/.kerndiffexclude bonnie++-1.03e/bon_time.h bonnie++-1.03e-1-detailwrite/bon_time.h
--- bonnie++-1.03e/bon_time.h	2001-04-16 19:01:39.000000000 +0200
+++ bonnie++-1.03e-1-detailwrite/bon_time.h	2018-03-07 16:59:27.675660388 +0100
@@ -58,4 +58,12 @@ private:
   BonTimer &operator=(const BonTimer&);
 };
 
+class UsecTimer {
+public:
+  void timestamp();
+  unsigned long long get_usec_delta_stamp();
+private:
+  struct timespec ts;
+};
+
 #endif
diff -rupNX /crypted/home/jack/.kerndiffexclude bonnie++-1.03e/global.h bonnie++-1.03e-1-detailwrite/global.h
--- bonnie++-1.03e/global.h	1970-01-01 01:00:00.000000000 +0100
+++ bonnie++-1.03e-1-detailwrite/global.h	2018-03-08 18:10:11.229613894 +0100
@@ -0,0 +1,70 @@
+#include "semaphore.h"
+
+class CGlobalItems
+{
+public:
+  bool quiet;
+  bool fast;
+  bool sync_bonnie;
+  bool use_direct_io;
+  unsigned int report_interval;
+  FILE *report_log;
+  BonTimer timer;
+  int ram;
+  Semaphore sem;
+  char *name;
+  bool bufSync;
+  int  chunk_bits;
+  int chunk_size() const { return m_chunk_size; }
+  bool *doExit;
+  void set_chunk_size(int size)
+    { delete m_buf; pa_new(size, m_buf, m_buf_pa); m_chunk_size = size; }
+
+  // Return the page-aligned version of the local buffer
+  char *buf() { return m_buf_pa; }
+
+  CGlobalItems(bool *exitFlag);
+  ~CGlobalItems() { delete name; delete m_buf; }
+
+  void decrement_and_wait(int nr_sem);
+
+  void SetName(CPCCHAR path)
+  {
+    delete name;
+    name = new char[strlen(path) + 15];
+#ifdef OS2
+    ULONG myPid = 0;
+    DosQuerySysInfo(QSV_FOREGROUND_PROCESS, QSV_FOREGROUND_PROCESS
+                  , &myPid, sizeof(myPid));
+#else
+    pid_t myPid = getpid();
+#endif
+    sprintf(name, "%s/Bonnie.%d", path, int(myPid));
+  }
+private:
+  int m_chunk_size;
+  char *m_buf;     // Pointer to the entire buffer
+  char *m_buf_pa;  // Pointer to the page-aligned version of the same buffer
+
+  CGlobalItems(const CGlobalItems &f);
+  CGlobalItems & operator =(const CGlobalItems &f);
+
+  // Implement a page-aligned version of new.
+  // 'p' is the pointer created
+  // 'page_aligned_p' is the page-aligned pointer created
+  void pa_new(unsigned int num_bytes, char *&p, char *&page_aligned_p)
+  {
+#ifdef NON_UNIX
+    SYSTEM_INFO system_info;
+    GetSystemInfo(&system_info);
+    long page_size = system_info.dwPageSize;
+#else
+    int page_size = getpagesize();
+#endif
+    p = ::new char [num_bytes + page_size];
+
+    page_aligned_p = (char *)((((unsigned long)p + page_size - 1) / page_size) * page_size);
+  }
+};
+
+extern CGlobalItems globals;
diff -rupNX /crypted/home/jack/.kerndiffexclude bonnie++-1.03e/Makefile bonnie++-1.03e-1-detailwrite/Makefile
--- bonnie++-1.03e/Makefile	2016-12-01 17:55:29.071498135 +0100
+++ bonnie++-1.03e-1-detailwrite/Makefile	2018-03-07 17:07:10.094115352 +0100
@@ -8,7 +8,7 @@ prefix=/usr/local
 eprefix=${prefix}
 #MORE_WARNINGS=-Weffc++ -Wcast-align
 WFLAGS=-Wall -W -Wshadow -Wpointer-arith -Wwrite-strings -pedantic -ffor-scope $(MORE_WARNINGS)
-CFLAGS=-O2  -DNDEBUG $(WFLAGS) $(MORECFLAGS)
+CFLAGS=-O2 -std=c++11 -DNDEBUG $(WFLAGS) $(MORECFLAGS)
 CXX=g++ $(CFLAGS)
 
 INSTALL=/usr/bin/install -c
diff -rupNX /crypted/home/jack/.kerndiffexclude bonnie++-1.03e/Makefile.in bonnie++-1.03e-1-detailwrite/Makefile.in
--- bonnie++-1.03e/Makefile.in	2002-10-13 22:26:36.000000000 +0200
+++ bonnie++-1.03e-1-detailwrite/Makefile.in	2018-03-07 17:18:28.905020099 +0100
@@ -8,7 +8,7 @@ prefix=@prefix@
 eprefix=@exec_prefix@
 #MORE_WARNINGS=-Weffc++ -Wcast-align
 WFLAGS=-Wall -W -Wshadow -Wpointer-arith -Wwrite-strings -pedantic -ffor-scope $(MORE_WARNINGS)
-CFLAGS=-O2 @debug@ -DNDEBUG $(WFLAGS) $(MORECFLAGS)
+CFLAGS=-O2 @debug@ -DNDEBUG -std=c++11 $(WFLAGS) $(MORECFLAGS)
 CXX=@CXX@ $(CFLAGS)
 
 INSTALL=@INSTALL@
==== END bonnie-detailed-io-report.patch ====
