summaryrefslogtreecommitdiff
path: root/0001-Revert-pmemblk-remove-pmemblk-engine.patch
diff options
context:
space:
mode:
Diffstat (limited to '0001-Revert-pmemblk-remove-pmemblk-engine.patch')
-rw-r--r--0001-Revert-pmemblk-remove-pmemblk-engine.patch722
1 files changed, 722 insertions, 0 deletions
diff --git a/0001-Revert-pmemblk-remove-pmemblk-engine.patch b/0001-Revert-pmemblk-remove-pmemblk-engine.patch
new file mode 100644
index 0000000..38749db
--- /dev/null
+++ b/0001-Revert-pmemblk-remove-pmemblk-engine.patch
@@ -0,0 +1,722 @@
+From 2383a1ec2ad9090259f6d200b92676acff37de3b Mon Sep 17 00:00:00 2001
+From: Pavel Reichl <preichl@redhat.com>
+Date: Fri, 9 Jun 2023 18:18:48 +0200
+Subject: [PATCH] Revert "pmemblk: remove pmemblk engine"
+
+This reverts commit 04c1cdc4c108c6537681ab7c50daaed6d2fb4c93.
+
+Signed-off-by: Pavel Reichl <preichl@redhat.com>
+---
+ HOWTO.rst | 5 +
+ Makefile | 5 +
+ ci/actions-install.sh | 1 +
+ configure | 41 ++++
+ engines/pmemblk.c | 449 ++++++++++++++++++++++++++++++++++++++++
+ examples/pmemblk.fio | 71 +++++++
+ fio.1 | 5 +
+ options.c | 6 +
+ os/windows/examples.wxs | 4 +
+ 10 files changed, 587 insertions(+)
+ create mode 100644 engines/pmemblk.c
+ create mode 100644 examples/pmemblk.fio
+
+diff --git a/HOWTO.rst b/HOWTO.rst
+index 32fff5ecbde42cf894214f766f38130dba079760..4f003524f69e5cced1195fb0f7efcc2590648122 100644
+--- a/HOWTO.rst
++++ b/HOWTO.rst
+@@ -2147,6 +2147,11 @@ I/O engine
+ before overwriting. The `trimwrite` mode works well for this
+ constraint.
+
++ **pmemblk**
++ Read and write using filesystem DAX to a file on a filesystem
++ mounted with DAX on a persistent memory device through the PMDK
++ libpmemblk library.
++
+ **dev-dax**
+ Read and write using device DAX to a persistent memory device (e.g.,
+ /dev/dax0.0) through the PMDK libpmem library.
+diff --git a/Makefile b/Makefile
+index 6d7fd4e2bbbdeb196d22299d379bebb29172d538..89205ebf498f957ceedefdf1b0e565f08c85060f 100644
+--- a/Makefile
++++ b/Makefile
+@@ -208,6 +208,11 @@ ifdef CONFIG_MTD
+ SOURCE += oslib/libmtd.c
+ SOURCE += oslib/libmtd_legacy.c
+ endif
++ifdef CONFIG_PMEMBLK
++ pmemblk_SRCS = engines/pmemblk.c
++ pmemblk_LIBS = -lpmemblk
++ ENGINES += pmemblk
++endif
+ ifdef CONFIG_LINUX_DEVDAX
+ dev-dax_SRCS = engines/dev-dax.c
+ dev-dax_LIBS = -lpmem
+diff --git a/ci/actions-install.sh b/ci/actions-install.sh
+index 95241e78825a9939814a747daf486f866949e392..2f1a0cbaeef4b528a93813d18b94f9bc041bfa04 100755
+--- a/ci/actions-install.sh
++++ b/ci/actions-install.sh
+@@ -47,6 +47,7 @@ DPKGCFG
+ libnbd-dev
+ libpmem-dev
+ libpmem2-dev
++ libpmemblk-dev
+ libprotobuf-c-dev
+ librbd-dev
+ libtcmalloc-minimal4
+diff --git a/configure b/configure
+index 74416fd48bc73e35cd8fd5440b9733efd1d0adbb..f6b160c99d374034ba308b74a306e3eb1570be1e 100755
+--- a/configure
++++ b/configure
+@@ -163,6 +163,7 @@ show_help="no"
+ exit_val=0
+ gfio_check="no"
+ libhdfs="no"
++pmemblk="no"
+ devdax="no"
+ pmem="no"
+ cuda="no"
+@@ -2260,6 +2261,43 @@ if test "$libpmem" = "yes" && test "$disable_pmem" = "no"; then
+ fi
+ fi
+
++##########################################
++# Check whether we have libpmemblk
++# libpmem is a prerequisite
++if test "$libpmemblk" != "yes" ; then
++ libpmemblk="no"
++fi
++if test "$libpmem" = "yes"; then
++ cat > $TMPC << EOF
++#include <libpmemblk.h>
++int main(int argc, char **argv)
++{
++ PMEMblkpool *pbp;
++ pbp = pmemblk_open("", 0);
++ return 0;
++}
++EOF
++ if compile_prog "" "-lpmemblk" "libpmemblk"; then
++ libpmemblk="yes"
++ fi
++fi
++print_config "libpmemblk" "$libpmemblk"
++
++# Choose libpmem-based ioengines
++if test "$libpmem" = "yes" && test "$disable_pmem" = "no"; then
++ devdax="yes"
++ if test "$libpmem1_5" = "yes"; then
++ pmem="yes"
++ fi
++ if test "$libpmemblk" = "yes"; then
++ pmemblk="yes"
++ fi
++fi
++
++##########################################
++# Report whether pmemblk engine is enabled
++print_config "PMDK pmemblk engine" "$pmemblk"
++
+ ##########################################
+ # Report whether dev-dax engine is enabled
+ print_config "PMDK dev-dax engine" "$devdax"
+@@ -3188,6 +3226,9 @@ fi
+ if test "$mtd" = "yes" ; then
+ output_sym "CONFIG_MTD"
+ fi
++if test "$pmemblk" = "yes" ; then
++ output_sym "CONFIG_PMEMBLK"
++fi
+ if test "$devdax" = "yes" ; then
+ output_sym "CONFIG_LINUX_DEVDAX"
+ fi
+diff --git a/engines/pmemblk.c b/engines/pmemblk.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..849d8a15a0da59d07209c2475b78a1e4098c143a
+--- /dev/null
++++ b/engines/pmemblk.c
+@@ -0,0 +1,449 @@
++/*
++ * pmemblk: IO engine that uses PMDK libpmemblk to read and write data
++ *
++ * Copyright (C) 2016 Hewlett Packard Enterprise Development LP
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License,
++ * version 2 as published by the Free Software Foundation..
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public
++ * License along with this program; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++
++/*
++ * pmemblk engine
++ *
++ * IO engine that uses libpmemblk to read and write data
++ *
++ * To use:
++ * ioengine=pmemblk
++ *
++ * Other relevant settings:
++ * thread=1 REQUIRED
++ * iodepth=1
++ * direct=1
++ * unlink=1
++ * filename=/mnt/pmem0/fiotestfile,BSIZE,FSIZEMiB
++ *
++ * thread must be set to 1 for pmemblk as multiple processes cannot
++ * open the same block pool file.
++ *
++ * iodepth should be set to 1 as pmemblk is always synchronous.
++ * Use numjobs to scale up.
++ *
++ * direct=1 is implied as pmemblk is always direct. A warning message
++ * is printed if this is not specified.
++ *
++ * unlink=1 removes the block pool file after testing, and is optional.
++ *
++ * The pmem device must have a DAX-capable filesystem and be mounted
++ * with DAX enabled. filename must point to a file on that filesystem.
++ *
++ * Example:
++ * mkfs.xfs /dev/pmem0
++ * mkdir /mnt/pmem0
++ * mount -o dax /dev/pmem0 /mnt/pmem0
++ *
++ * When specifying the filename, if the block pool file does not already
++ * exist, then the pmemblk engine creates the pool file if you specify
++ * the block and file sizes. BSIZE is the block size in bytes.
++ * FSIZEMB is the pool file size in MiB.
++ *
++ * See examples/pmemblk.fio for more.
++ *
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/uio.h>
++#include <errno.h>
++#include <assert.h>
++#include <string.h>
++#include <libpmem.h>
++#include <libpmemblk.h>
++
++#include "../fio.h"
++
++/*
++ * libpmemblk
++ */
++typedef struct fio_pmemblk_file *fio_pmemblk_file_t;
++
++struct fio_pmemblk_file {
++ fio_pmemblk_file_t pmb_next;
++ char *pmb_filename;
++ uint64_t pmb_refcnt;
++ PMEMblkpool *pmb_pool;
++ size_t pmb_bsize;
++ size_t pmb_nblocks;
++};
++
++static fio_pmemblk_file_t Cache;
++
++static pthread_mutex_t CacheLock = PTHREAD_MUTEX_INITIALIZER;
++
++#define PMB_CREATE (0x0001) /* should create file */
++
++fio_pmemblk_file_t fio_pmemblk_cache_lookup(const char *filename)
++{
++ fio_pmemblk_file_t i;
++
++ for (i = Cache; i != NULL; i = i->pmb_next)
++ if (!strcmp(filename, i->pmb_filename))
++ return i;
++
++ return NULL;
++}
++
++static void fio_pmemblk_cache_insert(fio_pmemblk_file_t pmb)
++{
++ pmb->pmb_next = Cache;
++ Cache = pmb;
++}
++
++static void fio_pmemblk_cache_remove(fio_pmemblk_file_t pmb)
++{
++ fio_pmemblk_file_t i;
++
++ if (pmb == Cache) {
++ Cache = Cache->pmb_next;
++ pmb->pmb_next = NULL;
++ return;
++ }
++
++ for (i = Cache; i != NULL; i = i->pmb_next)
++ if (pmb == i->pmb_next) {
++ i->pmb_next = i->pmb_next->pmb_next;
++ pmb->pmb_next = NULL;
++ return;
++ }
++}
++
++/*
++ * to control block size and gross file size at the libpmemblk
++ * level, we allow the block size and file size to be appended
++ * to the file name:
++ *
++ * path[,bsize,fsizemib]
++ *
++ * note that we do not use the fio option "filesize" to dictate
++ * the file size because we can only give libpmemblk the gross
++ * file size, which is different from the net or usable file
++ * size (which is probably what fio wants).
++ *
++ * the final path without the parameters is returned in ppath.
++ * the block size and file size are returned in pbsize and fsize.
++ *
++ * note that the user specifies the file size in MiB, but
++ * we return bytes from here.
++ */
++static void pmb_parse_path(const char *pathspec, char **ppath, uint64_t *pbsize,
++ uint64_t *pfsize)
++{
++ char *path;
++ char *s;
++ uint64_t bsize;
++ uint64_t fsizemib;
++
++ path = strdup(pathspec);
++ if (!path) {
++ *ppath = NULL;
++ return;
++ }
++
++ /* extract sizes, if given */
++ s = strrchr(path, ',');
++ if (s && (fsizemib = strtoull(s + 1, NULL, 10))) {
++ *s = 0;
++ s = strrchr(path, ',');
++ if (s && (bsize = strtoull(s + 1, NULL, 10))) {
++ *s = 0;
++ *ppath = path;
++ *pbsize = bsize;
++ *pfsize = fsizemib << 20;
++ return;
++ }
++ }
++
++ /* size specs not found */
++ strcpy(path, pathspec);
++ *ppath = path;
++ *pbsize = 0;
++ *pfsize = 0;
++}
++
++static fio_pmemblk_file_t pmb_open(const char *pathspec, int flags)
++{
++ fio_pmemblk_file_t pmb;
++ char *path = NULL;
++ uint64_t bsize = 0;
++ uint64_t fsize = 0;
++
++ pmb_parse_path(pathspec, &path, &bsize, &fsize);
++ if (!path)
++ return NULL;
++
++ pthread_mutex_lock(&CacheLock);
++
++ pmb = fio_pmemblk_cache_lookup(path);
++ if (!pmb) {
++ pmb = malloc(sizeof(*pmb));
++ if (!pmb)
++ goto error;
++
++ /* try opening existing first, create it if needed */
++ pmb->pmb_pool = pmemblk_open(path, bsize);
++ if (!pmb->pmb_pool && (errno == ENOENT) &&
++ (flags & PMB_CREATE) && (0 < fsize) && (0 < bsize)) {
++ pmb->pmb_pool =
++ pmemblk_create(path, bsize, fsize, 0644);
++ }
++ if (!pmb->pmb_pool) {
++ log_err("pmemblk: unable to open pmemblk pool file %s (%s)\n",
++ path, strerror(errno));
++ goto error;
++ }
++
++ pmb->pmb_filename = path;
++ pmb->pmb_next = NULL;
++ pmb->pmb_refcnt = 0;
++ pmb->pmb_bsize = pmemblk_bsize(pmb->pmb_pool);
++ pmb->pmb_nblocks = pmemblk_nblock(pmb->pmb_pool);
++
++ fio_pmemblk_cache_insert(pmb);
++ } else {
++ free(path);
++ }
++
++ pmb->pmb_refcnt += 1;
++
++ pthread_mutex_unlock(&CacheLock);
++
++ return pmb;
++
++error:
++ if (pmb) {
++ if (pmb->pmb_pool)
++ pmemblk_close(pmb->pmb_pool);
++ pmb->pmb_pool = NULL;
++ pmb->pmb_filename = NULL;
++ free(pmb);
++ }
++ if (path)
++ free(path);
++
++ pthread_mutex_unlock(&CacheLock);
++ return NULL;
++}
++
++static void pmb_close(fio_pmemblk_file_t pmb, const bool keep)
++{
++ pthread_mutex_lock(&CacheLock);
++
++ pmb->pmb_refcnt--;
++
++ if (!keep && !pmb->pmb_refcnt) {
++ pmemblk_close(pmb->pmb_pool);
++ pmb->pmb_pool = NULL;
++ free(pmb->pmb_filename);
++ pmb->pmb_filename = NULL;
++ fio_pmemblk_cache_remove(pmb);
++ free(pmb);
++ }
++
++ pthread_mutex_unlock(&CacheLock);
++}
++
++static int pmb_get_flags(struct thread_data *td, uint64_t *pflags)
++{
++ static int thread_warned = 0;
++ static int odirect_warned = 0;
++
++ uint64_t flags = 0;
++
++ if (!td->o.use_thread) {
++ if (!thread_warned) {
++ thread_warned = 1;
++ log_err("pmemblk: must set thread=1 for pmemblk engine\n");
++ }
++ return 1;
++ }
++
++ if (!td->o.odirect && !odirect_warned) {
++ odirect_warned = 1;
++ log_info("pmemblk: direct == 0, but pmemblk is always direct\n");
++ }
++
++ if (td->o.allow_create)
++ flags |= PMB_CREATE;
++
++ (*pflags) = flags;
++ return 0;
++}
++
++static int fio_pmemblk_open_file(struct thread_data *td, struct fio_file *f)
++{
++ uint64_t flags = 0;
++ fio_pmemblk_file_t pmb;
++
++ if (pmb_get_flags(td, &flags))
++ return 1;
++
++ pmb = pmb_open(f->file_name, flags);
++ if (!pmb)
++ return 1;
++
++ FILE_SET_ENG_DATA(f, pmb);
++ return 0;
++}
++
++static int fio_pmemblk_close_file(struct thread_data fio_unused *td,
++ struct fio_file *f)
++{
++ fio_pmemblk_file_t pmb = FILE_ENG_DATA(f);
++
++ if (pmb)
++ pmb_close(pmb, false);
++
++ FILE_SET_ENG_DATA(f, NULL);
++ return 0;
++}
++
++static int fio_pmemblk_get_file_size(struct thread_data *td, struct fio_file *f)
++{
++ uint64_t flags = 0;
++ fio_pmemblk_file_t pmb = FILE_ENG_DATA(f);
++
++ if (fio_file_size_known(f))
++ return 0;
++
++ if (!pmb) {
++ if (pmb_get_flags(td, &flags))
++ return 1;
++ pmb = pmb_open(f->file_name, flags);
++ if (!pmb)
++ return 1;
++ }
++
++ f->real_file_size = pmb->pmb_bsize * pmb->pmb_nblocks;
++
++ fio_file_set_size_known(f);
++
++ if (!FILE_ENG_DATA(f))
++ pmb_close(pmb, true);
++
++ return 0;
++}
++
++static enum fio_q_status fio_pmemblk_queue(struct thread_data *td,
++ struct io_u *io_u)
++{
++ struct fio_file *f = io_u->file;
++ fio_pmemblk_file_t pmb = FILE_ENG_DATA(f);
++
++ unsigned long long off;
++ unsigned long len;
++ void *buf;
++
++ fio_ro_check(td, io_u);
++
++ switch (io_u->ddir) {
++ case DDIR_READ:
++ case DDIR_WRITE:
++ off = io_u->offset;
++ len = io_u->xfer_buflen;
++
++ io_u->error = EINVAL;
++ if (off % pmb->pmb_bsize)
++ break;
++ if (len % pmb->pmb_bsize)
++ break;
++ if ((off + len) / pmb->pmb_bsize > pmb->pmb_nblocks)
++ break;
++
++ io_u->error = 0;
++ buf = io_u->xfer_buf;
++ off /= pmb->pmb_bsize;
++ len /= pmb->pmb_bsize;
++ while (0 < len) {
++ if (io_u->ddir == DDIR_READ) {
++ if (0 != pmemblk_read(pmb->pmb_pool, buf, off)) {
++ io_u->error = errno;
++ break;
++ }
++ } else if (0 != pmemblk_write(pmb->pmb_pool, buf, off)) {
++ io_u->error = errno;
++ break;
++ }
++ buf += pmb->pmb_bsize;
++ off++;
++ len--;
++ }
++ off *= pmb->pmb_bsize;
++ len *= pmb->pmb_bsize;
++ io_u->resid = io_u->xfer_buflen - (off - io_u->offset);
++ break;
++ case DDIR_SYNC:
++ case DDIR_DATASYNC:
++ case DDIR_SYNC_FILE_RANGE:
++ /* we're always sync'd */
++ io_u->error = 0;
++ break;
++ default:
++ io_u->error = EINVAL;
++ break;
++ }
++
++ return FIO_Q_COMPLETED;
++}
++
++static int fio_pmemblk_unlink_file(struct thread_data *td, struct fio_file *f)
++{
++ char *path = NULL;
++ uint64_t bsize = 0;
++ uint64_t fsize = 0;
++
++ /*
++ * we need our own unlink in case the user has specified
++ * the block and file sizes in the path name. we parse
++ * the file_name to determine the file name we actually used.
++ */
++
++ pmb_parse_path(f->file_name, &path, &bsize, &fsize);
++ if (!path)
++ return ENOENT;
++
++ unlink(path);
++ free(path);
++ return 0;
++}
++
++FIO_STATIC struct ioengine_ops ioengine = {
++ .name = "pmemblk",
++ .version = FIO_IOOPS_VERSION,
++ .queue = fio_pmemblk_queue,
++ .open_file = fio_pmemblk_open_file,
++ .close_file = fio_pmemblk_close_file,
++ .get_file_size = fio_pmemblk_get_file_size,
++ .unlink_file = fio_pmemblk_unlink_file,
++ .flags = FIO_SYNCIO | FIO_DISKLESSIO | FIO_NOEXTEND | FIO_NODISKUTIL,
++};
++
++static void fio_init fio_pmemblk_register(void)
++{
++ register_ioengine(&ioengine);
++}
++
++static void fio_exit fio_pmemblk_unregister(void)
++{
++ unregister_ioengine(&ioengine);
++}
+diff --git a/examples/pmemblk.fio b/examples/pmemblk.fio
+new file mode 100644
+index 0000000000000000000000000000000000000000..59bb2a8a5acbf0e03d16a988f6ae0b9eb84575d2
+--- /dev/null
++++ b/examples/pmemblk.fio
+@@ -0,0 +1,71 @@
++[global]
++bs=1m
++ioengine=pmemblk
++norandommap
++time_based
++runtime=30
++group_reporting
++disable_lat=1
++disable_slat=1
++disable_clat=1
++clat_percentiles=0
++cpus_allowed_policy=split
++
++# For the pmemblk engine:
++#
++# IOs always complete immediately
++# IOs are always direct
++# Must use threads
++#
++iodepth=1
++direct=1
++thread
++numjobs=16
++#
++# Unlink can be used to remove the files when done, but if you are
++# using serial runs with stonewall, and you want the files to be created
++# only once and unlinked only at the very end, then put the unlink=1
++# in the last group. This is the method demonstrated here.
++#
++# Note that if you have a read-only group and if the files will be
++# newly created, then all of the data will read back as zero and the
++# read will be optimized, yielding performance that is different from
++# that of reading non-zero blocks (or unoptimized zero blocks).
++#
++unlink=0
++#
++# The pmemblk engine does IO to files in a DAX-mounted filesystem.
++# The filesystem should be created on an NVDIMM (e.g /dev/pmem0)
++# and then mounted with the '-o dax' option. Note that the engine
++# accesses the underlying NVDIMM directly, bypassing the kernel block
++# layer, so the usual filesystem/disk performance monitoring tools such
++# as iostat will not provide useful data.
++#
++# Here we specify a test file on each of two NVDIMMs. The first
++# number after the file name is the block size in bytes (4096 bytes
++# in this example). The second number is the size of the file to
++# create in MiB (1 GiB in this example); note that the actual usable
++# space available to fio will be less than this as libpmemblk requires
++# some space for metadata.
++#
++# Currently, the minimum block size is 512 bytes and the minimum file
++# size is about 17 MiB (these are libpmemblk requirements).
++#
++# While both files in this example have the same block size and file
++# size, this is not required.
++#
++filename=/pmem0/fio-test,4096,1024
++#filename=/pmem1/fio-test,4096,1024
++
++[pmemblk-write]
++rw=randwrite
++stonewall
++
++[pmemblk-read]
++rw=randread
++stonewall
++#
++# We're done, so unlink the file:
++#
++unlink=1
++
+diff --git a/fio.1 b/fio.1
+index 80bf3371a3556406cbcb29323bb21f55e769b9f9..3dc7e062a063d54bcd79120a7d6dc1ffd934b80c 100644
+--- a/fio.1
++++ b/fio.1
+@@ -1960,6 +1960,11 @@ e.g., on NAND, writing sequentially to erase blocks and discarding
+ before overwriting. The \fBtrimwrite\fR mode works well for this
+ constraint.
+ .TP
++.B pmemblk
++Read and write using filesystem DAX to a file on a filesystem
++mounted with DAX on a persistent memory device through the PMDK
++libpmemblk library.
++.TP
+ .B dev\-dax
+ Read and write using device DAX to a persistent memory device (e.g.,
+ /dev/dax0.0) through the PMDK libpmem library.
+diff --git a/options.c b/options.c
+index 8193fb29fe2b1cdfab8e745b9522aeb507f5361e..6c58577d8dbfd0a8dfd2b77e11c9be57e4aaaf10 100644
+--- a/options.c
++++ b/options.c
+@@ -2125,6 +2125,12 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
+ .help = "Hadoop Distributed Filesystem (HDFS) engine"
+ },
+ #endif
++#ifdef CONFIG_PMEMBLK
++ { .ival = "pmemblk",
++ .help = "PMDK libpmemblk based IO engine",
++ },
++
++#endif
+ #ifdef CONFIG_IME
+ { .ival = "ime_psync",
+ .help = "DDN's IME synchronous IO engine",
+diff --git a/os/windows/examples.wxs b/os/windows/examples.wxs
+index d70c77133f5a9f24908fffde9ce5ad20dbad2562..9308ba8be829c62b88cb06470a068cc2aef3f7dc 100755
+--- a/os/windows/examples.wxs
++++ b/os/windows/examples.wxs
+@@ -125,6 +125,9 @@
+ <Component>
+ <File Source="..\..\examples\numa.fio" />
+ </Component>
++ <Component>
++ <File Source="..\..\examples\pmemblk.fio" />
++ </Component>
+ <Component>
+ <File Source="..\..\examples\poisson-rate-submission.fio" />
+ </Component>
+@@ -209,6 +212,7 @@
+ <ComponentRef Id="netio_multicast.fio" />
+ <ComponentRef Id="null.fio" />
+ <ComponentRef Id="numa.fio" />
++ <ComponentRef Id="pmemblk.fio" />
+ <ComponentRef Id="poisson_rate_submission.fio" />
+ <ComponentRef Id="rados.fio"/>
+ <ComponentRef Id="rand_zones.fio" />
+--
+2.41.0
+