Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.19-rc3 168 lines 4.0 kB view raw
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}