[dbench @ cvs-1:tridge-20070622101840-jlcfy1gphxfo0ts3]
authortridge <tridge@blu>
Fri, 22 Jun 2007 10:18:40 +0000 (10:18 +0000)
committertridge <tridge@blu>
Fri, 22 Jun 2007 10:18:40 +0000 (10:18 +0000)
added support for rate limiting, numeric status codes and timed operations

child.c
dbench.c
dbench.h
fileio.c
io.c
proto.h
sockio.c
util.c

diff --git a/child.c b/child.c
index b710dede8a79d80cd94bb1a04d07ca285b43be8a..807cc05df75f3d0569be86ca9d89e9eade9eb259 100644 (file)
--- a/child.c
+++ b/child.c
@@ -37,20 +37,30 @@ void child_run(struct child_struct *child, const char *loadfile)
        int i;
        char line[1024];
        char *cname;
-       char params[20][100];
+       char **sparams, **params;
        char *p;
        const char *status;
        char *fname = NULL;
        char *fname2 = NULL;
        FILE *f = fopen(loadfile, "r");
        pid_t parent = getppid();
+       extern double targetrate;
 
        child->line = 0;
 
        asprintf(&cname,"client%d", child->id);
 
+       sparams = calloc(20, sizeof(char *));
+       for (i=0;i<20;i++) {
+               sparams[i] = malloc(100);
+       }
+
 again:
+       nb_time_reset(child);
+
        while (fgets(line, sizeof(line)-1, f)) {
+               params = sparams;
+
                if (child->done || kill(parent, 0) == -1) {
                        goto done;
                }
@@ -77,7 +87,19 @@ again:
                        exit(1);
                }
 
