From: Aaron Lewis <aaronlewis@google.com>
To: kvm@vger.kernel.org
Cc: alex@shazbot.org, dmatlack@google.com, jgg@nvidia.com,
Aaron Lewis <aaronlewis@google.com>
Subject: [PATCH v4 2/5] vfio: selftests: Introduce vfio_dma_mapping_perf_test
Date: Sat, 14 Nov 2026 13:21:57 +0000 [thread overview]
Message-ID: <20261114132200.113697-3-aaronlewis@google.com> (raw)
In-Reply-To: <20261114132200.113697-1-aaronlewis@google.com>
Introduce vfio_dma_mapping_perf_test to aid in latency testing. Rather
than a traditional pass/fail test, which tends to be flaky when
enforcing latency bounds, this test directly reports the latency of
various stages in the mapping and unmapping process.
Start with a basic test that performs a simple DMA map/unmap and tracks
the duration of each operation. The test reports the following metrics:
1. Time taken by mmap().
2. Time taken to map a DMA region.
3. Time taken to unmap a DMA region.
4. Time taken by munmap().
Subsequent commits will introduce more features to allow for a wider
variety of testing.
To ensure consistent DMA mapping times, the test uses MAP_POPULATE when
calling mmap(). This forces page faults to be handled upfront, isolating
the DMA mapping times from them.
Reviewed-by: David Matlack <dmatlack@google.com>
Signed-off-by: Aaron Lewis <aaronlewis@google.com>
---
tools/testing/selftests/vfio/Makefile | 1 +
.../selftests/vfio/lib/include/libvfio.h | 31 +++++++
.../vfio/vfio_dma_mapping_perf_test.c | 90 +++++++++++++++++++
3 files changed, 122 insertions(+)
create mode 100644 tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 2c32c48db509..ed5856af5f9a 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -8,6 +8,7 @@ else
CFLAGS = $(KHDR_INCLUDES)
TEST_GEN_PROGS += vfio_dma_mapping_test
TEST_GEN_PROGS += vfio_dma_mapping_mmio_test
+TEST_GEN_PROGS += vfio_dma_mapping_perf_test
TEST_GEN_PROGS += vfio_iommufd_setup_test
TEST_GEN_PROGS += vfio_pci_device_test
TEST_GEN_PROGS += vfio_pci_device_init_perf_test
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio.h b/tools/testing/selftests/vfio/lib/include/libvfio.h
index 07862b470777..05802a2c3aba 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio.h
@@ -9,6 +9,37 @@
#include <libvfio/vfio_pci_device.h>
#include <libvfio/vfio_pci_driver.h>
+#include <stdint.h>
+#include <time.h>
+#include <linux/time64.h>
+
+static inline void timer_get(struct timespec *ts)
+{
+ clock_gettime(CLOCK_MONOTONIC, ts);
+}
+
+static inline uint64_t timer_elapsed_ns(struct timespec start)
+{
+ struct timespec end;
+
+ timer_get(&end);
+
+ return (uint64_t)(end.tv_sec - start.tv_sec) * NSEC_PER_SEC +
+ (uint64_t)(end.tv_nsec - start.tv_nsec);
+}
+
+#define TIME(_name, _expression) do { \
+ struct timespec __start; \
+ int __errno; \
+ \
+ timer_get(&__start); \
+ _expression; \
+ __errno = errno; \
+ ksft_print_msg(_name " = %.2lfms\n", \
+ (double)timer_elapsed_ns(__start) / NSEC_PER_MSEC); \
+ errno = __errno; \
+} while (0)
+
/*
* Return the BDF string of the device that the test should use.
*
diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
new file mode 100644
index 000000000000..4d41fecf2372
--- /dev/null
+++ b/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <limits.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/iommufd.h>
+#include <linux/limits.h>
+#include <linux/memfd.h>
+#include <linux/mman.h>
+#include <linux/sizes.h>
+#include <linux/time64.h>
+#include <linux/vfio.h>
+
+#include <libvfio.h>
+
+#include "kselftest_harness.h"
+
+static const char *device_bdf;
+
+FIXTURE(vfio_dma_mapping_perf_test) {
+ struct iommu *iommu;
+ struct vfio_pci_device *device;
+ struct iova_allocator *iova_allocator;
+};
+
+FIXTURE_VARIANT(vfio_dma_mapping_perf_test) {
+ const char *iommu_mode;
+ int mmap_flags;
+};
+
+#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode, _name, _mmap_flags) \
+FIXTURE_VARIANT_ADD(vfio_dma_mapping_perf_test, _iommu_mode ## _ ## _name) { \
+ .iommu_mode = #_iommu_mode, \
+ .mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE | (_mmap_flags), \
+}
+
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous, 0);
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_2mb, MAP_HUGETLB | MAP_HUGE_2MB);
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_1gb, MAP_HUGETLB | MAP_HUGE_1GB);
+
+#undef FIXTURE_VARIANT_ADD_IOMMU_MODE
+
+FIXTURE_SETUP(vfio_dma_mapping_perf_test)
+{
+ self->iommu = iommu_init(variant->iommu_mode);
+ self->device = vfio_pci_device_init(device_bdf, self->iommu);
+ self->iova_allocator = iova_allocator_init(self->iommu);
+}
+
+FIXTURE_TEARDOWN(vfio_dma_mapping_perf_test)
+{
+ iova_allocator_cleanup(self->iova_allocator);
+ vfio_pci_device_cleanup(self->device);
+ iommu_cleanup(self->iommu);
+}
+
+TEST_F(vfio_dma_mapping_perf_test, dma_map_unmap)
+{
+ const u64 size = SZ_1G;
+ const int flags = variant->mmap_flags;
+ struct dma_region region;
+
+ ksft_print_msg("mmap size = %lluG\n", (unsigned long long)(size / SZ_1G));
+
+ TIME("mmap",
+ region.vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0));
+
+ /* Skip the test if there aren't enough HugeTLB pages available. */
+ if (flags & MAP_HUGETLB && region.vaddr == MAP_FAILED)
+ SKIP(return, "mmap() failed: %s (%d)\n", strerror(errno), errno);
+ else
+ ASSERT_NE(region.vaddr, MAP_FAILED);
+
+ region.iova = iova_allocator_alloc(self->iova_allocator, size);
+ region.size = size;
+
+ TIME("IOMMU map", iommu_map(self->iommu, ®ion));
+ ASSERT_EQ(region.iova, to_iova(self->device, region.vaddr));
+
+ TIME("IOMMU unmap", iommu_unmap(self->iommu, ®ion));
+ TIME("munmap", ASSERT_EQ(0, munmap(region.vaddr, size)));
+}
+
+int main(int argc, char *argv[])
+{
+ device_bdf = vfio_selftests_get_bdf(&argc, argv);
+ return test_harness_run(argc, argv);
+}
--
2.56.0.611.g1030f0b940-goog
next prev parent reply other threads:[~2026-11-14 13:22 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-14 13:21 [PATCH v4 0/5] Introduce vfio_dma_mapping_perf_test Aaron Lewis
2026-11-14 13:21 ` [PATCH v4 1/5] vfio: selftests: Assert the region was unmapped in iommu_unmap() Aaron Lewis
2026-11-14 13:21 ` Aaron Lewis [this message]
2026-11-14 13:21 ` [PATCH v4 3/5] vfio: selftests: Add memfd test to vfio_dma_mapping_perf_test Aaron Lewis
2026-11-14 13:21 ` [PATCH v4 4/5] selftests: harness: Support custom command-line options Aaron Lewis
2026-11-14 13:22 ` [PATCH v4 5/5] vfio: selftests: Allow a size for vfio_dma_mapping_perf_test Aaron Lewis
2026-11-14 13:29 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261114132200.113697-3-aaronlewis@google.com \
--to=aaronlewis@google.com \
--cc=alex@shazbot.org \
--cc=dmatlack@google.com \
--cc=jgg@nvidia.com \
--cc=kvm@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox