[PATCH v2 4/5] time: Evaluate ramp up condition once per second
Jan Kara <[email protected]> Fri, 19 Dec 2025 14:42:38 +0100
| Newsgroups | org.kernel.vger.fio |
|---|---|
| Message-ID | <[email protected]> |
Instead of evaluating whether ramp up period has finished on each IO submission and completion evaluate it once per second and set appropriate state variable in thread_data. Later when ramp up period end condition will be more complex and would involve stat data from all threads, it would unnecessarily slow down IO. Reviewed-by: Damien Le Moal <[email protected]> Signed-off-by: Jan Kara <[email protected]> --- fio.h | 2 +- fio_time.h | 5 ++++ helper_thread.c | 8 +++++- time.c | 66 +++++++++++++++++++++++++++++++++---------------- 4 files changed, 58 insertions(+), 23 deletions(-) diff --git a/fio.h b/fio.h index 87c20803a929..fdd36fa49c95 100644 --- a/fio.h +++ b/fio.h @@ -417,7 +417,7 @@ struct thread_data { struct timespec terminate_time; unsigned int ts_cache_nr; unsigned int ts_cache_mask; - bool ramp_period_over; + unsigned int ramp_period_state; /* * Time since last latency_window was started diff --git a/fio_time.h b/fio_time.h index c67c9450f484..54dad8c7812e 100644 --- a/fio_time.h +++ b/fio_time.h @@ -8,6 +8,10 @@ /* IWYU pragma: end_exports */ #include "lib/types.h" +#define RAMP_PERIOD_CHECK_MSEC 1000 + +extern bool ramp_period_enabled; + struct thread_data; extern uint64_t ntime_since(const struct timespec *, const struct timespec *); extern uint64_t ntime_since_now(const struct timespec *); @@ -27,6 +31,7 @@ extern uint64_t usec_spin(unsigned int); extern uint64_t usec_sleep(struct thread_data *, unsigned long); extern void fill_start_time(struct timespec *); extern void set_genesis_time(void); +extern int ramp_period_check(void); extern bool ramp_period_over(struct thread_data *); extern bool in_ramp_period(struct thread_data *); extern void td_ramp_period_init(struct thread_data *); diff --git a/helper_thread.c b/helper_thread.c index fed21d1d61e7..88614e58e5a8 100644 --- a/helper_thread.c +++ b/helper_thread.c @@ -290,7 +290,13 @@ static void *helper_thread_main(void *data) .interval_ms = steadystate_enabled ? ss_check_interval : 0, .func = steadystate_check, - } + }, + { + .name = "ramp_period", + .interval_ms = ramp_period_enabled ? + RAMP_PERIOD_CHECK_MSEC : 0, + .func = ramp_period_check, + }, }; struct timespec ts; long clk_tck; diff --git a/time.c b/time.c index f90f2d9044fc..2709d5b9784a 100644 --- a/time.c +++ b/time.c @@ -6,6 +6,12 @@ static struct timespec genesis; static unsigned long ns_granularity; +enum ramp_period_states { + RAMP_RUNNING, + RAMP_FINISHING, + RAMP_DONE +}; + void timespec_add_msec(struct timespec *ts, unsigned int msec) { uint64_t adj_nsec = 1000000ULL * msec; @@ -112,51 +118,69 @@ uint64_t utime_since_genesis(void) bool in_ramp_period(struct thread_data *td) { - return !td->ramp_period_over; + return td->ramp_period_state != RAMP_DONE; +} + +bool ramp_period_enabled = false; + +int ramp_period_check(void) +{ + for_each_td(td) { + if (td->ramp_period_state != RAMP_RUNNING) + continue; + if (utime_since_now(&td->epoch) >= td->o.ramp_time) + td->ramp_period_state = RAMP_FINISHING; + } end_for_each(); + + return 0; } static bool parent_update_ramp(struct thread_data *td) { struct thread_data *parent = td->parent; - if (!parent || parent->ramp_period_over) + if (!parent || parent->ramp_period_state == RAMP_DONE) return false; reset_all_stats(parent); - parent->ramp_period_over = true; + parent->ramp_period_state = RAMP_DONE; td_set_runstate(parent, TD_RAMP); return true; } + bool ramp_period_over(struct thread_data *td) { - if (td->ramp_period_over) + if (td->ramp_period_state == RAMP_DONE) return true; - if (utime_since_now(&td->epoch) >= td->o.ramp_time) { - td->ramp_period_over = true; - reset_all_stats(td); - reset_io_stats(td); - td_set_runstate(td, TD_RAMP); + if (td->ramp_period_state == RAMP_RUNNING) + return false; - /* - * If we have a parent, the parent isn't doing IO. Hence - * the parent never enters do_io(), which will switch us - * from RAMP -> RUNNING. Do this manually here. - */ - if (parent_update_ramp(td)) - td_set_runstate(td, TD_RUNNING); + td->ramp_period_state = RAMP_DONE; + reset_all_stats(td); + reset_io_stats(td); + td_set_runstate(td, TD_RAMP); - return true; - } + /* + * If we have a parent, the parent isn't doing IO. Hence + * the parent never enters do_io(), which will switch us + * from RAMP -> RUNNING. Do this manually here. + */ + if (parent_update_ramp(td)) + td_set_runstate(td, TD_RUNNING); - return false; + return true; } void td_ramp_period_init(struct thread_data *td) { - if (!td->o.ramp_time) - td->ramp_period_over = true; + if (td->o.ramp_time) { + td->ramp_period_state = RAMP_RUNNING; + ramp_period_enabled = true; + } else { + td->ramp_period_state = RAMP_DONE; + } } void fio_time_init(void) -- 2.51.0