Implement new Rate Control
[fio.git] / backend.c
index 2aa88403da00600c5a1b8713572aa5840eb7dba3..d5b260a81c896fbcbe8c2ddf581d584225f69067 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -373,6 +373,9 @@ static inline void update_runtime(struct thread_data *td,
                                  unsigned long long *elapsed_us,
                                  const enum fio_ddir ddir)
 {
+       if (ddir == DDIR_WRITE && td_write(td) && td->o.verify_only)
+               return;
+
        td->ts.runtime[ddir] -= (elapsed_us[ddir] + 999) / 1000;
        elapsed_us[ddir] += utime_since_now(&td->start);
        td->ts.runtime[ddir] += (elapsed_us[ddir] + 999) / 1000;
@@ -759,6 +762,25 @@ static int io_complete_bytes_exceeded(struct thread_data *td)
        return bytes >= limit || exceeds_number_ios(td);
 }
 
+/*
+ * used to calculate the next io time for rate control
+ *
+ */
+static long long usec_for_io(struct thread_data *td, enum fio_ddir ddir)
+{
+       uint64_t secs, remainder, bps, bytes;
+
+       assert(!(td->flags & TD_F_CHILD));
+       bytes = td->rate_io_issue_bytes[ddir];
+       bps = td->rate_bps[ddir];
+       if (bps) {
+               secs = bytes / bps;
+               remainder = bytes % bps;
+               return remainder * 1000000 / bps + secs * 1000000;
+       } else
+               return 0;
+}
+
 /*
  * Main IO worker function. It retrieves io_u's to process and queues
  * and reaps them, checking for rate and errors along the way.
@@ -888,10 +910,17 @@ static uint64_t do_io(struct thread_data *td)
                        if (td->error)
                                break;
                        ret = workqueue_enqueue(&td->io_wq, io_u);
+
+                       if (should_check_rate(td))
+                               td->rate_next_io_time[ddir] = usec_for_io(td, ddir);
+
                } else {
                        ret = td_io_queue(td, io_u);
 
-                       if (io_queue_event(td, io_u, &ret, ddir, &bytes_issued, 1, &comp_time))
+                       if (should_check_rate(td))
+                               td->rate_next_io_time[ddir] = usec_for_io(td, ddir);
+
+                       if (io_queue_event(td, io_u, &ret, ddir, &bytes_issued, 0, &comp_time))
                                break;
 
                        /*
@@ -921,7 +950,7 @@ reap:
                }
                if (!in_ramp_time(td) && td->o.latency_target)
                        lat_target_check(td);
-
+                                       
                if (td->o.thinktime) {
                        unsigned long long b;
 
@@ -1172,13 +1201,17 @@ static int switch_ioscheduler(struct thread_data *td)
        /*
         * Read back and check that the selected scheduler is now the default.
         */
+       memset(tmp, 0, sizeof(tmp));
        ret = fread(tmp, sizeof(tmp), 1, f);
        if (ferror(f) || ret < 0) {
                td_verror(td, errno, "fread");
                fclose(f);
                return 1;
        }
-       tmp[sizeof(tmp) - 1] = '\0';
+       /*
+        * either a list of io schedulers or "none\n" is expected.
+        */
+       tmp[strlen(tmp) - 1] = '\0';
 
 
        sprintf(tmp2, "[%s]", td->o.ioscheduler);
@@ -1235,7 +1268,8 @@ static int keep_running(struct thread_data *td)
 
 static int exec_string(struct thread_options *o, const char *string, const char *mode)
 {
-       int ret, newlen = strlen(string) + strlen(o->name) + strlen(mode) + 9 + 1;
+       size_t newlen = strlen(string) + strlen(o->name) + strlen(mode) + 9 + 1;
+       int ret;
        char *str;
 
        str = malloc(newlen);