From nobody Mon Feb 9 00:55:01 2026 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AC9E1355058 for ; Wed, 12 Nov 2025 19:23:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762975394; cv=none; b=NIjicbbyWOwOmWxI1BeU5SoBGYzqZ2AzuLPh2ntzqNT6tdUTqvNKItQigEyi/wzw3K8+isT/RQy0DpwGXEfowt8TrohCC9pQrMBhhNEJSMA3GR39CGWja4S5mLQJcuZEXqoGvc+4m4iJ6/pkS4mQFTNcMdG9Nu761XiATFnnrY8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762975394; c=relaxed/simple; bh=91BJdnU91RfIE/hJq59U7COO8d5lVht0pXvEtkmCCmc=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=HlJBbzshE226YOjQvbTkjfJGv5CHYrjXxMUcaNXJ25J46UW9+pzCHQg2Qc2SBYZqteE3ETrpV5TM1G2+BwK6Kp5crcIGdYdfUVYu5Jw5XaxUYvr9UdM5nrXoOkSml9FO6APZFR6FtrUzca4ZDe8o3GfUiDWLTAE95iMglP9Gg8Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=j6NksHB8; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="j6NksHB8" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-7b8a12f0cb4so461976b3a.3 for ; Wed, 12 Nov 2025 11:23:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1762975392; x=1763580192; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=o2e+js0Qy7w6O0gL6/BZx4eVZarhnCcJq/+q0M3UtfI=; b=j6NksHB8XILDLfnhzIeKF/vc+U3FFRqipwTXzqQYFgNrgijzd0NVRMQraOJ1miZm3R mFt7M38YZS5OEOLKWiuXKSoaYi0u0aHel9bWSVjybgvnP8jnZzbXuhCZJdBytXjfnxlB c9Q8LSgL4psSu2K/tiera/35A4uTZRx02A3RGGwplfUhSYGFYgn4JN9j8ao6/yNLZ8iu PuT1E0ehsOtO2G5Z2WFOMS/IVKgKmy4W72JHe6b9SiYJXArqcrnQ6Nz4BPXVRuWmvhFp 5qyEWfe482vI28Yt1HFE8L11ZqLpIzumQ+Z6nfkRkPDBoEyht14z3SDTZQO3jutgO0NO ycOA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1762975392; x=1763580192; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=o2e+js0Qy7w6O0gL6/BZx4eVZarhnCcJq/+q0M3UtfI=; b=eV01mEh0sQ275E2MCN40ArZt1Ey2WmfOyo+z6exxp+SUKb3Yg+2hvDZ99mlr/jhx1E TTyrZL+hl1mbJYSblZwD0mkxQx1PmqelQFTjqPx8awPvJYCOOtc/uKhbxchs0qwQymZw z57NeFsyVZ4Bw/4fizZb5aamgDAfZJlro2/OiKouJzWcDRam0hL8BcG1V2MMcvH3GKsz bl2+FdMzbMV2RO5vaGzUdX/kqV41lwjoPzDFL7MqvuF3tmLDXlfLuF/KylL8HWHibH+p m828IUVpGy9batFq+IRTI5fKpXA0ngijvkZA1IYVTMJOYm0FYOTtwK7U88NoK7fP/KHZ bp9A== X-Forwarded-Encrypted: i=1; AJvYcCXraNzGwcqjXd35SZ/GJUmlVqKlh+zc2pV0pfVZOy81LlagYirELIJ4YuLHWn1+xRmZIg0pHnPdERwQVv4=@vger.kernel.org X-Gm-Message-State: AOJu0YxiimKjHMMBqAxc8FOHH4B/58+cOOwxc94BYIt7FH8S4TWqnvFm nvSjAGyrB9ZYv6VUFaTEWenHOMUkj70zgabm/8v5ECOTt4Dq2A5gN1sb3bgx8y3O7h0DLBIBBml 1a1ouAVq5GPCunA== X-Google-Smtp-Source: AGHT+IF8kvsYlmSEbjUQ/k2eUYglNUnLyK7Y7SQjAhLBmOM14SOm1bhd8hAnVvjd1DlYsknFTJKiG6sVMJVM+w== X-Received: from pfrj16.prod.google.com ([2002:aa7:8dd0:0:b0:7af:2faf:c3af]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:aa7:88c8:0:b0:7ab:e007:deec with SMTP id d2e1a72fcca58-7b7a53c10cfmr5819330b3a.32.1762975392025; Wed, 12 Nov 2025 11:23:12 -0800 (PST) Date: Wed, 12 Nov 2025 19:22:32 +0000 In-Reply-To: <20251112192232.442761-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20251112192232.442761-1-dmatlack@google.com> X-Mailer: git-send-email 2.52.0.rc1.455.g30608eb744-goog Message-ID: <20251112192232.442761-19-dmatlack@google.com> Subject: [PATCH v2 18/18] vfio: selftests: Add vfio_pci_device_init_perf_test From: David Matlack To: Alex Williamson Cc: Alex Mastro , Alex Williamson , David Matlack , Jason Gunthorpe , Josh Hilke , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Raghavendra Rao Ananta , Vipin Sharma , Aaron Lewis Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a new VFIO selftest for measuring the time it takes to run vfio_pci_device_init() in parallel for one or more devices. This test serves as manual regression test for the performance improvement of commit e908f58b6beb ("vfio/pci: Separate SR-IOV VF dev_set"). For example, when running this test with 64 VFs under the same PF: Before: $ ./vfio_pci_device_init_perf_test -r vfio_pci_device_init_perf_test.iomm= ufd.init 0000:1a:00.0 0000:1a:00.1 ... ... Wall time: 6.653234463s Min init time (per device): 0.101215344s Max init time (per device): 6.652755941s Avg init time (per device): 3.377609608s After: $ ./vfio_pci_device_init_perf_test -r vfio_pci_device_init_perf_test.iomm= ufd.init 0000:1a:00.0 0000:1a:00.1 ... ... Wall time: 0.122978332s Min init time (per device): 0.108121915s Max init time (per device): 0.122762761s Avg init time (per device): 0.113816748s This test does not make any assertions about performance, since any such assertion is likely to be flaky due to system differences and random noise. However this test can be fed into automation to detect regressions, and can be used by developers in the future to measure performance optimizations. Suggested-by: Aaron Lewis Signed-off-by: David Matlack Reviewed-by: Alex Mastro --- tools/testing/selftests/vfio/Makefile | 3 + .../vfio/vfio_pci_device_init_perf_test.c | 167 ++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 tools/testing/selftests/vfio/vfio_pci_device_init_perf_= test.c diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftest= s/vfio/Makefile index e9e5c6dc63b6..8bb0b1e2d3a3 100644 --- a/tools/testing/selftests/vfio/Makefile +++ b/tools/testing/selftests/vfio/Makefile @@ -2,6 +2,7 @@ CFLAGS =3D $(KHDR_INCLUDES) TEST_GEN_PROGS +=3D vfio_dma_mapping_test TEST_GEN_PROGS +=3D vfio_iommufd_setup_test TEST_GEN_PROGS +=3D vfio_pci_device_test +TEST_GEN_PROGS +=3D vfio_pci_device_init_perf_test TEST_GEN_PROGS +=3D vfio_pci_driver_test =20 TEST_PROGS_EXTENDED :=3D scripts/cleanup.sh @@ -15,6 +16,8 @@ CFLAGS +=3D -I$(top_srcdir)/tools/include CFLAGS +=3D -MD CFLAGS +=3D $(EXTRA_CFLAGS) =20 +LDFLAGS +=3D -pthread + $(TEST_GEN_PROGS): %: %.o $(LIBVFIO_O) $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< $(LIBVFIO_O) $(LDLIBS) -o $@ =20 diff --git a/tools/testing/selftests/vfio/vfio_pci_device_init_perf_test.c = b/tools/testing/selftests/vfio/vfio_pci_device_init_perf_test.c new file mode 100644 index 000000000000..54e327dadab4 --- /dev/null +++ b/tools/testing/selftests/vfio/vfio_pci_device_init_perf_test.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include + +#include +#include + +#include + +#include "../kselftest_harness.h" + +static char **device_bdfs; +static int nr_devices; + +struct thread_args { + struct iommu *iommu; + int device_index; + struct timespec start; + struct timespec end; + pthread_barrier_t *barrier; +}; + +FIXTURE(vfio_pci_device_init_perf_test) { + pthread_t *threads; + pthread_barrier_t barrier; + struct thread_args *thread_args; + struct iommu *iommu; +}; + +FIXTURE_VARIANT(vfio_pci_device_init_perf_test) { + const char *iommu_mode; +}; + +#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode) \ +FIXTURE_VARIANT_ADD(vfio_pci_device_init_perf_test, _iommu_mode) { \ + .iommu_mode =3D #_iommu_mode, \ +} + +FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(); + +FIXTURE_SETUP(vfio_pci_device_init_perf_test) +{ + int i; + + self->iommu =3D iommu_init(variant->iommu_mode); + self->threads =3D calloc(nr_devices, sizeof(self->threads[0])); + self->thread_args =3D calloc(nr_devices, sizeof(self->thread_args[0])); + + pthread_barrier_init(&self->barrier, NULL, nr_devices); + + for (i =3D 0; i < nr_devices; i++) { + self->thread_args[i].iommu =3D self->iommu; + self->thread_args[i].barrier =3D &self->barrier; + self->thread_args[i].device_index =3D i; + } +} + +FIXTURE_TEARDOWN(vfio_pci_device_init_perf_test) +{ + iommu_cleanup(self->iommu); + free(self->threads); + free(self->thread_args); +} + +static s64 to_ns(struct timespec ts) +{ + return (s64)ts.tv_nsec + 1000000000LL * (s64)ts.tv_sec; +} + +static struct timespec to_timespec(s64 ns) +{ + struct timespec ts =3D { + .tv_nsec =3D ns % 1000000000LL, + .tv_sec =3D ns / 1000000000LL, + }; + + return ts; +} + +static struct timespec timespec_sub(struct timespec a, struct timespec b) +{ + return to_timespec(to_ns(a) - to_ns(b)); +} + +static struct timespec timespec_min(struct timespec a, struct timespec b) +{ + return to_ns(a) < to_ns(b) ? a : b; +} + +static struct timespec timespec_max(struct timespec a, struct timespec b) +{ + return to_ns(a) > to_ns(b) ? a : b; +} + +static void *thread_main(void *__args) +{ + struct thread_args *args =3D __args; + struct vfio_pci_device *device; + + pthread_barrier_wait(args->barrier); + + clock_gettime(CLOCK_MONOTONIC, &args->start); + device =3D vfio_pci_device_init(device_bdfs[args->device_index], args->io= mmu); + clock_gettime(CLOCK_MONOTONIC, &args->end); + + pthread_barrier_wait(args->barrier); + + vfio_pci_device_cleanup(device); + return NULL; +} + +TEST_F(vfio_pci_device_init_perf_test, init) +{ + struct timespec start =3D to_timespec(INT64_MAX), end =3D {}; + struct timespec min =3D to_timespec(INT64_MAX); + struct timespec max =3D {}; + struct timespec avg =3D {}; + struct timespec wall_time; + s64 thread_ns =3D 0; + int i; + + for (i =3D 0; i < nr_devices; i++) { + pthread_create(&self->threads[i], NULL, thread_main, + &self->thread_args[i]); + } + + for (i =3D 0; i < nr_devices; i++) { + struct thread_args *args =3D &self->thread_args[i]; + struct timespec init_time; + + pthread_join(self->threads[i], NULL); + + start =3D timespec_min(start, args->start); + end =3D timespec_max(end, args->end); + + init_time =3D timespec_sub(args->end, args->start); + min =3D timespec_min(min, init_time); + max =3D timespec_max(max, init_time); + thread_ns +=3D to_ns(init_time); + } + + avg =3D to_timespec(thread_ns / nr_devices); + wall_time =3D timespec_sub(end, start); + + printf("Wall time: %lu.%09lus\n", + wall_time.tv_sec, wall_time.tv_nsec); + printf("Min init time (per device): %lu.%09lus\n", + min.tv_sec, min.tv_nsec); + printf("Max init time (per device): %lu.%09lus\n", + max.tv_sec, max.tv_nsec); + printf("Avg init time (per device): %lu.%09lus\n", + avg.tv_sec, avg.tv_nsec); +} + +int main(int argc, char *argv[]) +{ + int i; + + device_bdfs =3D vfio_selftests_get_bdfs(&argc, argv, &nr_devices); + + printf("Testing parallel initialization of %d devices:\n", nr_devices); + for (i =3D 0; i < nr_devices; i++) + printf(" %s\n", device_bdfs[i]); + + return test_harness_run(argc, argv); +} --=20 2.52.0.rc1.455.g30608eb744-goog