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 v2 2/4] vfio: selftests: Introduce vfio_dma_mapping_perf_test
Date: Tue, 4 Aug 2026 16:57:46 +0000 [thread overview]
Message-ID: <20260804165748.1060476-3-aaronlewis@google.com> (raw)
In-Reply-To: <20260804165748.1060476-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 in this series 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.
Signed-off-by: Aaron Lewis <aaronlewis@google.com>
---
tools/testing/selftests/vfio/Makefile | 1 +
.../selftests/vfio/lib/include/libvfio.h | 28 ++++++
.../vfio/vfio_dma_mapping_perf_test.c | 90 +++++++++++++++++++
3 files changed, 119 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..cf322b499cfb 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio.h
@@ -9,6 +9,34 @@
#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_start(struct timespec *start)
+{
+ clock_gettime(CLOCK_MONOTONIC, start);
+}
+
+static inline uint64_t timer_elapsed_ns(struct timespec start)
+{
+ struct timespec end;
+
+ clock_gettime(CLOCK_MONOTONIC, &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; \
+ \
+ timer_start(&__start); \
+ _expression; \
+ printf(_name " = %.2lfms\n", \
+ (double)timer_elapsed_ns(__start) / NSEC_PER_MSEC); \
+} 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..26c04cabef61
--- /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;
+
+ printf("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.55.0.654.g21b8a5bc05-goog
next prev parent reply other threads:[~2026-08-04 16:57 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-04 16:57 [PATCH v2 0/4] Introduce vfio_dma_mapping_perf_test Aaron Lewis
2026-08-04 16:57 ` [PATCH v2 1/4] vfio: selftests: Assert the region was unmapped in iommu_unmap() Aaron Lewis
2026-08-04 16:57 ` Aaron Lewis [this message]
2026-08-04 17:15 ` [PATCH v2 2/4] vfio: selftests: Introduce vfio_dma_mapping_perf_test sashiko-bot
2026-08-04 16:57 ` [PATCH v2 3/4] vfio: selftests: Add memfd test to vfio_dma_mapping_perf_test Aaron Lewis
2026-08-04 16:57 ` [PATCH v2 4/4] vfio: selftests: Allow a size for vfio_dma_mapping_perf_test Aaron Lewis
2026-08-04 17:11 ` 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=20260804165748.1060476-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.