+
+void steadystate_check(void)
+{
+ int i, j, ddir, prev_groupid, group_ramp_time_over = 0;
+ unsigned long rate_time;
+ struct thread_data *td, *td2;
+ struct timeval now;
+ unsigned long group_bw = 0, group_iops = 0;
+ unsigned long long td_iops;
+ unsigned long long td_bytes;
+ bool ret;
+
+ prev_groupid = -1;
+ for_each_td(td, i) {
+ struct steadystate_data *ss = &td->ss;
+
+ if (!ss->dur || td->runstate <= TD_SETTING_UP || td->runstate >= TD_EXITED || ss->attained)
+ continue;
+
+ td_iops = 0;
+ td_bytes = 0;
+ if (!td->o.group_reporting ||
+ (td->o.group_reporting && td->groupid != prev_groupid)) {
+ group_bw = 0;
+ group_iops = 0;
+ group_ramp_time_over = 0;
+ }
+ prev_groupid = td->groupid;
+
+ fio_gettime(&now, NULL);
+ if (ss->ramp_time && !ss->ramp_time_over)
+ /*
+ * Begin recording data one second after ss->ramp_time
+ * has elapsed
+ */
+ if (utime_since(&td->epoch, &now) >= (ss->ramp_time + 1000000L))
+ ss->ramp_time_over = 1;
+
+ td_io_u_lock(td);
+ for (ddir = DDIR_READ; ddir < DDIR_RWDIR_CNT; ddir++) {
+ td_iops += td->io_blocks[ddir];
+ td_bytes += td->io_bytes[ddir];
+ }
+ td_io_u_unlock(td);
+
+ rate_time = mtime_since(&ss->prev_time, &now);
+ memcpy(&ss->prev_time, &now, sizeof(now));
+
+ /*
+ * Begin monitoring when job starts but don't actually use
+ * data in checking stopping criterion until ss->ramp_time is
+ * over. This ensures that we will have a sane value in
+ * prev_iops/bw the first time through after ss->ramp_time
+ * is done.
+ */
+ if (ss->ramp_time_over) {
+ group_bw += 1000 * (td_bytes - ss->prev_bytes) / rate_time;
+ group_iops += 1000 * (td_iops - ss->prev_iops) / rate_time;
+ ++group_ramp_time_over;
+ }
+ ss->prev_iops = td_iops;
+ ss->prev_bytes = td_bytes;
+
+ if (td->o.group_reporting && !ss->last_in_group)
+ continue;
+
+ /* don't begin checking criterion until ss->ramp_time is over for at least one thread in group */
+ if (!group_ramp_time_over)
+ continue;
+
+ dprint(FD_STEADYSTATE, "steadystate_check() thread: %d, groupid: %u, rate_msec: %ld, iops: %lu, bw: %lu, head: %d, tail: %d\n",
+ i, td->groupid, rate_time, group_iops, group_bw, ss->head, ss->tail);
+
+ if (steadystate_check_slope(&td->o))
+ ret = steadystate_slope(group_iops, group_bw, td);
+ else
+ ret = steadystate_deviation(group_iops, group_bw, td);
+
+ if (ret) {
+ if (td->o.group_reporting) {
+ for_each_td(td2, j) {
+ if (td2->groupid == td->groupid) {
+ td2->ss.attained = 1;
+ fio_mark_td_terminate(td2);
+ }
+ }
+ } else {
+ ss->attained = 1;
+ fio_mark_td_terminate(td);
+ }
+ }
+ }
+}
+
+