* [PATCH v2 0/2] Introduce a page_fault ioengine for MM workflows
@ 2026-03-11 15:51 Nico Pache
2026-03-11 15:51 ` [PATCH v2 1/2] page_fault: add mmap-backed ioengine for anonymous faults Nico Pache
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Nico Pache @ 2026-03-11 15:51 UTC (permalink / raw)
To: vincentfu, axboe, fio; +Cc: jvozar, jjurca, jhladky, peterx, spetrovi, david
This series introduces a new page_fault ioengine for Anonymous memory
testing. This enables using fio’s existing framework and job files for
memory management style workloads without relying on a filesystem. An
example job file is included to demonstrate usage.
The first patch adds the mmap‑backed ioengine that allocates anonymous
memory and copies data on read/write to intentionally trigger faults.
The second patch updates the documentation to guide usage of the new
feature.
V2:
- drop the khugepaged_delay, and all other additional features. This
provides a clean initial implmentation. Further features will be added
in future series as we keep testing and discover what will be useful
for functional and performance testing.
- Changed the byte-by-byte r/w to leverage memcpy
- provide a number of test cases
- hardened the engine by limiting what parameters it can accept,
preventing undefined or broken behavior
- Use clang-format to adhere to formatting conventions
Signed-off-by: Nico Pache <npache@redhat.com>
Nico Pache (2):
page_fault: add mmap-backed ioengine for anonymous faults
Documentation: update the HOWTO to include the page_fault engine
HOWTO.rst | 5 ++
Makefile | 2 +-
engines/page_fault.c | 116 ++++++++++++++++++++++++++++++++++++++++
examples/page_fault.fio | 60 +++++++++++++++++++++
4 files changed, 182 insertions(+), 1 deletion(-)
create mode 100644 engines/page_fault.c
create mode 100644 examples/page_fault.fio
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/2] page_fault: add mmap-backed ioengine for anonymous faults
2026-03-11 15:51 [PATCH v2 0/2] Introduce a page_fault ioengine for MM workflows Nico Pache
@ 2026-03-11 15:51 ` Nico Pache
2026-03-12 13:34 ` Vincent Fu
2026-03-11 15:51 ` [PATCH v2 2/2] Documentation: update the HOWTO to include the page_fault engine Nico Pache
2026-03-11 17:08 ` [PATCH v2 0/2] Introduce a page_fault ioengine for MM workflows fiotestbot
2 siblings, 1 reply; 7+ messages in thread
From: Nico Pache @ 2026-03-11 15:51 UTC (permalink / raw)
To: vincentfu, axboe, fio; +Cc: jvozar, jjurca, jhladky, peterx, spetrovi, david
Introduce a new ioengine that mmaps anonymous memory and copies data
on read/write to trigger page faults. This allows us to leverage FIOs
powerful framework for MM related testing, and will ideally allow us to
quickly expand testing, by leveraging previously FS related fio scripts.
Signed-off-by: Nico Pache <npache@redhat.com>
---
Makefile | 2 +-
engines/page_fault.c | 116 ++++++++++++++++++++++++++++++++++++++++
examples/page_fault.fio | 60 +++++++++++++++++++++
3 files changed, 177 insertions(+), 1 deletion(-)
create mode 100644 engines/page_fault.c
create mode 100644 examples/page_fault.fio
diff --git a/Makefile b/Makefile
index 0337e8fe..099e2f94 100644
--- a/Makefile
+++ b/Makefile
@@ -57,7 +57,7 @@ SOURCE := $(sort $(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/crc/*.c)) \
smalloc.c filehash.c profile.c debug.c engines/cpu.c \
engines/mmap.c engines/sync.c engines/null.c engines/net.c \
engines/ftruncate.c engines/fileoperations.c \
- engines/exec.c \
+ engines/exec.c engines/page_fault.c \
server.c client.c iolog.c backend.c libfio.c flow.c cconv.c \
gettime-thread.c helpers.c json.c idletime.c td_error.c \
profiles/tiobench.c profiles/act.c io_u_queue.c filelock.c \
diff --git a/engines/page_fault.c b/engines/page_fault.c
new file mode 100644
index 00000000..88108644
--- /dev/null
+++ b/engines/page_fault.c
@@ -0,0 +1,116 @@
+/*
+ * page_fault engine
+ *
+ * IO engine that reads/writes directly to/from anonymous memory
+ * by triggering page faults.
+ */
+#include "fio.h"
+#include "ioengines.h"
+#include <sys/mman.h>
+
+struct fio_page_fault_data {
+ void *mmap_ptr;
+ size_t mmap_sz;
+};
+
+static int fio_page_fault_init(struct thread_data *td) {
+ size_t total_io_size;
+ struct fio_page_fault_data *fpd;
+
+ if (td->o.nr_files > 1) {
+ log_err("page_fault engine does not support multiple files\n");
+ return 1;
+ }
+
+ fpd = calloc(1, sizeof(*fpd));
+ if (!fpd)
+ return 1;
+
+ total_io_size = td->o.size;
+ fpd->mmap_sz = total_io_size;
+ fpd->mmap_ptr = mmap(NULL, total_io_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (fpd->mmap_ptr == MAP_FAILED) {
+ free(fpd);
+ return 1;
+ }
+
+ td->io_ops_data = fpd;
+ FILE_SET_ENG_DATA(td->files[0], fpd);
+ return 0;
+}
+
+static enum fio_q_status fio_page_fault_queue(struct thread_data *td,
+ struct io_u *io_u) {
+ void *mmap_head;
+ struct fio_page_fault_data *fpd = FILE_ENG_DATA(io_u->file);
+ if (!fpd) {
+ io_u->error = EINVAL;
+ return FIO_Q_COMPLETED;
+ }
+
+ if (io_u->offset + io_u->buflen > fpd->mmap_sz) {
+ io_u->error = EINVAL;
+ return FIO_Q_COMPLETED;
+ }
+
+ mmap_head = fpd->mmap_ptr + io_u->offset;
+ switch (io_u->ddir) {
+ case DDIR_READ:
+ memcpy(io_u->xfer_buf, mmap_head, io_u->buflen);
+ break;
+ case DDIR_WRITE:
+ memcpy(mmap_head, io_u->xfer_buf, io_u->buflen);
+ break;
+ case DDIR_SYNC:
+ case DDIR_DATASYNC:
+ case DDIR_SYNC_FILE_RANGE:
+ case DDIR_SYNCFS:
+ break;
+ default:
+ io_u->error = EINVAL;
+ break;
+ }
+
+ return FIO_Q_COMPLETED;
+}
+
+static int fio_page_fault_open_file(struct thread_data *td,
+ struct fio_file *f) {
+ return 0;
+}
+
+static int fio_page_fault_close_file(struct thread_data *td,
+ struct fio_file *f) {
+ return 0;
+}
+
+static void fio_page_fault_cleanup(struct thread_data *td) {
+ struct fio_page_fault_data *fpd = td->io_ops_data;
+
+ if (!fpd)
+ return;
+ if (fpd->mmap_ptr && fpd->mmap_sz)
+ munmap(fpd->mmap_ptr, fpd->mmap_sz);
+ free(fpd);
+}
+
+static struct ioengine_ops ioengine = {
+ .name = "page_fault",
+ .version = FIO_IOOPS_VERSION,
+ .init = fio_page_fault_init,
+ .cleanup = fio_page_fault_cleanup,
+ .queue = fio_page_fault_queue,
+ .open_file = fio_page_fault_open_file,
+ .close_file = fio_page_fault_close_file,
+ .get_file_size = generic_get_file_size,
+ .flags = FIO_SYNCIO | FIO_NOEXTEND | FIO_DISKLESSIO,
+};
+
+static void fio_init fio_page_fault_register(void) {
+ register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_page_fault_unregister(void) {
+ unregister_ioengine(&ioengine);
+}
\ No newline at end of file
diff --git a/examples/page_fault.fio b/examples/page_fault.fio
new file mode 100644
index 00000000..4a49fb7d
--- /dev/null
+++ b/examples/page_fault.fio
@@ -0,0 +1,60 @@
+[global]
+stonewall
+ioengine=page_fault
+size=5*1024*1024*$mb_memory/8 # 5/8 of the memory
+bs=$pagesize
+
+[page_fault_write]
+rw=write
+
+[page_fault_mixed]
+rw=randrw
+rwmixread=50
+
+[page_fault_process_storm]
+size=8*1024*$pagesize
+rw=randrw
+rwmixread=50
+numjobs=$ncpus
+
+[page_fault_mthp]
+bsrange=16k-1M
+blockalign=2M
+rw=write
+
+[page_fault_seq_read]
+rw=read
+
+[page_fault_rand_read]
+rw=randread
+
+[page_fault_rand_write]
+rw=randwrite
+
+[page_fault_warm]
+rw=randrw
+rwmixread=50
+loops=3
+
+[page_fault_read_heavy]
+rw=randrw
+rwmixread=90
+
+[page_fault_write_heavy]
+rw=randrw
+rwmixread=10
+
+[page_fault_large_block]
+bs=2M
+blockalign=2M
+rw=write
+
+[page_fault_cache_hot]
+size=64*$pagesize
+rw=randrw
+rwmixread=50
+loops=100
+
+[page_fault_pressure]
+size=7*1024*1024*$mb_memory/8 # 7/8 of the memory
+rw=write
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] Documentation: update the HOWTO to include the page_fault engine
2026-03-11 15:51 [PATCH v2 0/2] Introduce a page_fault ioengine for MM workflows Nico Pache
2026-03-11 15:51 ` [PATCH v2 1/2] page_fault: add mmap-backed ioengine for anonymous faults Nico Pache
@ 2026-03-11 15:51 ` Nico Pache
2026-03-12 13:35 ` Vincent Fu
2026-03-11 17:08 ` [PATCH v2 0/2] Introduce a page_fault ioengine for MM workflows fiotestbot
2 siblings, 1 reply; 7+ messages in thread
From: Nico Pache @ 2026-03-11 15:51 UTC (permalink / raw)
To: vincentfu, axboe, fio; +Cc: jvozar, jjurca, jhladky, peterx, spetrovi, david
Document the new page fault engine.
Signed-off-by: Nico Pache <npache@redhat.com>
---
HOWTO.rst | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/HOWTO.rst b/HOWTO.rst
index e712ee2e..421e6408 100644
--- a/HOWTO.rst
+++ b/HOWTO.rst
@@ -2376,6 +2376,11 @@ I/O engine
several instances to access the same device or file
simultaneously, but allow it for threads.
+ **page_fault**
+ I/O engine that uses an mmap region to simulate data transfer by
+ allocating anonymous memory and copying data on read/write to
+ intentionally trigger page faults.
+
File/directory operation engines define how the job operates file or directory. The
following types are defined:
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 0/2] Introduce a page_fault ioengine for MM workflows
2026-03-11 15:51 [PATCH v2 0/2] Introduce a page_fault ioengine for MM workflows Nico Pache
2026-03-11 15:51 ` [PATCH v2 1/2] page_fault: add mmap-backed ioengine for anonymous faults Nico Pache
2026-03-11 15:51 ` [PATCH v2 2/2] Documentation: update the HOWTO to include the page_fault engine Nico Pache
@ 2026-03-11 17:08 ` fiotestbot
2 siblings, 0 replies; 7+ messages in thread
From: fiotestbot @ 2026-03-11 17:08 UTC (permalink / raw)
To: fio
[-- Attachment #1: Type: text/plain, Size: 144 bytes --]
The result of fio's continuous integration tests was: success
For more details see https://github.com/fiotestbot/fio/actions/runs/22962368664
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] page_fault: add mmap-backed ioengine for anonymous faults
2026-03-11 15:51 ` [PATCH v2 1/2] page_fault: add mmap-backed ioengine for anonymous faults Nico Pache
@ 2026-03-12 13:34 ` Vincent Fu
2026-03-12 17:37 ` Nico Pache
0 siblings, 1 reply; 7+ messages in thread
From: Vincent Fu @ 2026-03-12 13:34 UTC (permalink / raw)
To: Nico Pache; +Cc: axboe, fio, jvozar, jjurca, jhladky, peterx, spetrovi, david
On Wed, Mar 11, 2026 at 11:52 AM Nico Pache <npache@redhat.com> wrote:
>
> Introduce a new ioengine that mmaps anonymous memory and copies data
> on read/write to trigger page faults. This allows us to leverage FIOs
> powerful framework for MM related testing, and will ideally allow us to
> quickly expand testing, by leveraging previously FS related fio scripts.
>
> Signed-off-by: Nico Pache <npache@redhat.com>
> ---
> Makefile | 2 +-
> engines/page_fault.c | 116 ++++++++++++++++++++++++++++++++++++++++
> examples/page_fault.fio | 60 +++++++++++++++++++++
> 3 files changed, 177 insertions(+), 1 deletion(-)
> create mode 100644 engines/page_fault.c
> create mode 100644 examples/page_fault.fio
>
> diff --git a/Makefile b/Makefile
> index 0337e8fe..099e2f94 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -57,7 +57,7 @@ SOURCE := $(sort $(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/crc/*.c)) \
> smalloc.c filehash.c profile.c debug.c engines/cpu.c \
> engines/mmap.c engines/sync.c engines/null.c engines/net.c \
> engines/ftruncate.c engines/fileoperations.c \
> - engines/exec.c \
> + engines/exec.c engines/page_fault.c \
> server.c client.c iolog.c backend.c libfio.c flow.c cconv.c \
> gettime-thread.c helpers.c json.c idletime.c td_error.c \
> profiles/tiobench.c profiles/act.c io_u_queue.c filelock.c \
> diff --git a/engines/page_fault.c b/engines/page_fault.c
> new file mode 100644
> index 00000000..88108644
> --- /dev/null
> +++ b/engines/page_fault.c
> @@ -0,0 +1,116 @@
> +/*
> + * page_fault engine
> + *
> + * IO engine that reads/writes directly to/from anonymous memory
> + * by triggering page faults.
> + */
> +#include "fio.h"
> +#include "ioengines.h"
> +#include <sys/mman.h>
> +
> +struct fio_page_fault_data {
> + void *mmap_ptr;
> + size_t mmap_sz;
> +};
> +
> +static int fio_page_fault_init(struct thread_data *td) {
The style we follow is to put the { on a new line. Also please use
tabs. We basically follow the kernel's style conventions. Did you use
the default LLVM conventions with clang-format?
> + size_t total_io_size;
> + struct fio_page_fault_data *fpd;
> +
> + if (td->o.nr_files > 1) {
> + log_err("page_fault engine does not support multiple files\n");
How about, "fio: page_fault ioengine ..."?
> + return 1;
> + }
Consider checking that td->o.offset == 0 and emitting an error message
saying that the offset option must be zero for this ioengine to work.
> +
> + fpd = calloc(1, sizeof(*fpd));
> + if (!fpd)
> + return 1;
> +
> + total_io_size = td->o.size;
> + fpd->mmap_sz = total_io_size;
> + fpd->mmap_ptr = mmap(NULL, total_io_size, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> + if (fpd->mmap_ptr == MAP_FAILED) {
> + free(fpd);
> + return 1;
> + }
> +
> + td->io_ops_data = fpd;
> + FILE_SET_ENG_DATA(td->files[0], fpd);
I would avoid directly manipulating files[] here. Since there is only
a single instance of fpd, why not omit this and just access fpd via
td->io_ops_data in queue()?
Vincent
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] Documentation: update the HOWTO to include the page_fault engine
2026-03-11 15:51 ` [PATCH v2 2/2] Documentation: update the HOWTO to include the page_fault engine Nico Pache
@ 2026-03-12 13:35 ` Vincent Fu
0 siblings, 0 replies; 7+ messages in thread
From: Vincent Fu @ 2026-03-12 13:35 UTC (permalink / raw)
To: Nico Pache; +Cc: axboe, fio, jvozar, jjurca, jhladky, peterx, spetrovi, david
On Wed, Mar 11, 2026 at 11:52 AM Nico Pache <npache@redhat.com> wrote:
>
> Document the new page fault engine.
>
> Signed-off-by: Nico Pache <npache@redhat.com>
> ---
> HOWTO.rst | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/HOWTO.rst b/HOWTO.rst
> index e712ee2e..421e6408 100644
> --- a/HOWTO.rst
> +++ b/HOWTO.rst
> @@ -2376,6 +2376,11 @@ I/O engine
> several instances to access the same device or file
> simultaneously, but allow it for threads.
>
> + **page_fault**
> + I/O engine that uses an mmap region to simulate data transfer by
> + allocating anonymous memory and copying data on read/write to
> + intentionally trigger page faults.
> +
> File/directory operation engines define how the job operates file or directory. The
> following types are defined:
>
> --
> 2.53.0
>
Please also make the same change to fio.1
Vincent
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] page_fault: add mmap-backed ioengine for anonymous faults
2026-03-12 13:34 ` Vincent Fu
@ 2026-03-12 17:37 ` Nico Pache
0 siblings, 0 replies; 7+ messages in thread
From: Nico Pache @ 2026-03-12 17:37 UTC (permalink / raw)
To: Vincent Fu; +Cc: axboe, fio, jvozar, jjurca, jhladky, peterx, spetrovi, david
On Thu, Mar 12, 2026 at 7:34 AM Vincent Fu <vincentfu@gmail.com> wrote:
>
> On Wed, Mar 11, 2026 at 11:52 AM Nico Pache <npache@redhat.com> wrote:
> >
> > Introduce a new ioengine that mmaps anonymous memory and copies data
> > on read/write to trigger page faults. This allows us to leverage FIOs
> > powerful framework for MM related testing, and will ideally allow us to
> > quickly expand testing, by leveraging previously FS related fio scripts.
> >
> > Signed-off-by: Nico Pache <npache@redhat.com>
> > ---
> > Makefile | 2 +-
> > engines/page_fault.c | 116 ++++++++++++++++++++++++++++++++++++++++
> > examples/page_fault.fio | 60 +++++++++++++++++++++
> > 3 files changed, 177 insertions(+), 1 deletion(-)
> > create mode 100644 engines/page_fault.c
> > create mode 100644 examples/page_fault.fio
> >
> > diff --git a/Makefile b/Makefile
> > index 0337e8fe..099e2f94 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -57,7 +57,7 @@ SOURCE := $(sort $(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/crc/*.c)) \
> > smalloc.c filehash.c profile.c debug.c engines/cpu.c \
> > engines/mmap.c engines/sync.c engines/null.c engines/net.c \
> > engines/ftruncate.c engines/fileoperations.c \
> > - engines/exec.c \
> > + engines/exec.c engines/page_fault.c \
> > server.c client.c iolog.c backend.c libfio.c flow.c cconv.c \
> > gettime-thread.c helpers.c json.c idletime.c td_error.c \
> > profiles/tiobench.c profiles/act.c io_u_queue.c filelock.c \
> > diff --git a/engines/page_fault.c b/engines/page_fault.c
> > new file mode 100644
> > index 00000000..88108644
> > --- /dev/null
> > +++ b/engines/page_fault.c
> > @@ -0,0 +1,116 @@
> > +/*
> > + * page_fault engine
> > + *
> > + * IO engine that reads/writes directly to/from anonymous memory
> > + * by triggering page faults.
> > + */
> > +#include "fio.h"
> > +#include "ioengines.h"
> > +#include <sys/mman.h>
> > +
> > +struct fio_page_fault_data {
> > + void *mmap_ptr;
> > + size_t mmap_sz;
> > +};
> > +
> > +static int fio_page_fault_init(struct thread_data *td) {
>
> The style we follow is to put the { on a new line. Also please use
> tabs. We basically follow the kernel's style conventions. Did you use
> the default LLVM conventions with clang-format?
Hmm perhaps I called clang-format incorrectly. I assumed it would read
the format file automatically but that is not the case. Sorry, first
time using the clang-format function.
>
> > + size_t total_io_size;
> > + struct fio_page_fault_data *fpd;
> > +
> > + if (td->o.nr_files > 1) {
> > + log_err("page_fault engine does not support multiple files\n");
>
> How about, "fio: page_fault ioengine ..."?
Sounds good, yeah I wasnt thinking about the reporting format you guys
use. Ill keep that in mind.
>
> > + return 1;
> > + }
>
> Consider checking that td->o.offset == 0 and emitting an error message
> saying that the offset option must be zero for this ioengine to work.
Hmm, I didnt even notice, but while doing my cleanup and ripping out
the other features I added I accidently removed the offset...
Ill add that back. Thanks :)
>
> > +
> > + fpd = calloc(1, sizeof(*fpd));
> > + if (!fpd)
> > + return 1;
> > +
> > + total_io_size = td->o.size;
> > + fpd->mmap_sz = total_io_size;
> > + fpd->mmap_ptr = mmap(NULL, total_io_size, PROT_READ | PROT_WRITE,
> > + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> > + if (fpd->mmap_ptr == MAP_FAILED) {
> > + free(fpd);
> > + return 1;
> > + }
> > +
> > + td->io_ops_data = fpd;
> > + FILE_SET_ENG_DATA(td->files[0], fpd);
>
> I would avoid directly manipulating files[] here. Since there is only
> a single instance of fpd, why not omit this and just access fpd via
> td->io_ops_data in queue()?
Yeah I had to switch to using io_ops_data directly and use the cleanup
hook (rather than close_file) because of a bug I found, but now it
just looks messy. Ill clean it up as you suggested! thanks.
Cheers,
-- Nico
>
> Vincent
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-03-12 17:37 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-11 15:51 [PATCH v2 0/2] Introduce a page_fault ioengine for MM workflows Nico Pache
2026-03-11 15:51 ` [PATCH v2 1/2] page_fault: add mmap-backed ioengine for anonymous faults Nico Pache
2026-03-12 13:34 ` Vincent Fu
2026-03-12 17:37 ` Nico Pache
2026-03-11 15:51 ` [PATCH v2 2/2] Documentation: update the HOWTO to include the page_fault engine Nico Pache
2026-03-12 13:35 ` Vincent Fu
2026-03-11 17:08 ` [PATCH v2 0/2] Introduce a page_fault ioengine for MM workflows fiotestbot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox