The patch has been revised to add 'mem=ioengine' option and respective sanity checks. Regards, Andrey diff --git a/HOWTO b/HOWTO index 5e765d4..c2243b5 100644 --- a/HOWTO +++ b/HOWTO @@ -1195,6 +1195,10 @@ mem=str Fio can use various types of memory as the io unit buffer. mmapshared Same as mmap, but use a MMAP_SHARED mapping. + ioengine I/O engine provides iomem_alloc/free + entries to allocate and free I/O memory. + The engine is then responsible for the memory + type compatibility with other job settings. The area allocated is a function of the maximum allowed bs size for the job, multiplied by the io depth given. Note diff --git a/ioengine.h b/ioengine.h index 6734c7b..161acf5 100644 --- a/ioengine.h +++ b/ioengine.h @@ -16,7 +16,7 @@ #include <guasi.h> #endif -#define FIO_IOOPS_VERSION 22 +#define FIO_IOOPS_VERSION 23 enum { IO_U_F_FREE = 1 << 0, @@ -157,6 +157,8 @@ struct ioengine_ops { int (*unlink_file)(struct thread_data *, struct fio_file *); int (*get_file_size)(struct thread_data *, struct fio_file *); void (*terminate)(struct thread_data *); + int (*iomem_alloc)(struct thread_data *, size_t); + void (*iomem_free)(struct thread_data *); int (*io_u_init)(struct thread_data *, struct io_u *); void (*io_u_free)(struct thread_data *, struct io_u *); int option_struct_size; diff --git a/ioengines.c b/ioengines.c index decc9cb..9ef3395 100644 --- a/ioengines.c +++ b/ioengines.c @@ -22,7 +22,7 @@ static FLIST_HEAD(engine_list); -static int check_engine_ops(struct ioengine_ops *ops) +static int check_engine_ops(struct thread_options *o, struct ioengine_ops *ops) { if (ops->version != FIO_IOOPS_VERSION) { log_err("bad ioops version %d (want %d)\n", ops->version, @@ -35,6 +35,20 @@ static int check_engine_ops(struct ioengine_ops *ops) return 1; } + if (o->mem_type == MEM_IOENGINE && + !(ops->iomem_alloc && ops->iomem_free)) { + log_err("%s: iomem handler(s) missing when " + "iomem=ioengine\n", ops->name); + return 1; + } + + if (o->mem_type != MEM_IOENGINE && + (ops->iomem_alloc || ops->iomem_free)) { + log_err("%s: iomem handler(s) present when " + "iomem!=ioengine\n", ops->name); + return 1; + } + /* * sync engines only need a ->queue() */ @@ -154,7 +168,7 @@ struct ioengine_ops *load_ioengine(struct thread_data *td, const char *name) /* * Check that the required methods are there. */ - if (check_engine_ops(ops)) + if (check_engine_ops(&td->o, ops)) return NULL; ret = malloc(sizeof(*ret)); diff --git a/memory.c b/memory.c index 5060223..cf9f60a 100644 --- a/memory.c +++ b/memory.c @@ -236,6 +236,8 @@ int allocate_io_mem(struct thread_data *td) else if (td->o.mem_type == MEM_MMAP || td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAPSHARED) ret = alloc_mem_mmap(td, total_mem); + else if (td->o.mem_type == MEM_IOENGINE) + ret = td->io_ops->iomem_alloc(td, total_mem); else { log_err("fio: bad mem type: %d\n", td->o.mem_type); ret = 1; @@ -262,6 +264,8 @@ void free_io_mem(struct thread_data *td) else if (td->o.mem_type == MEM_MMAP || td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAPSHARED) free_mem_mmap(td, total_mem); + else if (td->o.mem_type == MEM_IOENGINE) + td->io_ops->iomem_free(td); else log_err("Bad memory type %u\n", td->o.mem_type); diff --git a/options.c b/options.c index 3902087..28a8fca 100644 --- a/options.c +++ b/options.c @@ -2100,6 +2100,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Like mmap, but use huge pages", }, #endif + { .ival = "ioengine", + .oval = MEM_IOENGINE, + .help = "I/O engine provides alloc/free methods", + }, }, }, { diff --git a/thread_options.h b/thread_options.h index 384534a..98fafa3 100644 --- a/thread_options.h +++ b/thread_options.h @@ -20,6 +20,7 @@ enum fio_memtype { MEM_MMAP, /* use anonynomous mmap */ MEM_MMAPHUGE, /* memory mapped huge file */ MEM_MMAPSHARED, /* use mmap with shared flag */ + MEM_IOENGINE, /* managed by I/O engine */ }; #define ERROR_STR_MAX 128
diff --git a/HOWTO b/HOWTO index 5e765d4..c2243b5 100644 --- a/HOWTO +++ b/HOWTO @@ -1195,6 +1195,10 @@ mem=str Fio can use various types of memory as the io unit buffer. mmapshared Same as mmap, but use a MMAP_SHARED mapping. + ioengine I/O engine provides iomem_alloc/free + entries to allocate and free I/O memory. + The engine is then responsible for the memory + type compatibility with other job settings. The area allocated is a function of the maximum allowed bs size for the job, multiplied by the io depth given. Note diff --git a/ioengine.h b/ioengine.h index 6734c7b..161acf5 100644 --- a/ioengine.h +++ b/ioengine.h @@ -16,7 +16,7 @@ #include <guasi.h> #endif -#define FIO_IOOPS_VERSION 22 +#define FIO_IOOPS_VERSION 23 enum { IO_U_F_FREE = 1 << 0, @@ -157,6 +157,8 @@ struct ioengine_ops { int (*unlink_file)(struct thread_data *, struct fio_file *); int (*get_file_size)(struct thread_data *, struct fio_file *); void (*terminate)(struct thread_data *); + int (*iomem_alloc)(struct thread_data *, size_t); + void (*iomem_free)(struct thread_data *); int (*io_u_init)(struct thread_data *, struct io_u *); void (*io_u_free)(struct thread_data *, struct io_u *); int option_struct_size; diff --git a/ioengines.c b/ioengines.c index decc9cb..9ef3395 100644 --- a/ioengines.c +++ b/ioengines.c @@ -22,7 +22,7 @@ static FLIST_HEAD(engine_list); -static int check_engine_ops(struct ioengine_ops *ops) +static int check_engine_ops(struct thread_options *o, struct ioengine_ops *ops) { if (ops->version != FIO_IOOPS_VERSION) { log_err("bad ioops version %d (want %d)\n", ops->version, @@ -35,6 +35,20 @@ static int check_engine_ops(struct ioengine_ops *ops) return 1; } + if (o->mem_type == MEM_IOENGINE && + !(ops->iomem_alloc && ops->iomem_free)) { + log_err("%s: iomem handler(s) missing when " + "iomem=ioengine\n", ops->name); + return 1; + } + + if (o->mem_type != MEM_IOENGINE && + (ops->iomem_alloc || ops->iomem_free)) { + log_err("%s: iomem handler(s) present when " + "iomem!=ioengine\n", ops->name); + return 1; + } + /* * sync engines only need a ->queue() */ @@ -154,7 +168,7 @@ struct ioengine_ops *load_ioengine(struct thread_data *td, const char *name) /* * Check that the required methods are there. */ - if (check_engine_ops(ops)) + if (check_engine_ops(&td->o, ops)) return NULL; ret = malloc(sizeof(*ret)); diff --git a/memory.c b/memory.c index 5060223..cf9f60a 100644 --- a/memory.c +++ b/memory.c @@ -236,6 +236,8 @@ int allocate_io_mem(struct thread_data *td) else if (td->o.mem_type == MEM_MMAP || td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAPSHARED) ret = alloc_mem_mmap(td, total_mem); + else if (td->o.mem_type == MEM_IOENGINE) + ret = td->io_ops->iomem_alloc(td, total_mem); else { log_err("fio: bad mem type: %d\n", td->o.mem_type); ret = 1; @@ -262,6 +264,8 @@ void free_io_mem(struct thread_data *td) else if (td->o.mem_type == MEM_MMAP || td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAPSHARED) free_mem_mmap(td, total_mem); + else if (td->o.mem_type == MEM_IOENGINE) + td->io_ops->iomem_free(td); else log_err("Bad memory type %u\n", td->o.mem_type); diff --git a/options.c b/options.c index 3902087..28a8fca 100644 --- a/options.c +++ b/options.c @@ -2100,6 +2100,10 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .help = "Like mmap, but use huge pages", }, #endif + { .ival = "ioengine", + .oval = MEM_IOENGINE, + .help = "I/O engine provides alloc/free methods", + }, }, }, { diff --git a/thread_options.h b/thread_options.h index 384534a..98fafa3 100644 --- a/thread_options.h +++ b/thread_options.h @@ -20,6 +20,7 @@ enum fio_memtype { MEM_MMAP, /* use anonynomous mmap */ MEM_MMAPHUGE, /* memory mapped huge file */ MEM_MMAPSHARED, /* use mmap with shared flag */ + MEM_IOENGINE, /* managed by I/O engine */ }; #define ERROR_STR_MAX 128