-               if (strncmp(params[i-1], "NT_STATUS_", 10) != 0) {
+               if (i > 0 && isdigit(params[0][0])) {
+                       double targett = strtod(params[0], NULL);
+                       if (targetrate != 0) {
+                               nb_target_rate(child, targetrate);
+                       } else {
+                               nb_time_delay(child, targett);
+                       }
+                       params++;
+                       i--;
+               }
+
+               if (strncmp(params[i-1], "NT_STATUS_", 10) != 0 &&
+                   strncmp(params[i-1], "0x", 2) != 0) {
                        printf("Badly formed status at line %d\n", child->line);
                        continue;
                }
index c9cd3769b7d95f42a5a597d99a79e32400386339..25ada63c12852116280544b4ae7112f144ba4de0 100644 (file)
--- a/dbench.c
+++ b/dbench.c
@@ -34,6 +34,7 @@ static char *loadfile = DATADIR "/client.txt";
 static struct timeval tv_start;
 static struct timeval tv_end;
 static int barrier=-1;
+double targetrate;
 
 #if HAVE_EA_SUPPORT
 int ea_enable=0;
@@ -250,6 +251,7 @@ static void show_usage(void)
               "  -t timelimit     run time in seconds (default 600)\n" \
               "  -D directory     base directory to run in\n" \
               "  -c loadfile      set location of the loadfile\n" \
+              "  -R               target rate (MByte/sec)\n" \
               "  -s               synchronous file IO\n" \
               "  -S               synchronous directories (mkdir, unlink...)\n" \
               "  -x               enable EA support\n" \
@@ -265,8 +267,10 @@ static int process_opts(int argc, char **argv,
        int c;
        extern int sync_open;
        extern char *server;
+       
+       targetrate = 0;
 
-       while ((c = getopt(argc, argv, "vc:sST:t:xD:")) != -1) 
+       while ((c = getopt(argc, argv, "vc:sST:t:xD:R:")) != -1) 
                switch (c) {
                case 'c':
                        loadfile = optarg;
@@ -289,7 +293,11 @@ static int process_opts(int argc, char **argv,
                case 'v':
                        exit(0);
                        break;
+               case 'R':
+                       targetrate = strtod(optarg, NULL);
+                       break;
                case 'x':
+
 #if HAVE_EA_SUPPORT
                        ea_enable = 1;
 #else
index 4e1bb9023b66dffbfea9b31f5c9769ef905cc9b3..370a6cc10575a0dbb67da315b826c78af2b77b9d 100644 (file)
--- a/dbench.h
+++ b/dbench.h
@@ -102,6 +102,8 @@ struct child_struct {
        const char *directory;
        double bytes;
        double bytes_done_warmup;
+       double max_latency;
+       struct timeval starttime;
 };
 
 
index 989ce471c38fc586b2f63daf41c5347e2afa8934..dd9c7a07d7fdf038b09f3b19564a3936fa505364 100644 (file)
--- a/fileio.c
+++ b/fileio.c
@@ -31,6 +31,44 @@ static struct {
        int handle;
 } ftable[MAX_FILES];
 
+void nb_target_rate(struct child_struct *child, double rate)
+{
+       static double last_bytes;
+       static struct timeval last_time;
+       double tdelay;
+
+       if (last_bytes == 0) {
+               last_bytes = child->bytes;
+               last_time = timeval_current();
+               return;
+       }
+
+       tdelay = (child->bytes - last_bytes)/(1.0e6*rate) - timeval_elapsed(&last_time);
+       if (tdelay > 0) {
+               msleep(tdelay*1000);
+       } else {
+               child->max_latency = MAX(child->max_latency, -tdelay);
+       }
+
+       last_time = timeval_current();
+       last_bytes = child->bytes;
+}
+
+void nb_time_reset(struct child_struct *child)
+{
+       child->starttime = timeval_current();   
+}
+
+void nb_time_delay(struct child_struct *child, double targett)
+{
+       double elapsed = timeval_elapsed(&child->starttime);
+       if (targett > elapsed) {
+               msleep(1000*(targett - elapsed));
+       } else if (elapsed - targett > child->max_latency) {
+               child->max_latency = MAX(elapsed - targett, child->max_latency);
+       }
+}
+
 static int find_handle(struct child_struct *child, int handle)
 {
        int i;
@@ -139,7 +177,8 @@ static void xattr_fd_write_hook(int fd)
 
 static int expected_status(const char *status)
 {
-       if (strcmp(status, "NT_STATUS_OK") == 0) return 0;
+       if (strcmp(status, "NT_STATUS_OK") == 0 ||
+           strtoul(status, NULL, 16) == 0) return 0;
        return -1;
 }
 
@@ -154,6 +193,8 @@ static void resolve_name(const char *name)
        char *p;
        struct dirent *d;
 
+       if (name == NULL) return;
+
        if (stat(name, &st) == 0) {
                xattr_fname_read_hook(name);
                return;
@@ -252,14 +293,18 @@ void nb_createx(struct child_struct *child, const char *fname,
        if (create_options & FILE_DIRECTORY_FILE) flags = O_RDONLY|O_DIRECTORY;
 
        fd = open(fname, flags, 0600);
+       if (fd == -1 && errno == EISDIR) {
+               flags = O_RDONLY|O_DIRECTORY;
+               fd = open(fname, flags, 0600);
+       }
        if (fd == -1) {
-               if (strcmp(status, "NT_STATUS_OK") == 0) {
+               if (expected_status(status) == 0) {
                        printf("(%d) open %s failed for handle %d (%s)\n", 
                               child->line, fname, fnum, strerror(errno));
                }
                return;
        }
-       if (strcmp(status, "NT_STATUS_OK") != 0) {
+       if (expected_status(status) != 0) {
                printf("(%d) open %s succeeded for handle %d\n", 
                       child->line, fname, fnum);
                close(fd);
@@ -289,11 +334,29 @@ void nb_writex(struct child_struct *child, int handle, int offset,
 {
        int i = find_handle(child, handle);
        void *buf;
+       struct stat st;
 
        (void)status;
 
        buf = calloc(size, 1);
 
+       if (size == 1 && fstat(ftable[i].fd, &st) == 0) {
+               if (st.st_size > offset) {
+                       unsigned char c;
+                       pread(ftable[i].fd, &c, 1, offset);
+                       if (c == ((unsigned char *)buf)[0]) {
+                               free(buf);
+                               child->bytes += size;
+                               return;
+                       }
+               } else if (((unsigned char *)buf)[0] == 0) {
+                       ftruncate(ftable[i].fd, offset+1);
+                       free(buf);
+                       child->bytes += size;
+                       return;
+               } 
+       }
+
        if (pwrite(ftable[i].fd, buf, size, offset) != ret_size) {
                printf("write failed on handle %d (%s)\n", handle, strerror(errno));
                exit(1);
diff --git a/io.c b/io.c
index 30a92a8021d06cc24f43fc03f4e242296e1d44ed..4d2bf7d1db43d1c4a56b7833c773beec3e80ff20 100644 (file)
--- a/io.c
+++ b/io.c
@@ -206,3 +206,5 @@ void do_create(char *fname, int size)
        do_open(fname, 5000, size);
        do_close(5000);
 }
+
+
diff --git a/proto.h b/proto.h
index 905496db40abce49ec36736f1aa5f5da7fcc7253..157c30a4f84f11c97e2e01d62f0a4da86c51ee4f 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -13,6 +13,9 @@ void child_run(struct child_struct *child, const char *loadfile);
 
 /* The following definitions come from fileio.c  */
 
+void nb_target_rate(struct child_struct *child, double rate);
+void nb_time_reset(struct child_struct *child);
+void nb_time_delay(struct child_struct *child, double targett);
 void nb_setup(struct child_struct *child);
 void nb_unlink(struct child_struct *child, char *fname, int attr, const char *status);
 void nb_mkdir(struct child_struct *child, char *dname, const char *status);
@@ -56,6 +59,9 @@ void do_rename(char *old, char *new);
 void do_stat(char *fname, int size);
 void do_create(char *fname, int size);
 
+/* The following definitions come from snprintf.c  */
+
+
 /* The following definitions come from sockio.c  */
 
 void nb_setup(struct child_struct *child);
@@ -112,5 +118,6 @@ BOOL next_token(char **ptr,char *buff,char *sep);
 struct timeval timeval_current(void);
 double timeval_elapsed(struct timeval *tv);
 double timeval_elapsed2(struct timeval *tv1, struct timeval *tv2);
+void msleep(unsigned int t);
 
 #endif /*  _PROTO_H_  */
index 062b15986947480c39f88f37b7e9cb5bafff6eed..54b4aa5839d2ea563501dab324aabd8f128fa15e 100644 (file)
--- a/sockio.c
+++ b/sockio.c
@@ -78,6 +78,45 @@ void nb_setup(struct child_struct *child)
        do_packets(8, 8);
 }
 
+
+void nb_target_rate(struct child_struct *child, double rate)
+{
+       static double last_bytes;
+       static struct timeval last_time;
+       double tdelay;
+
+       if (last_bytes == 0) {
+               last_bytes = child->bytes;
+               last_time = timeval_current();
+               return;
+       }
+
+       tdelay = (child->bytes - last_bytes)/(1.0e6*rate) - timeval_elapsed(&last_time);
+       if (tdelay > 0) {
+               msleep(tdelay*1000);
+       } else {
+               child->max_latency = MAX(child->max_latency, -tdelay);
+       }
+
+       last_time = timeval_current();
+       last_bytes = child->bytes;
+}
+
+void nb_time_reset(struct child_struct *child)
+{
+       child->starttime = timeval_current();   
+}
+
+void nb_time_delay(struct child_struct *child, double targett)
+{
+       double elapsed = timeval_elapsed(&child->starttime);
+       if (targett > elapsed) {
+               msleep(1000*(targett - elapsed));
+       } else if (elapsed - targett > child->max_latency) {
+               child->max_latency = MAX(elapsed - targett, child->max_latency);
+       }
+}
+
 void nb_unlink(struct child_struct *child, char *fname, int attr, const char *status)
 {
        (void)child;
diff --git a/util.c b/util.c
index 543a8cd79984cae4f5cd2814e82eecb33fe7f9b5..102cc720c45f4effb6e40bcfe2c497e2ee0ef951 100644 (file)
--- a/util.c
+++ b/util.c
@@ -164,3 +164,18 @@ double timeval_elapsed2(struct timeval *tv1, struct timeval *tv2)
                (tv2->tv_usec - tv1->tv_usec)*1.0e-6;
 }
 
+
+
+/**
+ Sleep for a specified number of milliseconds.
+**/
+void msleep(unsigned int t)
+{
+       struct timeval tval;  
+
+       tval.tv_sec = t/1000;
+       tval.tv_usec = 1000*(t%1000);
+       /* this should be the real select - do NOT replace
+          with sys_select() */
+       select(0,NULL,NULL,NULL,&tval);
+}