Merge branch 'master' of ssh://router/data/git/fio
authorJens Axboe <axboe@suse.de>
Fri, 2 Jun 2006 08:53:49 +0000 (10:53 +0200)
committerJens Axboe <axboe@suse.de>
Fri, 2 Jun 2006 08:53:49 +0000 (10:53 +0200)
Conflicts:

fio.h

1  2 
README
fio-ini.c
fio.c
fio.h

diff --combined README
index b4e007c6e8dff67ae06fb496c183acb5ad61c09b,d6e266ad6370788ae877dc514387f975ba7c42e1..7ecac863756128c231415e0f22581a00e7280081
--- 1/README
--- 2/README
+++ b/README
@@@ -41,13 -41,6 +41,13 @@@ The <jobs> format is as follows
        directory=x     Use 'x' as the top level directory for storing files
        rw=x            'x' may be: read, randread, write, randwrite,
                        rw (read-write mix), randrw (read-write random mix)
 +      rwmixcycle=x    Base cycle for switching between read and write
 +                      in msecs.
 +      rwmixread=x     'x' percentage of rw mix ios will be reads. If
 +                      rwmixwrite is also given, the last of the two will
 +                       be used if they don't add up to 100%.
 +      rwmixwrite=x    'x' percentage of rw mix ios will be writes. See
 +                      rwmixread.
        size=x          Set file size to x bytes (x string can include k/m/g)
        ioengine=x      'x' may be: aio/libaio/linuxaio for Linux aio,
                        posixaio for POSIX aio, sync for regular read/write io,
                        rw, offset, length
                        where with rw=0/1 for read/write, and the offset
                        and length entries being in bytes.
+       write_iolog=x   Write an iolog to file 'x' in the same format as iolog.
+                       The iolog options are exclusive, if both given the
+                       read iolog will be performed.
        lockmem=x       Lock down x amount of memory on the machine, to
                        simulate a machine with less memory available. x can
                        include k/m/g suffix.
 +      nice=x          Run job at given nice value.
  
  Examples using a job file
  -------------------------
diff --combined fio-ini.c
index 38d60a2d7dcff820af84989d2e8511f625d38762,d51503519ff709875ebb56cb210a671ad118de59..73cebf220d5f761c6797993b402a556f4af0ca27
+++ b/fio-ini.c
@@@ -36,9 -36,6 +36,9 @@@
  #define DEF_FILE_SIZE         (1024 * 1024 * 1024UL)
  #define DEF_ZONE_SIZE         (0)
  #define DEF_ZONE_SKIP         (0)
 +#define DEF_RWMIX_CYCLE               (500)
 +#define DEF_RWMIX_READ                (50)
 +#define DEF_NICE              (0)
  
  static char fio_version_string[] = "fio 1.3";
  
@@@ -285,7 -282,7 +285,7 @@@ err
  
  int init_random_state(struct thread_data *td)
  {
 -      unsigned long seed;
 +      unsigned long seeds[4];
        int fd, num_maps, blocks;
  
        fd = open("/dev/urandom", O_RDONLY);
                return 1;
        }
  
 -      if (read(fd, &seed, sizeof(seed)) < (int) sizeof(seed)) {
 +      if (read(fd, seeds, sizeof(seeds)) < (int) sizeof(seeds)) {
                td_verror(td, EIO);
                close(fd);
                return 1;
  
        close(fd);
  
 -      srand48_r(seed, &td->bsrange_state);
 -      srand48_r(seed, &td->verify_state);
 +      srand48_r(seeds[0], &td->bsrange_state);
 +      srand48_r(seeds[1], &td->verify_state);
 +      srand48_r(seeds[2], &td->rwmix_state);
  
        if (td->sequential)
                return 0;
  
        if (repeatable)
 -              seed = DEF_RANDSEED;
 +              seeds[3] = DEF_RANDSEED;
  
        blocks = (td->io_size + td->min_bs - 1) / td->min_bs;
        num_maps = blocks / BLOCKS_PER_MAP;
        td->num_maps = num_maps;
        memset(td->file_map, 0, num_maps * sizeof(long));
  
 -      srand48_r(seed, &td->random_state);
 +      srand48_r(seeds[3], &td->random_state);
        return 0;
  }
  
@@@ -406,8 -402,12 +406,12 @@@ typedef int (str_cb_fn)(struct thread_d
  
  static int check_str(char *p, char *name, str_cb_fn *cb, struct thread_data *td)
  {
-       char *s = strstr(p, name);
+       char *s;
  
+       if (strncmp(p, name, strlen(name)))
+               return 1;
+       s = strstr(p, name);
        if (!s)
                return 1;
  
  
  static int check_strstore(char *p, char *name, char *dest)
  {
-       char *s = strstr(p, name);
+       char *s;
  
+       if (strncmp(p, name, strlen(name)))
+               return 1;
+       s = strstr(p, name);
        if (!s)
                return 1;
  
@@@ -458,6 -462,9 +466,9 @@@ static int check_range(char *p, char *n
        char option[128];
        char *str, *p1, *p2;
  
+       if (strncmp(p, name, strlen(name)))
+               return 1;
        strcpy(option, p);
        p = option;
  
@@@ -638,13 -645,12 +649,12 @@@ static int str_ioengine_cb(struct threa
  static int str_iolog_cb(struct thread_data *td, char *file)
  {
        strncpy(td->iolog_file, file, sizeof(td->iolog_file) - 1);
        return 0;
  }
  
  int parse_jobs_ini(char *file)
  {
 -      unsigned int prioclass, prio, cpu, global;
 +      unsigned int prioclass, prio, cpu, global, il;
        unsigned long long ull;
        unsigned long ul1, ul2;
        struct thread_data *td;
                                fgetpos(f, &off);
                                continue;
                        }
 +                      if (!check_int(p, "rwmixcycle", &td->rwmixcycle)) {
 +                              fgetpos(f, &off);
 +                              continue;
 +                      }
 +                      if (!check_int(p, "rwmixread", &il)) {
 +                              if (il > 100)
 +                                      il = 100;
 +                              td->rwmixread = il;
 +                              fgetpos(f, &off);
 +                              continue;
 +                      }
 +                      if (!check_int(p, "rwmixwrite", &il)) {
 +                              if (il > 100)
 +                                      il = 100;
 +                              td->rwmixread = 100 - il;
 +                              fgetpos(f, &off);
 +                              continue;
 +                      }
 +                      if (!check_int(p, "nice", &td->nice)) {
 +                              fgetpos(f, &off);
 +                              continue;
 +                      }
                        if (!check_range(p, "bsrange", &ul1, &ul2)) {
                                if (ul1 > ul2) {
                                        td->max_bs = ul1;
                                continue;
                        }
                        if (!check_str(p, "iolog", str_iolog_cb, td)) {
-                               td->iolog = 1;
+                               printf("got read iolog\n");
+                               td->read_iolog = 1;
+                               td->write_iolog = 0;
+                               fgetpos(f, &off);
+                               continue;
+                       }
+                       if (!td->read_iolog &&
+                           !check_str(p, "write_iolog", str_iolog_cb, td)) {
+                               printf("got write iolog\n");
+                               td->write_iolog = 1;
                                fgetpos(f, &off);
                                continue;
                        }
@@@ -940,9 -933,6 +959,9 @@@ static int fill_def_thread(void
        def_thread.stonewall = DEF_STONEWALL;
        def_thread.numjobs = DEF_NUMJOBS;
        def_thread.use_thread = DEF_USE_THREAD;
 +      def_thread.rwmixcycle = DEF_RWMIX_CYCLE;
 +      def_thread.rwmixread = DEF_RWMIX_READ;
 +      def_thread.nice = DEF_NICE;
  #ifdef FIO_HAVE_DISK_UTIL
        def_thread.do_disk_util = 1;
  #endif
diff --combined fio.c
index 571971d381d32bb2dbd72845c7c35b4fe6485805,695d754976e8c82fa7ae4edc323a505b057ff9ad..04496ea6399c206795f5a733722aee250ec1cc7a
--- 1/fio.c
--- 2/fio.c
+++ b/fio.c
@@@ -545,32 -545,44 +545,32 @@@ static void fill_md5(struct verify_head
        memcpy(hdr->md5_digest, md5_ctx.hash, sizeof(md5_ctx.hash));
  }
  
 -unsigned int hweight32(unsigned int w)
 -{
 -      unsigned int res = w - ((w >> 1) & 0x55555555);
 -
 -      res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
 -      res = (res + (res >> 4)) & 0x0F0F0F0F;
 -      res = res + (res >> 8);
 -
 -      return (res + (res >> 16)) & 0x000000FF;
 -}
 -
 -unsigned long hweight64(unsigned long long w)
 +static int get_rw_ddir(struct thread_data *td)
  {
 -#if __WORDSIZE == 32
 -        return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
 -#elif __WORDSIZE == 64
 -      unsigned long long v = w - ((w >> 1) & 0x5555555555555555ul);
 +      if (td_rw(td)) {
 +              struct timeval now;
 +              unsigned long elapsed;
  
 -      v = (v & 0x3333333333333333ul) + ((v >> 2) & 0x3333333333333333ul);
 -      v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
 -      v = v + (v >> 8);
 -      v = v + (v >> 16);
 +              gettimeofday(&now, NULL);
 +              elapsed = mtime_since_now(&td->rwmix_switch);
  
 -      return (v + (v >> 32)) & 0x00000000000000FFul;
 -#else
 -#error __WORDSIZE not defined
 -#endif
 -}
 +              /*
 +               * Check if it's time to seed a new data direction.
 +               */
 +              if (elapsed >= td->rwmixcycle) {
 +                      unsigned long v;
 +                      long r;
  
 -static int get_rw_ddir(struct thread_data *td)
 -{
 -      /*
 -       * perhaps cheasy, but use the hamming weight of the position
 -       * as a randomizer for data direction.
 -       */
 -      if (td_rw(td))
 -              return hweight64(td->last_pos) & 1;
 -      else if (td_read(td))
 +                      lrand48_r(&td->random_state, &r);
 +                      v = 100UL * r / (unsigned long) (RAND_MAX + 1.0);
 +                      if (v < td->rwmixread)
 +                              td->rwmix_ddir = DDIR_READ;
 +                      else
 +                              td->rwmix_ddir = DDIR_WRITE;
 +                      memcpy(&td->rwmix_switch, &now, sizeof(now));
 +              }
 +              return td->rwmix_ddir;
 +      } else if (td_read(td))
                return DDIR_READ;
        else
                return DDIR_WRITE;
@@@ -616,17 -628,16 +616,16 @@@ void put_io_u(struct thread_data *td, s
        td->cur_depth--;
  }
  
- static int fill_io_u(struct thread_data *td, struct io_u *io_u)
+ static void write_iolog_put(struct thread_data *td, struct io_u *io_u)
  {
-       /*
-        * If using an iolog, grab next piece if any available.
-        */
-       if (td->iolog) {
-               struct io_piece *ipo;
+       fprintf(td->iolog_f, "%d,%llu,%u\n", io_u->ddir, io_u->offset, io_u->buflen);
+ }
  
-               if (list_empty(&td->io_log_list))
-                       return 1;
+ static int read_iolog_get(struct thread_data *td, struct io_u *io_u)
+ {
+       struct io_piece *ipo;
  
+       if (!list_empty(&td->io_log_list)) {
                ipo = list_entry(td->io_log_list.next, struct io_piece, list);
                list_del(&ipo->list);
                io_u->offset = ipo->offset;
                return 0;
        }
  
+       return 1;
+ }
+ static int fill_io_u(struct thread_data *td, struct io_u *io_u)
+ {
+       /*
+        * If using an iolog, grab next piece if any available.
+        */
+       if (td->read_iolog)
+               return read_iolog_get(td, io_u);
        /*
         * No log, let the seq/rand engine retrieve the next position.
         */
  
                if (io_u->buflen) {
                        io_u->ddir = get_rw_ddir(td);
+                       /*
+                        * If using a write iolog, store this entry.
+                        */
+                       if (td->write_iolog)
+                               write_iolog_put(td, io_u);
                        return 0;
                }
        }
@@@ -695,7 -724,7 +712,7 @@@ static struct io_u *get_io_u(struct thr
                return NULL;
        }
  
-       if (!td->iolog && !td->sequential)
+       if (!td->read_iolog && !td->sequential)
                mark_random_map(td, io_u);
  
        td->last_pos += io_u->buflen;
@@@ -783,6 -812,13 +800,13 @@@ static void log_io_piece(struct thread_
        list_add(&ipo->list, entry);
  }
  
+ static void write_iolog_close(struct thread_data *td)
+ {
+       fflush(td->iolog_f);
+       fclose(td->iolog_f);
+       free(td->iolog_buf);
+ }
  static int init_iolog(struct thread_data *td)
  {
        unsigned long long offset;
        FILE *f;
        int rw, i, reads, writes;
  
-       if (!td->iolog)
+       if (!td->read_iolog && !td->write_iolog)
                return 0;
  
-       f = fopen(td->iolog_file, "r");
+       if (td->read_iolog)
+               f = fopen(td->iolog_file, "r");
+       else
+               f = fopen(td->iolog_file, "w");
        if (!f) {
                perror("fopen iolog");
+               printf("file %s, %d/%d\n", td->iolog_file, td->read_iolog, td->write_iolog);
                return 1;
        }
  
+       /*
+        * That's it for writing, setup a log buffer and we're done.
+         */
+       if (td->write_iolog) {
+               td->iolog_f = f;
+               td->iolog_buf = malloc(8192);
+               setvbuf(f, td->iolog_buf, _IOFBF, 8192);
+               return 0;
+       }
+       /*
+        * Read in the read iolog and store it, reuse the infrastructure
+        * for doing verifications.
+        */
        str = malloc(4096);
        reads = writes = i = 0;
        while ((p = fgets(str, 4096, f)) != NULL) {
@@@ -1786,6 -1841,7 +1829,6 @@@ static void update_rusage_stat(struct t
  static void *thread_main(void *data)
  {
        struct thread_data *td = data;
 -      int ret = 1;
  
        if (!td->use_thread)
                setsid();
                }
        }
  
 +      if (nice(td->nice) < 0) {
 +              td_verror(td, errno);
 +              goto err;
 +      }
 +
        if (init_random_state(td))
                goto err;
  
        td_set_runstate(td, TD_INITIALIZED);
        sem_post(&startup_sem);
        sem_wait(&td->mutex);
+       ret = 0;
  
        if (!td->create_serialize && setup_file(td))
                goto err;
                finish_log(td, td->slat_log, "slat");
        if (td->clat_log)
                finish_log(td, td->clat_log, "clat");
+       if (td->write_iolog)
+               write_iolog_close(td);
  
        if (exitall_on_terminate)
                terminate_threads(td->groupid);
@@@ -1890,6 -1944,10 +1936,6 @@@ err
                munmap(td->mmap, td->file_size);
        cleanup_io(td);
        cleanup_io_u(td);
 -      if (ret) {
 -              sem_post(&startup_sem);
 -              sem_wait(&td->mutex);
 -      }
        td_set_runstate(td, TD_EXITED);
        return NULL;
  
@@@ -2384,14 -2442,11 +2430,14 @@@ static void run_threads(void
                                td = map[i];
                                if (!td)
                                        continue;
 -                              if (td->runstate == TD_INITIALIZED ||
 -                                  td->runstate >= TD_EXITED) {
 +                              if (td->runstate == TD_INITIALIZED) {
                                        map[i] = NULL;
                                        left--;
 -                                      continue;
 +                              } else if (td->runstate >= TD_EXITED) {
 +                                      map[i] = NULL;
 +                                      left--;
 +                                      todo--;
 +                                      nr_running++; /* work-around... */
                                }
                        }
                }
                }
  
                /*
 -               * start created threads (TD_INITIALIZED -> TD_RUNNING)
 +               * start created threads (TD_INITIALIZED -> TD_RUNNING).
                 */
                printf("fio: Go for launch\n");
                for (i = 0; i < thread_number; i++) {
diff --combined fio.h
index a75d3b2d1b6ad08441c0826d513c6a92109551e4,01c8b9baa566fab534ab042a637e62fc6b2d74f9..107f767146d2abc01126e8605fd6910e75e852ff
--- 1/fio.h
--- 2/fio.h
+++ b/fio.h
@@@ -150,12 -150,12 +150,16 @@@ struct thread_data 
        unsigned int iodepth;
        os_cpu_mask_t cpumask;
        unsigned int jobnum;
 +      unsigned int iolog;
+       unsigned int read_iolog;
+       unsigned int write_iolog;
 +      unsigned int rwmixcycle;
 +      unsigned int rwmixread;
 +      unsigned int nice;
  
        char iolog_file[256];
+       void *iolog_buf;
+       FILE *iolog_f;
  
        struct drand48_data bsrange_state;
        struct drand48_data verify_state;
        unsigned int do_disk_util;
        unsigned int override_sync;
  
 +      struct drand48_data rwmix_state;
 +      struct timeval rwmix_switch;
 +      int rwmix_ddir;
 +
        struct list_head io_hist_list;
        struct list_head io_log_list;
  };