Add clue for ENOMEM hugepage allocation
[fio.git] / fio.c
diff --git a/fio.c b/fio.c
index 504b78db0b0cd6dc1390435f56fd89d6bf19345c..fcf3ae80c1fd5316c0ce121434eef2426b4471fe 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -35,7 +35,7 @@
 #include <sys/mman.h>
 
 #include "fio.h"
-#include "os.h"
+#include "hash.h"
 
 unsigned long page_mask;
 unsigned long page_size;
@@ -311,6 +311,7 @@ static void do_verify(struct thread_data *td)
 
                if (runtime_exceeded(td, &io_u->start_time)) {
                        put_io_u(td, io_u);
+                       td->terminate = 1;
                        break;
                }
 
@@ -333,6 +334,7 @@ static void do_verify(struct thread_data *td)
                                ret = -io_u->error;
                        else if (io_u->resid) {
                                int bytes = io_u->xfer_buflen - io_u->resid;
+                               struct fio_file *f = io_u->file;
 
                                /*
                                 * zero read, fail
@@ -342,10 +344,20 @@ static void do_verify(struct thread_data *td)
                                        put_io_u(td, io_u);
                                        break;
                                }
+
                                io_u->xfer_buflen = io_u->resid;
                                io_u->xfer_buf += bytes;
+                               io_u->offset += bytes;
+                               f->last_completed_pos = io_u->offset;
+
+                               td->ts.short_io_u[io_u->ddir]++;
+
+                               if (io_u->offset == f->real_file_size)
+                                       goto sync_done;
+
                                requeue_io_u(td, &io_u);
                        } else {
+sync_done:
                                ret = io_u_sync_complete(td, io_u);
                                if (ret < 0)
                                        break;
@@ -412,7 +424,7 @@ static void do_io(struct thread_data *td)
 
        td_set_runstate(td, TD_RUNNING);
 
-       while ((td->this_io_bytes[0] + td->this_io_bytes[1]) < td->io_size) {
+       while ((td->this_io_bytes[0] + td->this_io_bytes[1]) < td->o.size) {
                struct timeval comp_time;
                long bytes_done = 0;
                int min_evts = 0;
@@ -430,6 +442,7 @@ static void do_io(struct thread_data *td)
 
                if (runtime_exceeded(td, &s)) {
                        put_io_u(td, io_u);
+                       td->terminate = 1;
                        break;
                }
 
@@ -440,6 +453,7 @@ static void do_io(struct thread_data *td)
                                ret = -io_u->error;
                        else if (io_u->resid) {
                                int bytes = io_u->xfer_buflen - io_u->resid;
+                               struct fio_file *f = io_u->file;
 
                                /*
                                 * zero read, fail
@@ -452,8 +466,17 @@ static void do_io(struct thread_data *td)
 
                                io_u->xfer_buflen = io_u->resid;
                                io_u->xfer_buf += bytes;
+                               io_u->offset += bytes;
+                               f->last_completed_pos = io_u->offset;
+
+                               td->ts.short_io_u[io_u->ddir]++;
+
+                               if (io_u->offset == f->real_file_size)
+                                       goto sync_done;
+
                                requeue_io_u(td, &io_u);
                        } else {
+sync_done:
                                fio_gettime(&comp_time, NULL);
                                bytes_done = io_u_sync_complete(td, io_u);
                                if (bytes_done < 0)
@@ -576,14 +599,17 @@ static void cleanup_io_u(struct thread_data *td)
 /*
  * "randomly" fill the buffer contents
  */
-static void fill_rand_buf(struct io_u *io_u, int max_bs)
+static void fill_io_buf(struct thread_data *td, struct io_u *io_u, int max_bs)
 {
-       int *ptr = io_u->buf;
+       long *ptr = io_u->buf;
 
-       while ((void *) ptr - io_u->buf < max_bs) {
-               *ptr = rand() * 0x9e370001;
-               ptr++;
-       }
+       if (!td->o.zero_buffers) {
+               while ((void *) ptr - io_u->buf < max_bs) {
+                       *ptr = rand() * GOLDEN_RATIO_PRIME;
+                       ptr++;
+               }
+       } else
+               memset(ptr, 0, max_bs);
 }
 
 static int init_io_u(struct thread_data *td)
@@ -619,13 +645,16 @@ static int init_io_u(struct thread_data *td)
 
        p = ALIGN(td->orig_buffer);
        for (i = 0; i < max_units; i++) {
+               if (td->terminate)
+                       return 1;
                io_u = malloc(sizeof(*io_u));
                memset(io_u, 0, sizeof(*io_u));
                INIT_LIST_HEAD(&io_u->list);
 
                io_u->buf = p + max_bs * i;
-               if (td_write(td) || td_rw(td))
-                       fill_rand_buf(io_u, max_bs);
+
+               if (td_write(td))
+                       fill_io_buf(td, io_u, max_bs);
 
                io_u->index = i;
                io_u->flags = IO_U_F_FREE;
@@ -650,7 +679,11 @@ static int switch_ioscheduler(struct thread_data *td)
 
        f = fopen(tmp, "r+");
        if (!f) {
-               td_verror(td, errno, "fopen");
+               if (errno == ENOENT) {
+                       log_err("fio: os or kernel doesn't support IO scheduler switching\n");
+                       return 0;
+               }
+               td_verror(td, errno, "fopen iosched");
                return 1;
        }
 
@@ -688,6 +721,24 @@ static int switch_ioscheduler(struct thread_data *td)
        return 0;
 }
 
+static int keep_running(struct thread_data *td)
+{
+       unsigned long long io_done;
+
+       if (td->o.time_based)
+               return 1;
+       if (td->o.loops) {
+               td->o.loops--;
+               return 1;
+       }
+
+       io_done = td->io_bytes[DDIR_READ] + td->io_bytes[DDIR_WRITE];
+       if (io_done < td->o.size)
+               return 1;
+
+       return 0;
+}
+
 static int clear_io_state(struct thread_data *td)
 {
        struct fio_file *f;
@@ -703,11 +754,14 @@ static int clear_io_state(struct thread_data *td)
 
        td->last_was_sync = 0;
 
+       td->nr_done_files = 0;
+
        for_each_file(td, f, i)
                td_io_close_file(td, f);
 
        ret = 0;
        for_each_file(td, f, i) {
+               f->flags &= ~FIO_FILE_DONE;
                ret = td_io_open_file(td, f);
                if (ret)
                        break;
@@ -736,42 +790,48 @@ static void *thread_main(void *data)
        INIT_LIST_HEAD(&td->io_u_busylist);
        INIT_LIST_HEAD(&td->io_u_requeues);
        INIT_LIST_HEAD(&td->io_log_list);
+       INIT_LIST_HEAD(&td->io_hist_list);
+       td->io_hist_tree = RB_ROOT;
+
+       td_set_runstate(td, TD_INITIALIZED);
+       fio_sem_up(startup_sem);
+       fio_sem_down(td->mutex);
+
+       /*
+        * the ->mutex semaphore is now no longer used, close it to avoid
+        * eating a file descriptor
+        */
+       fio_sem_remove(td->mutex);
+
+       /*
+        * May alter parameters that init_io_u() will use, so we need to
+        * do this first.
+        */
+       if (init_iolog(td))
+               goto err;
 
        if (init_io_u(td))
-               goto err_sem;
+               goto err;
 
-       if (fio_setaffinity(td) == -1) {
+       if (td->o.cpumask_set && fio_setaffinity(td) == -1) {
                td_verror(td, errno, "cpu_set_affinity");
-               goto err_sem;
+               goto err;
        }
 
-       if (init_iolog(td))
-               goto err_sem;
-
        if (td->ioprio) {
                if (ioprio_set(IOPRIO_WHO_PROCESS, 0, td->ioprio) == -1) {
                        td_verror(td, errno, "ioprio_set");
-                       goto err_sem;
+                       goto err;
                }
        }
 
        if (nice(td->o.nice) == -1) {
                td_verror(td, errno, "nice");
-               goto err_sem;
+               goto err;
        }
 
        if (td->o.ioscheduler && switch_ioscheduler(td))
-               goto err_sem;
-
-       td_set_runstate(td, TD_INITIALIZED);
-       fio_sem_up(startup_sem);
-       fio_sem_down(td->mutex);
-
-       /*
-        * the ->mutex semaphore is now no longer used, close it to avoid
-        * eating a file descriptor
-        */
-       fio_sem_remove(td->mutex);
+               goto err;
 
        if (!td->o.create_serialize && setup_files(td))
                goto err;
@@ -796,7 +856,7 @@ static void *thread_main(void *data)
 
        runtime[0] = runtime[1] = 0;
        clear_state = 0;
-       while (td->o.loops--) {
+       while (keep_running(td)) {
                fio_gettime(&td->start, NULL);
                memcpy(&td->ts.stat_sample_time, &td->start, sizeof(td->start));
 
@@ -880,9 +940,6 @@ err:
        options_mem_free(td);
        td_set_runstate(td, TD_EXITED);
        return (void *) (unsigned long) td->error;
-err_sem:
-       fio_sem_up(startup_sem);
-       goto err;
 }
 
 /*
@@ -976,6 +1033,7 @@ static void reap_threads(int *nr_running, int *t_rate, int *m_rate)
                /*
                 * thread is not dead, continue
                 */
+               pending++;
                continue;
 reaped:
                if (td->o.use_thread) {
@@ -988,6 +1046,7 @@ reaped:
                (*nr_running)--;
                (*m_rate) -= td->o.ratemin;
                (*t_rate) -= td->o.rate;
+               pending--;
 
                if (td->error)
                        exit_value++;
@@ -1195,10 +1254,8 @@ int main(int argc, char *argv[])
        if (parse_options(argc, argv))
                return 1;
 
-       if (!thread_number) {
-               log_err("Nothing to do\n");
-               return 1;
-       }
+       if (!thread_number)
+               return 0;
 
        ps = sysconf(_SC_PAGESIZE);
        if (ps < 0) {