File Index
Files and directories
Sign in
FILE

vfio_pci_device_init_perf_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/vfio/vfio_pci_device_init_perf_test.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2#include <pthread.h>
  3#include <sys/ioctl.h>
  4#include <sys/mman.h>
  5
  6#include <linux/sizes.h>
  7#include <linux/time64.h>
  8#include <linux/vfio.h>
  9
 10#include <libvfio.h>
 11
 12#include "../kselftest_harness.h"
 13
 14static char **device_bdfs;
 15static int nr_devices;
 16
 17struct thread_args {
 18	struct iommu *iommu;
 19	int device_index;
 20	struct timespec start;
 21	struct timespec end;
 22	pthread_barrier_t *barrier;
 23};
 24
 25FIXTURE(vfio_pci_device_init_perf_test) {
 26	pthread_t *threads;
 27	pthread_barrier_t barrier;
 28	struct thread_args *thread_args;
 29	struct iommu *iommu;
 30};
 31
 32FIXTURE_VARIANT(vfio_pci_device_init_perf_test) {
 33	const char *iommu_mode;
 34};
 35
 36#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode)			\
 37FIXTURE_VARIANT_ADD(vfio_pci_device_init_perf_test, _iommu_mode) {	\
 38	.iommu_mode = #_iommu_mode,					\
 39}
 40
 41FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES();
 42
 43FIXTURE_SETUP(vfio_pci_device_init_perf_test)
 44{
 45	int i;
 46
 47	self->iommu = iommu_init(variant->iommu_mode);
 48	self->threads = calloc(nr_devices, sizeof(self->threads[0]));
 49	self->thread_args = calloc(nr_devices, sizeof(self->thread_args[0]));
 50
 51	pthread_barrier_init(&self->barrier, NULL, nr_devices);
 52
 53	for (i = 0; i < nr_devices; i++) {
 54		self->thread_args[i].iommu = self->iommu;
 55		self->thread_args[i].barrier = &self->barrier;
 56		self->thread_args[i].device_index = i;
 57	}
 58}
 59
 60FIXTURE_TEARDOWN(vfio_pci_device_init_perf_test)
 61{
 62	iommu_cleanup(self->iommu);
 63	free(self->threads);
 64	free(self->thread_args);
 65}
 66
 67static s64 to_ns(struct timespec ts)
 68{
 69	return (s64)ts.tv_nsec + NSEC_PER_SEC * (s64)ts.tv_sec;
 70}
 71
 72static struct timespec to_timespec(s64 ns)
 73{
 74	struct timespec ts = {
 75		.tv_nsec = ns % NSEC_PER_SEC,
 76		.tv_sec = ns / NSEC_PER_SEC,
 77	};
 78
 79	return ts;
 80}
 81
 82static struct timespec timespec_sub(struct timespec a, struct timespec b)
 83{
 84	return to_timespec(to_ns(a) - to_ns(b));
 85}
 86
 87static struct timespec timespec_min(struct timespec a, struct timespec b)
 88{
 89	return to_ns(a) < to_ns(b) ? a : b;
 90}
 91
 92static struct timespec timespec_max(struct timespec a, struct timespec b)
 93{
 94	return to_ns(a) > to_ns(b) ? a : b;
 95}
 96
 97static void *thread_main(void *__args)
 98{
 99	struct thread_args *args = __args;
100	struct vfio_pci_device *device;
101
102	pthread_barrier_wait(args->barrier);
103
104	clock_gettime(CLOCK_MONOTONIC, &args->start);
105	device = vfio_pci_device_init(device_bdfs[args->device_index], args->iommu);
106	clock_gettime(CLOCK_MONOTONIC, &args->end);
107
108	pthread_barrier_wait(args->barrier);
109
110	vfio_pci_device_cleanup(device);
111	return NULL;
112}
113
114TEST_F(vfio_pci_device_init_perf_test, init)
115{
116	struct timespec start = to_timespec(INT64_MAX), end = {};
117	struct timespec min = to_timespec(INT64_MAX);
118	struct timespec max = {};
119	struct timespec avg = {};
120	struct timespec wall_time;
121	s64 thread_ns = 0;
122	int i;
123
124	for (i = 0; i < nr_devices; i++) {
125		pthread_create(&self->threads[i], NULL, thread_main,
126			       &self->thread_args[i]);
127	}
128
129	for (i = 0; i < nr_devices; i++) {
130		struct thread_args *args = &self->thread_args[i];
131		struct timespec init_time;
132
133		pthread_join(self->threads[i], NULL);
134
135		start = timespec_min(start, args->start);
136		end = timespec_max(end, args->end);
137
138		init_time = timespec_sub(args->end, args->start);
139		min = timespec_min(min, init_time);
140		max = timespec_max(max, init_time);
141		thread_ns += to_ns(init_time);
142	}
143
144	avg = to_timespec(thread_ns / nr_devices);
145	wall_time = timespec_sub(end, start);
146
147	printf("Wall time: %lu.%09lus\n",
148	       wall_time.tv_sec, wall_time.tv_nsec);
149	printf("Min init time (per device): %lu.%09lus\n",
150	       min.tv_sec, min.tv_nsec);
151	printf("Max init time (per device): %lu.%09lus\n",
152	       max.tv_sec, max.tv_nsec);
153	printf("Avg init time (per device): %lu.%09lus\n",
154	       avg.tv_sec, avg.tv_nsec);
155}
156
157int main(int argc, char *argv[])
158{
159	int i;
160
161	device_bdfs = vfio_selftests_get_bdfs(&argc, argv, &nr_devices);
162
163	printf("Testing parallel initialization of %d devices:\n", nr_devices);
164	for (i = 0; i < nr_devices; i++)
165		printf("    %s\n", device_bdfs[i]);
166
167	return test_harness_run(argc, argv);
168}
~/ Read-only file preview.