Skip to content

engines: add ROCm hipFile engine via shared gpuaccel layer#2113

Open
sbates130272 wants to merge 4 commits into
axboe:masterfrom
sbates130272:feat/hipfile-upstream-rebase
Open

engines: add ROCm hipFile engine via shared gpuaccel layer#2113
sbates130272 wants to merge 4 commits into
axboe:masterfrom
sbates130272:feat/hipfile-upstream-rebase

Conversation

@sbates130272

Copy link
Copy Markdown
Contributor

This series adds support for AMD ROCm hardware to fio by introducing a new
libhipfile I/O engine, structured analogously to the existing libcufile engine.
Rather than duplicating the cuFile orchestration logic, the series first
refactors libcufile.c into a shared gpuaccel layer that both backends build on.

Patch 1extracts the vendor-neutral orchestration from libcufile.c into a new
engines/gpuaccel.c / gpuaccel.h, introducing a struct gpuaccel_backend vtable
so each backend supplies only its vendor-specific calls (malloc, free, memcpy,
read, write). libcufile retains its existing behaviour as an identity transform
through the vtable; no functional change is intended for cuFile users.

Patch 2 adds sync_after_write_recv, sync_after_verify_copy, and
sync_after_verify_read_copy flags to struct gpuaccel_backend, allowing hipFile
to request extra stream-synchronize calls without ifdefs. Also moves the static
running/initialized state into the backend struct so cuFile and hipFile can
coexist in one process. No functional change to libcufile.

Patch 3 implements struct gpuaccel_backend for AMD ROCm using hipMalloc/hipFree,
hipMemcpy, and hipFileRead/hipFileWrite. Built into the fio binary (like
libcufile), enabled via --enable-libhipfile. ROCM_PATH defaults to /opt/rocm.
Exposes two new options: gpu_dev_ids (comma-separated GPU device list) and
rocm_io (hipfile for direct VRAM I/O, posix for bounce-buffer mode).

Patch 4 (examples/doc: add libhipfile example job files and documentation):
Adds examples/libhipfile-hipfile.fio and examples/libhipfile-posix.fio, and
documents the new engine, its options, and the configure flag in both HOWTO.rst
and fio.1, mirroring the existing libcufile entries.

Fixes #2111.

Signed-off-by: Zach Byrne zbyrne@amd.com
Signed-off-by: Stephen Bates sbates@raithlin.com

zbyrne added 4 commits June 29, 2026 13:47
Extract the vendor-neutral orchestration out of the NVIDIA-specific
libcufile engine so that a second GPU-accelerator backend (ROCm hipFile)
can share it without code duplication.

Steps:
 1. Extract all CUDA calls from the engine interface into thin wrappers
    inside libcufile.c, leaving the rest of the engine logic untouched.
 2. Add a small backend vtable (struct gpuaccel_backend) so the wrappers
    are reached through a function table rather than directly.
 3. Rename the now-vendor-neutral orchestration from libcufile_* to
    gpuaccel_* throughout.
 4. Move the gpuaccel core into a new engines/gpuaccel.c and gpuaccel.h;
    libcufile.c retains only the CUDA/cuFile-specific pieces.

Steps 1-4 are intended to be no-functional-change for libcufile: the
cuFile behaviour is preserved as an identity transform through the vtable.

Signed-off-by: Zach Byrne <zbyrne@amd.com>
Signed-off-by: Stephen Bates <sbates@raithlin.com>
Two independent clean-ups to the gpuaccel layer:

 * Add sync_after_write_recv, sync_after_verify_copy, and
   sync_after_verify_read_copy flags to struct gpuaccel_backend.  hipFile
   requires several extra stream-synchronize calls that cuFile does not;
   the flags let each backend declare its needs without ifdefs.  libcufile
   sets all flags to false (no behaviour change).

 * Move the static running/initialized state out of gpuaccel.c file scope
   and into struct gpuaccel_backend so that cuFile and hipFile can coexist
   in one process without sharing state.  libcufile initialises the new
   fields (no behaviour change).

Signed-off-by: Zach Byrne <zbyrne@amd.com>
Signed-off-by: Stephen Bates <sbates@raithlin.com>
Add a new fio I/O engine for AMD ROCm hardware using the HIP and hipFile
APIs.  The engine implements struct gpuaccel_backend by calling HIP
functions to allocate and manage GPU memory (hipMalloc/hipFree), copy
between VRAM and host buffers (hipMemcpy), and perform direct I/O from
VRAM via hipFileRead/hipFileWrite.

The engine is built into the fio binary like libcufile (not as a dynamic
external engine), so the shared gpuaccel symbols resolve at link time.
configure carries the full ROCm include/lib/rpath flags; the Makefile
stanza stays minimal.  ROCM_PATH defaults to /opt/rocm and can be
overridden via the environment.

New options:
  gpu_dev_ids  - comma-separated list of GPU device IDs to use
  rocm_io      - select hipfile (direct) or posix (bounce-buffer) I/O mode

Signed-off-by: Zach Byrne <zbyrne@amd.com>
Signed-off-by: Stephen Bates <sbates@raithlin.com>
Add two example fio job files for the new libhipfile engine:
  examples/libhipfile-hipfile.fio  - direct GPU I/O via hipFile
  examples/libhipfile-posix.fio    - POSIX bounce-buffer mode

Document the libhipfile engine, its gpu_dev_ids and rocm_io options, and
the --enable-libhipfile configure flag in both HOWTO.rst and fio.1,
mirroring the existing libcufile entries.

Signed-off-by: Zach Byrne <zbyrne@amd.com>
Signed-off-by: Stephen Bates <sbates@raithlin.com>
Comment thread engines/gpuaccel.c
} else {
log_err("Illegal %s IO type: %d\n", be->name, o->io_mode);
assert(0);
rc = EINVAL;

@ankit-sam ankit-sam Jun 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-EINVAL
-EIO
-ENOMEM

The convention is to return negative error. Please update here and other places below.

Comment thread engines/gpuaccel.c
assert(*be->running >= 0);
if (*be->running == 0) {
/* only close the driver if initialized and
this is the last worker thread */

@ankit-sam ankit-sam Jun 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: For multiple line comment, I feel this looks better

/*
* ...
*/

Comment thread engines/gpuaccel.c
}

if (cur)
gpu_id = atoi(cur);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For any invalid values this will return 0, which is a valid GPU ID.
This needs to be handled properly

Comment thread engines/gpuaccel.c
} else if (o->io_mode == IO_POSIX) {
sz = pread(io_u->file->fd, ((char*) io_u->xfer_buf) + xfered,
remaining, io_offset + xfered);
if (sz < 0) {

@ankit-sam ankit-sam Jun 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can return 0. So maybe that needs to be considered here and at other places.

@ankit-sam

Copy link
Copy Markdown
Contributor

One verify issue I observed, I tried the examples/libhipfile-hipfile.fio for size greater than block size

--- a/examples/libhipfile-hipfile.fio
+++ b/examples/libhipfile-hipfile.fio
@@ -15,9 +15,9 @@ rocm_io=hipfile
 direct=1
 # Performance is negatively affected if 'bs' is not a multiple of 4k.
 # Refer to ROCm hipFile documentation.
-bs=1m
-size=1m
-numjobs=16
+bs=1M
+size=4M
+numjobs=1
 # hipMalloc fails if too many processes attach to the GPU, use threads.
 thread
FIO_DIR=/mnt/nvme/sbates-fio GPU_DEV_IDS=0 ./fio examples/libhipfile-hipfile.fio --section=verify
verify: (g=0): rw=write, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=libhipfile, iodepth=1
fio-2.2.8-4632-gca7a-dirty
Starting 1 thread
verify: bad header rand_seed 1763778943062938676, wanted 46386204153304124 at file /mnt/nvme/sbates-fio/verify.0.0 offset 0, length 1048576 (requested block: offset=0, length=1048576)
fio: pid=1405170, err=84/file:io_u.c:2372, func=io_u_sync_complete, error=Invalid or incomplete multibyte or wide character

verify: (groupid=0, jobs=1): err=84 (file:io_u.c:2372, func=io_u_sync_complete, error=Invalid or incomplete multibyte or wide character): 

@sbates130272

Copy link
Copy Markdown
Contributor Author

@ankit-sam i assume that there is an NVMe SSD mounted? Also can you tell me what the output of ais-check is?

@zbyrne

zbyrne commented Jun 30, 2026

Copy link
Copy Markdown

@ankit-sam i assume that there is an NVMe SSD mounted? Also can you tell me what the output of ais-check is?

@ankit-sam in addition could you say how you built fio and where you installed/built hipfile? I wasn't able to repro the bad header issue on our test system. Thanks!

@ankit-sam

Copy link
Copy Markdown
Contributor

Hi @sbates130272 @zbyrne

ais-check

Linux yellow251 6.16.0debug+ #54 SMP PREEMPT_DYNAMIC Mon Jun 29 18:23:08 IST 2026 x86_64

AIS support in:
        Kernel P2PDMA support   : True
        HIP runtime             : True
        amdgpu                  : True

amd-smi
+------------------------------------------------------------------------------+
| AMD-SMI 26.2.2+671d39a71e    amdgpu version: 6.16.0   ROCm version: 7.2.2    |
| VBIOS version: 00158746                                                      |
| Platform: Linux Baremetal                                                    |
|-------------------------------------+----------------------------------------|
| BDF                        GPU-Name | Mem-Uti   Temp   UEC       Power-Usage |
| GPU  HIP-ID  OAM-ID  Partition-Mode | GFX-Uti    Fan               Mem-Usage |
|=====================================+========================================|
| 0000:04:00.0    AMD Radeon Graphics | 0 %      28 °C   0            38/300 W |
|   0       0     N/A             N/A | 14 %    20.0 %             57/32624 MB |
+-------------------------------------+----------------------------------------+
+------------------------------------------------------------------------------+
| Processes:                                                                   |
|  GPU        PID  Process Name          GTT_MEM  VRAM_MEM  MEM_USAGE     CU % |
|==============================================================================|
|  No running processes found                                                  |
+------------------------------------------------------------------------------+

Yes, its NVMe SSD mounted

mount | grep nvme
/dev/nvme1n1p1 on /mnt/nvme type ext4 (rw,relatime)

The setup I have is with rocm-7.2.2, and by default fio configure couldn't find it so made a couple of changes to the configure

git diff
index 804db167..97c841f9 100755
--- a/configure
+++ b/configure
@@ -2892,8 +2892,8 @@ int main(int argc, char* argv[]) {
 }
 EOF
   ROCM_PATH="${ROCM_PATH:-/opt/rocm}"
-  HIPFILE_CFLAGS="-D__HIP_PLATFORM_AMD__ -I${ROCM_PATH}/include"
-  HIPFILE_LIBS="-L${ROCM_PATH}/lib -Wl,-rpath,${ROCM_PATH}/lib -lamdhip64 -lhipfile"
+  HIPFILE_CFLAGS="-I${ROCM_PATH}/include -I/opt/rocm-7.2.2/include -D__HIP_PLATFORM_AMD__"
+  HIPFILE_LIBS="-L${ROCM_PATH}/lib -L/opt/rocm-7.2.2/lib -lamdhip64 -lhipfile"
   if compile_prog "$HIPFILE_CFLAGS" "$HIPFILE_LIBS" "libhipfile"; then
     libhipfile="yes"

I build fio by doing

./configure --enable-libhipfile
make

I added a debug log in fio to figure out the issue

diff --git a/verify.c b/verify.c
index 633a9bb2..a5882ba4 100644
--- a/verify.c
+++ b/verify.c
@@ -63,6 +63,7 @@ void fill_verify_pattern(struct thread_data *td, void *p, unsigned int len,
                                seed *= (unsigned long)__rand(&td->verify_state);
                }
                io_u->rand_seed = seed;
+               log_info("fill: rand_seed %"PRIu64"\n", io_u->rand_seed);
                __fill_buffer(o, seed, p, len);
FIO_DIR=/mnt/nvme/sbates-fio GPU_DEV_IDS=0 ./fio examples/libhipfile-hipfile.fio --section=verify
verify: (g=0): rw=write, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=libhipfile, iodepth=1
fio-2.2.8-4632-gca7a-dirty
Starting 1 thread
verify: Laying out IO file (1 file / 4MiB)
fill: rand_seed 46386204153304124
fill: rand_seed 9852480210356360750
fill: rand_seed 4726550845720924880
fill: rand_seed 1763778943062938676
verify: bad header rand_seed 1763778943062938676, wanted 46386204153304124 at file /mnt/nvme/sbates-fio/verify.0.0 offset 0, length 1048576 (requested block: offset=0, length=1048576)
fio: pid=3148870, err=84/file:io_u.c:2372, func=io_u_sync_complete, error=Invalid or incomplete multibyte or wide character

verify: (groupid=0, jobs=1): err=84 (file:io_u.c:2372, func=io_u_sync_complete, error=Invalid or incomplete multibyte or wide character): pid=3148870: Wed Jul  1 10:51:47 2026

The issue seems to be a bit weird, its trying to match the last rand_seed to the first one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature]: Add a new IO engine for AMD GPUs via the hipFile API

3 participants