+ td->ts.io_u_map[index]++;
+ td->ts.total_io_u[io_u->ddir]++;
+}
+
+static void io_u_mark_lat_usec(struct thread_data *td, unsigned long usec)
+{
+ int index = 0;
+
+ assert(usec < 1000);
+
+ switch (usec) {
+ case 750 ... 999:
+ index = 9;
+ break;
+ case 500 ... 749:
+ index = 8;
+ break;
+ case 250 ... 499:
+ index = 7;
+ break;
+ case 100 ... 249:
+ index = 6;
+ break;
+ case 50 ... 99:
+ index = 5;
+ break;
+ case 20 ... 49:
+ index = 4;
+ break;
+ case 10 ... 19:
+ index = 3;
+ break;
+ case 4 ... 9:
+ index = 2;
+ break;
+ case 2 ... 3:
+ index = 1;
+ case 0 ... 1:
+ break;
+ }
+
+ assert(index < FIO_IO_U_LAT_U_NR);
+ td->ts.io_u_lat_u[index]++;
+}
+
+static void io_u_mark_lat_msec(struct thread_data *td, unsigned long msec)
+{
+ int index = 0;
+
+ switch (msec) {
+ default:
+ index = 11;
+ break;
+ case 1000 ... 1999:
+ index = 10;
+ break;
+ case 750 ... 999:
+ index = 9;
+ break;
+ case 500 ... 749:
+ index = 8;
+ break;
+ case 250 ... 499:
+ index = 7;
+ break;
+ case 100 ... 249:
+ index = 6;
+ break;
+ case 50 ... 99:
+ index = 5;
+ break;
+ case 20 ... 49:
+ index = 4;
+ break;
+ case 10 ... 19:
+ index = 3;
+ break;
+ case 4 ... 9:
+ index = 2;
+ break;
+ case 2 ... 3:
+ index = 1;
+ case 0 ... 1:
+ break;
+ }
+
+ assert(index < FIO_IO_U_LAT_M_NR);
+ td->ts.io_u_lat_m[index]++;
+}
+
+static void io_u_mark_latency(struct thread_data *td, unsigned long usec)
+{
+ if (usec < 1000)
+ io_u_mark_lat_usec(td, usec);
+ else
+ io_u_mark_lat_msec(td, usec / 1000);
+}
+
+/*
+ * Get next file to service by choosing one at random
+ */
+static struct fio_file *get_next_file_rand(struct thread_data *td, int goodf,
+ int badf)
+{
+ struct fio_file *f;
+ int fno;
+
+ do {
+ long r = os_random_long(&td->next_file_state);
+
+ fno = (unsigned int) ((double) td->o.nr_files
+ * (r / (RAND_MAX + 1.0)));
+ f = td->files[fno];
+ if (f->flags & FIO_FILE_DONE)
+ continue;
+
+ if ((!goodf || (f->flags & goodf)) && !(f->flags & badf)) {
+ dprint(FD_FILE, "get_next_file_rand: %p\n", f);
+ return f;
+ }
+ } while (1);
+}
+
+/*
+ * Get next file to service by doing round robin between all available ones
+ */
+static struct fio_file *get_next_file_rr(struct thread_data *td, int goodf,
+ int badf)
+{
+ unsigned int old_next_file = td->next_file;
+ struct fio_file *f;
+
+ do {
+ f = td->files[td->next_file];
+
+ td->next_file++;
+ if (td->next_file >= td->o.nr_files)
+ td->next_file = 0;
+
+ if (f->flags & FIO_FILE_DONE) {
+ f = NULL;
+ continue;
+ }
+
+ if ((!goodf || (f->flags & goodf)) && !(f->flags & badf))
+ break;
+
+ f = NULL;
+ } while (td->next_file != old_next_file);
+
+ dprint(FD_FILE, "get_next_file_rr: %p\n", f);
+ return f;
+}
+
+static struct fio_file *get_next_file(struct thread_data *td)
+{
+ struct fio_file *f;
+
+ assert(td->o.nr_files <= td->files_index);
+
+ if (!td->nr_open_files || td->nr_done_files >= td->o.nr_files) {
+ dprint(FD_FILE, "get_next_file: nr_open=%d, nr_done=%d,"
+ " nr_files=%d\n", td->nr_open_files,
+ td->nr_done_files,
+ td->o.nr_files);
+ return NULL;
+ }
+
+ f = td->file_service_file;
+ if (f && (f->flags & FIO_FILE_OPEN) && td->file_service_left--)
+ goto out;
+
+ if (td->o.file_service_type == FIO_FSERVICE_RR)
+ f = get_next_file_rr(td, FIO_FILE_OPEN, FIO_FILE_CLOSING);
+ else
+ f = get_next_file_rand(td, FIO_FILE_OPEN, FIO_FILE_CLOSING);
+
+ td->file_service_file = f;
+ td->file_service_left = td->file_service_nr - 1;
+out:
+ dprint(FD_FILE, "get_next_file: %p\n", f);
+ return f;
+}
+
+static struct fio_file *find_next_new_file(struct thread_data *td)
+{
+ struct fio_file *f;
+
+ if (!td->nr_open_files || td->nr_done_files >= td->o.nr_files)
+ return NULL;
+
+ if (td->o.file_service_type == FIO_FSERVICE_RR)
+ f = get_next_file_rr(td, 0, FIO_FILE_OPEN);
+ else
+ f = get_next_file_rand(td, 0, FIO_FILE_OPEN);
+
+ return f;
+}
+
+static int set_io_u_file(struct thread_data *td, struct io_u *io_u)
+{
+ struct fio_file *f;
+
+ do {
+ f = get_next_file(td);
+ if (!f)
+ return 1;
+
+set_file:
+ io_u->file = f;
+ get_file(f);
+
+ if (!fill_io_u(td, io_u))
+ break;
+
+ /*
+ * td_io_close() does a put_file() as well, so no need to
+ * do that here.
+ */
+ io_u->file = NULL;
+ td_io_close_file(td, f);
+ f->flags |= FIO_FILE_DONE;
+ td->nr_done_files++;
+
+ /*
+ * probably not the right place to do this, but see
+ * if we need to open a new file
+ */
+ if (td->nr_open_files < td->o.open_files &&
+ td->o.open_files != td->o.nr_files) {
+ f = find_next_new_file(td);
+
+ if (!f || td_io_open_file(td, f))
+ return 1;
+
+ goto set_file;
+ }
+ } while (1);
+
+ return 0;