Skip to contentSkip to conversation

Recent changes (master)

PATCH Jens Axboe 1 participant 1 message Sep 12

lore
Share & tools
lore

Jens Axboe

author
#0 lore raw

The following changes since commit ac6ae485e6003b2a9999540c4e3e65780f1e6660:

Merge branch 'inconsistent_parameter_type_in_convert_agg_kbytes_percent' of https://github.com/dennischerchang/fio (2026-09-09 14:18:37 -0400)

are available in the Git repository at:

git://git.kernel.dk/fio.git master

for you to fetch changes up to 6bc57a931f04fa3f50348d8c8f087187f050c6e1:

eta: remove now unused done_secs (2026-09-11 14:41:56 -0400)

----------------------------------------------------------------
Keith Busch (4):
eta: count a job that is setting up as running
backend: don't mark a job as running before it has set up
eta: cap the ETA at the job's own remaining runtime
eta: remove now unused done_secs

 backend.c | 23 ++++++++++++++++-------
 eta.c     | 20 +++++++++++++++-----
 fio.h     |  1 -
 libfio.c  |  4 ++--
 4 files changed, 33 insertions(+), 15 deletions(-)

---

Diff of recent changes:

backend.c +16 -7
index 2b419b12..88557f0b 100644
@@ -71,7 +71,6 @@ unsigned int nr_segments = 0;
 unsigned int cur_segment = 0;
 unsigned int stat_number = 0;
 int temp_stall_ts;
-unsigned long done_secs = 0;
 #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
 pthread_mutex_t overlap_check = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
 #else
@@ -2180,6 +2179,17 @@ static void *thread_main(void *data)
 		goto err;
 
 	set_epoch_time(td, o->log_alternate_epoch_clock_id, o->job_start_clock_id);
+
+	/*
+	 * Setup is done and the job now has an epoch to measure itself
+	 * against, so it is finally safe to call it running. Everything
+	 * above this point ran as TD_SETTING_UP.
+	 */
+	if (in_ramp_period(td))
+		td_set_runstate(td, TD_RAMP);
+	else
+		td_set_runstate(td, TD_RUNNING);
+
 	fio_getrusage(&td->ru_start);
 	memcpy(&td->bw_sample_time, &td->epoch, sizeof(td->epoch));
 	memcpy(&td->iops_sample_time, &td->epoch, sizeof(td->epoch));
@@ -2499,7 +2509,6 @@ reaped:
 		if (td->error)
 			exit_value++;
 
-		done_secs += mtime_since_now(&td->epoch) / 1000;
 		profile_td_exit(td);
 		flow_exit_job(td);
 	} end_for_each();
@@ -2893,16 +2902,16 @@ reap:
 		}
 
 		/*
-		 * start created threads (TD_INITIALIZED -> TD_RUNNING).
+		 * start created threads (TD_INITIALIZED -> TD_SETTING_UP).
+		 * The job has plenty of setup left to do before it issues any
+		 * IO, so it promotes itself to TD_RAMP or TD_RUNNING once that
+		 * is done and it has recorded its epoch.
 		 */
 		for_each_td(td) {
 			if (td->runstate != TD_INITIALIZED)
 				continue;
 
-			if (in_ramp_period(td))
-				td_set_runstate(td, TD_RAMP);
-			else
-				td_set_runstate(td, TD_RUNNING);
+			td_set_runstate(td, TD_SETTING_UP);
 			nr_running++;
 			nr_started--;
 			m_rate += ddir_rw_sum(td->o.ratemin);
eta.c +15 -5
index c6e3cffb..d17b8c3f 100644
@@ -253,9 +253,18 @@ static unsigned long thread_eta(struct thread_data *td)
 			eta_sec = (unsigned long) (elapsed * (1.0 / perc)) - elapsed;
 		}
 
-		if (td->o.timeout &&
-		    eta_sec > (timeout + done_secs - elapsed))
-			eta_sec = timeout + done_secs - elapsed;
+		/*
+		 * A job never runs for longer than its own timeout, which is
+		 * measured from its own epoch. Cap the estimate at whatever
+		 * time this job has left.
+		 */
+		if (td->o.timeout) {
+			unsigned long timeout_left;
+
+			timeout_left = timeout > elapsed ? timeout - elapsed : 0;
+			if (eta_sec > timeout_left)
+				eta_sec = timeout_left;
+		}
 	} else if (td->runstate == TD_NOT_CREATED || td->runstate == TD_CREATED
 			|| td->runstate == TD_INITIALIZED
 			|| td->runstate == TD_SETTING_UP
@@ -466,9 +475,10 @@ static bool calc_thread_status(struct jobs_eta *je, int force)
 		} else if (td->runstate == TD_RAMP) {
 			je->nr_running++;
 			je->nr_ramp++;
-		} else if (td->runstate == TD_SETTING_UP)
+		} else if (td->runstate == TD_SETTING_UP) {
+			je->nr_running++;
 			je->nr_setting_up++;
-		else if (td->runstate < TD_RUNNING)
+		} else if (td->runstate < TD_RUNNING)
 			je->nr_pending++;
 
 		if (je->elapsed_sec >= 3)
fio.h +0 -1
index d96ad4d0..84d46414 100644
@@ -598,7 +598,6 @@ extern bool read_only;
 extern int eta_print;
 extern int eta_new_line;
 extern unsigned int eta_interval_msec;
-extern unsigned long done_secs;
 extern int fio_gtod_offload;
 extern int fio_gtod_cpu;
 extern enum fio_cs fio_clock_source;
libfio.c +2 -2
index 37f2c749..aff131ff 100644
@@ -188,7 +188,6 @@ void reset_fio_state(void)
 	for (i = 0; i < nr_segments; i++)
 		segments[i].nr_threads = 0;
 	stat_number = 0;
-	done_secs = 0;
 }
 
 const char *fio_get_os_string(int nr)
@@ -271,7 +270,8 @@ void fio_terminate_threads(unsigned int group_id, unsigned int terminate)
 	for_each_td(td) {
 		if ((terminate == TERMINATE_GROUP && group_id == TERMINATE_ALL) ||
 		    (terminate == TERMINATE_GROUP && group_id == td->groupid) ||
-		    (terminate == TERMINATE_STONEWALL && td->runstate >= TD_RUNNING) ||
+		    (terminate == TERMINATE_STONEWALL &&
+		     td->runstate >= TD_SETTING_UP) ||
 		    (terminate == TERMINATE_ALL)) {
 			dprint(FD_PROCESS, "setting terminate on %s/%d\n",
 						td->o.name, (int) td->pid);