From 10f74940073380f6cb15608053b36a796f879dec Mon Sep 17 00:00:00 2001 From: Lukas Straub Date: Wed, 19 Jan 2022 21:14:23 +0000 Subject: [PATCH] blktrace.c: Add support for read_iolog_chunked Signed-off-by: Lukas Straub Link: https://lore.kernel.org/r/d43a8a2d5fd23d9756cdcf280cd2f3572585f264.1642626314.git.lukasstraub2@web.de Signed-off-by: Jens Axboe --- blktrace.c | 154 ++++++++++++++++++++++++++++++++++++++--------------- blktrace.h | 12 ++++- fio.h | 1 + iolog.c | 13 +++-- 4 files changed, 131 insertions(+), 49 deletions(-) diff --git a/blktrace.c b/blktrace.c index c9a00eb1..f1dbd1a6 100644 --- a/blktrace.c +++ b/blktrace.c @@ -8,6 +8,7 @@ #include "flist.h" #include "fio.h" +#include "iolog.h" #include "blktrace.h" #include "blktrace_api.h" #include "oslib/linux-dev-lookup.h" @@ -171,7 +172,7 @@ static void store_ipo(struct thread_data *td, unsigned long long offset, queue_io_piece(td, ipo); } -static void handle_trace_notify(struct blk_io_trace *t) +static bool handle_trace_notify(struct blk_io_trace *t) { switch (t->action) { case BLK_TN_PROCESS: @@ -188,18 +189,19 @@ static void handle_trace_notify(struct blk_io_trace *t) dprint(FD_BLKTRACE, "unknown trace act %x\n", t->action); break; } + return false; } -static void handle_trace_discard(struct thread_data *td, +static bool handle_trace_discard(struct thread_data *td, struct blk_io_trace *t, unsigned long long ttime, - unsigned long *ios, unsigned int *bs) + unsigned long *ios, unsigned long long *bs) { struct io_piece *ipo; int fileno; if (td->o.replay_skip & (1u << DDIR_TRIM)) - return; + return false; ipo = calloc(1, sizeof(*ipo)); init_ipo(ipo); @@ -226,6 +228,7 @@ static void handle_trace_discard(struct thread_data *td, ipo->offset, ipo->len, ipo->delay); queue_io_piece(td, ipo); + return true; } static void dump_trace(struct blk_io_trace *t) @@ -233,9 +236,9 @@ static void dump_trace(struct blk_io_trace *t) log_err("blktrace: ignoring zero byte trace: action=%x\n", t->action); } -static void handle_trace_fs(struct thread_data *td, struct blk_io_trace *t, +static bool handle_trace_fs(struct thread_data *td, struct blk_io_trace *t, unsigned long long ttime, unsigned long *ios, - unsigned int *bs) + unsigned long long *bs) { int rw; int fileno; @@ -246,16 +249,16 @@ static void handle_trace_fs(struct thread_data *td, struct blk_io_trace *t, if (rw) { if (td->o.replay_skip & (1u << DDIR_WRITE)) - return; + return false; } else { if (td->o.replay_skip & (1u << DDIR_READ)) - return; + return false; } if (!t->bytes) { if (!fio_did_warn(FIO_WARN_BTRACE_ZERO)) dump_trace(t); - return; + return false; } if (t->bytes > bs[rw]) @@ -264,16 +267,17 @@ static void handle_trace_fs(struct thread_data *td, struct blk_io_trace *t, ios[rw]++; td->o.size += t->bytes; store_ipo(td, t->sector, t->bytes, rw, ttime, fileno); + return true; } -static void handle_trace_flush(struct thread_data *td, struct blk_io_trace *t, +static bool handle_trace_flush(struct thread_data *td, struct blk_io_trace *t, unsigned long long ttime, unsigned long *ios) { struct io_piece *ipo; int fileno; if (td->o.replay_skip & (1u << DDIR_SYNC)) - return; + return false; ipo = calloc(1, sizeof(*ipo)); init_ipo(ipo); @@ -286,20 +290,21 @@ static void handle_trace_flush(struct thread_data *td, struct blk_io_trace *t, ios[DDIR_SYNC]++; dprint(FD_BLKTRACE, "store flush delay=%lu\n", ipo->delay); queue_io_piece(td, ipo); + return true; } /* * We only care for queue traces, most of the others are side effects * due to internal workings of the block layer. */ -static void handle_trace(struct thread_data *td, struct blk_io_trace *t, - unsigned long *ios, unsigned int *bs) +static bool queue_trace(struct thread_data *td, struct blk_io_trace *t, + unsigned long *ios, unsigned long long *bs) { static unsigned long long last_ttime; unsigned long long delay = 0; if ((t->action & 0xffff) != __BLK_TA_QUEUE) - return; + return false; if (!(t->action & BLK_TC_ACT(BLK_TC_NOTIFY))) { if (!last_ttime || td->o.no_stall) @@ -320,13 +325,13 @@ static void handle_trace(struct thread_data *td, struct blk_io_trace *t, t_bytes_align(&td->o, t); if (t->action & BLK_TC_ACT(BLK_TC_NOTIFY)) - handle_trace_notify(t); + return handle_trace_notify(t); else if (t->action & BLK_TC_ACT(BLK_TC_DISCARD)) - handle_trace_discard(td, t, delay, ios, bs); + return handle_trace_discard(td, t, delay, ios, bs); else if (t->action & BLK_TC_ACT(BLK_TC_FLUSH)) - handle_trace_flush(td, t, delay, ios); + return handle_trace_flush(td, t, delay, ios); else - handle_trace_fs(td, t, delay, ios, bs); + return handle_trace_fs(td, t, delay, ios, bs); } static void byteswap_trace(struct blk_io_trace *t) @@ -394,27 +399,62 @@ static void depth_end(struct blk_io_trace *t, int *this_depth, int *depth) * Load a blktrace file by reading all the blk_io_trace entries, and storing * them as io_pieces like the fio text version would do. */ -bool load_blktrace(struct thread_data *td, const char *filename, int need_swap) +bool init_blktrace_read(struct thread_data *td, const char *filename, int need_swap) +{ + int old_state; + + td->io_log_rfile = fopen(filename, "rb"); + if (!td->io_log_rfile) { + td_verror(td, errno, "open blktrace file"); + goto err; + } + td->io_log_blktrace_swap = need_swap; + td->o.size = 0; + + free_release_files(td); + + old_state = td_bump_runstate(td, TD_SETTING_UP); + + if (!read_blktrace(td)) { + goto err; + } + + td_restore_runstate(td, old_state); + + if (!td->files_index) { + log_err("fio: did not find replay device(s)\n"); + return false; + } + + return true; + +err: + if (td->io_log_rfile) { + fclose(td->io_log_rfile); + td->io_log_rfile = NULL; + } + return false; +} + +bool read_blktrace(struct thread_data* td) { struct blk_io_trace t; unsigned long ios[DDIR_RWDIR_SYNC_CNT] = { }; - unsigned int rw_bs[DDIR_RWDIR_CNT] = { }; + unsigned long long rw_bs[DDIR_RWDIR_CNT] = { }; unsigned long skipped_writes; - FILE *f; - int i, old_state, max_depth; + FILE *f = td->io_log_rfile; + int i, max_depth; struct fio_file *fiof; int this_depth[DDIR_RWDIR_CNT] = { }; int depth[DDIR_RWDIR_CNT] = { }; + int64_t items_to_fetch = 0; - f = fopen(filename, "rb"); - if (!f) { - td_verror(td, errno, "open blktrace file"); - return false; + if (td->o.read_iolog_chunked) { + items_to_fetch = iolog_items_to_fetch(td); + if (!items_to_fetch) + return true; } - old_state = td_bump_runstate(td, TD_SETTING_UP); - - td->o.size = 0; skipped_writes = 0; do { int ret = fread(&t, 1, sizeof(t), f); @@ -429,7 +469,7 @@ bool load_blktrace(struct thread_data *td, const char *filename, int need_swap) break; } - if (need_swap) + if (td->io_log_blktrace_swap) byteswap_trace(&t); if ((t.magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) { @@ -462,21 +502,53 @@ bool load_blktrace(struct thread_data *td, const char *filename, int need_swap) } } - handle_trace(td, &t, ios, rw_bs); - } while (1); + if (!queue_trace(td, &t, ios, rw_bs)) + continue; - for_each_file(td, fiof, i) - trace_add_open_close_event(td, fiof->fileno, FIO_LOG_CLOSE_FILE); + if (td->o.read_iolog_chunked) { + td->io_log_current++; + items_to_fetch--; + if (items_to_fetch == 0) + break; + } + } while (1); - fclose(f); + if (td->o.read_iolog_chunked) { + td->io_log_highmark = td->io_log_current; + td->io_log_checkmark = (td->io_log_highmark + 1) / 2; + fio_gettime(&td->io_log_highmark_time, NULL); + } - td_restore_runstate(td, old_state); + if (skipped_writes) + log_err("fio: %s skips replay of %lu writes due to read-only\n", + td->o.name, skipped_writes); - if (!td->files_index) { - log_err("fio: did not find replay device(s)\n"); - return false; + if (td->o.read_iolog_chunked) { + if (td->io_log_current == 0) { + return false; + } + td->o.td_ddir = TD_DDIR_RW; + if ((rw_bs[DDIR_READ] > td->o.max_bs[DDIR_READ] || + rw_bs[DDIR_WRITE] > td->o.max_bs[DDIR_WRITE] || + rw_bs[DDIR_TRIM] > td->o.max_bs[DDIR_TRIM]) && + td->orig_buffer) + { + td->o.max_bs[DDIR_READ] = max(td->o.max_bs[DDIR_READ], rw_bs[DDIR_READ]); + td->o.max_bs[DDIR_WRITE] = max(td->o.max_bs[DDIR_WRITE], rw_bs[DDIR_WRITE]); + td->o.max_bs[DDIR_TRIM] = max(td->o.max_bs[DDIR_TRIM], rw_bs[DDIR_TRIM]); + io_u_quiesce(td); + free_io_mem(td); + init_io_u_buffers(td); + } + return true; } + for_each_file(td, fiof, i) + trace_add_open_close_event(td, fiof->fileno, FIO_LOG_CLOSE_FILE); + + fclose(td->io_log_rfile); + td->io_log_rfile = NULL; + /* * For stacked devices, we don't always get a COMPLETE event so * the depth grows to insane values. Limit it to something sane(r). @@ -490,10 +562,6 @@ bool load_blktrace(struct thread_data *td, const char *filename, int need_swap) max_depth = max(depth[i], max_depth); } - if (skipped_writes) - log_err("fio: %s skips replay of %lu writes due to read-only\n", - td->o.name, skipped_writes); - if (!ios[DDIR_READ] && !ios[DDIR_WRITE] && !ios[DDIR_TRIM] && !ios[DDIR_SYNC]) { log_err("fio: found no ios in blktrace data\n"); diff --git a/blktrace.h b/blktrace.h index b2ebdba3..c53b717b 100644 --- a/blktrace.h +++ b/blktrace.h @@ -20,7 +20,9 @@ struct blktrace_cursor { }; bool is_blktrace(const char *, int *); -bool load_blktrace(struct thread_data *, const char *, int); +bool init_blktrace_read(struct thread_data *, const char *, int); +bool read_blktrace(struct thread_data* td); + int merge_blktrace_iologs(struct thread_data *td); #else @@ -30,12 +32,18 @@ static inline bool is_blktrace(const char *fname, int *need_swap) return false; } -static inline bool load_blktrace(struct thread_data *td, const char *fname, +static inline bool init_blktrace_read(struct thread_data *td, const char *fname, int need_swap) { return false; } +static inline bool read_blktrace(struct thread_data* td) +{ + return false; +} + + static inline int merge_blktrace_iologs(struct thread_data *td) { return false; diff --git a/fio.h b/fio.h index 6bb21ebb..5c68ad80 100644 --- a/fio.h +++ b/fio.h @@ -428,6 +428,7 @@ struct thread_data { struct flist_head io_log_list; FILE *io_log_rfile; unsigned int io_log_blktrace; + unsigned int io_log_blktrace_swap; unsigned int io_log_current; unsigned int io_log_checkmark; unsigned int io_log_highmark; diff --git a/iolog.c b/iolog.c index 3d4646a8..5a41e93f 100644 --- a/iolog.c +++ b/iolog.c @@ -152,10 +152,15 @@ int read_iolog_get(struct thread_data *td, struct io_u *io_u) while (!flist_empty(&td->io_log_list)) { int ret; - if (!td->io_log_blktrace && td->o.read_iolog_chunked) { + if (td->o.read_iolog_chunked) { if (td->io_log_checkmark == td->io_log_current) { - if (!read_iolog2(td)) - return 1; + if (td->io_log_blktrace) { + if (!read_blktrace(td)) + return 1; + } else { + if (!read_iolog2(td)) + return 1; + } } td->io_log_current--; } @@ -709,7 +714,7 @@ bool init_iolog(struct thread_data *td) */ if (is_blktrace(fname, &need_swap)) { td->io_log_blktrace = 1; - ret = load_blktrace(td, fname, need_swap); + ret = init_blktrace_read(td, fname, need_swap); } else { td->io_log_blktrace = 0; ret = init_iolog_read(td, fname); -- 2.25.1