2121#include <linux/bitops.h>
2222#include <linux/userfaultfd.h>
2323
24- #include "test_util.h"
25- #include "kvm_util.h"
24+ #include "perf_test_util.h"
2625#include "processor.h"
26+ #include "test_util.h"
2727
2828#ifdef __NR_userfaultfd
2929
30- /* The memory slot index demand page */
31- #define TEST_MEM_SLOT_INDEX 1
32-
33- /* Default guest test virtual memory offset */
34- #define DEFAULT_GUEST_TEST_MEM 0xc0000000
35-
3630#define DEFAULT_GUEST_TEST_MEM_SIZE (1 << 30) /* 1G */
3731
3832#ifdef PRINT_PER_PAGE_UPDATES
4741#define PER_VCPU_DEBUG (...) _no_printf(__VA_ARGS__)
4842#endif
4943
50- #define MAX_VCPUS 512
51-
52- /*
53- * Guest/Host shared variables. Ensure addr_gva2hva() and/or
54- * sync_global_to/from_guest() are used when accessing from
55- * the host. READ/WRITE_ONCE() should also be used with anything
56- * that may change.
57- */
58- static uint64_t host_page_size ;
59- static uint64_t guest_page_size ;
60-
6144static char * guest_data_prototype ;
6245
63- /*
64- * Guest physical memory offset of the testing memory slot.
65- * This will be set to the topmost valid physical address minus
66- * the test memory size.
67- */
68- static uint64_t guest_test_phys_mem ;
69-
70- /*
71- * Guest virtual memory offset of the testing memory slot.
72- * Must not conflict with identity mapped test code.
73- */
74- static uint64_t guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM ;
75-
76- struct vcpu_args {
77- uint64_t gva ;
78- uint64_t pages ;
79-
80- /* Only used by the host userspace part of the vCPU thread */
81- int vcpu_id ;
82- struct kvm_vm * vm ;
83- };
84-
85- static struct vcpu_args vcpu_args [MAX_VCPUS ];
86-
87- /*
88- * Continuously write to the first 8 bytes of each page in the demand paging
89- * memory region.
90- */
91- static void guest_code (uint32_t vcpu_id )
92- {
93- uint64_t gva ;
94- uint64_t pages ;
95- int i ;
96-
97- /* Make sure vCPU args data structure is not corrupt. */
98- GUEST_ASSERT (vcpu_args [vcpu_id ].vcpu_id == vcpu_id );
99-
100- gva = vcpu_args [vcpu_id ].gva ;
101- pages = vcpu_args [vcpu_id ].pages ;
102-
103- for (i = 0 ; i < pages ; i ++ ) {
104- uint64_t addr = gva + (i * guest_page_size );
105-
106- addr &= ~(host_page_size - 1 );
107- * (uint64_t * )addr = 0x0123456789ABCDEF ;
108- }
109-
110- GUEST_SYNC (1 );
111- }
112-
11346static void * vcpu_worker (void * data )
11447{
11548 int ret ;
116- struct vcpu_args * args = (struct vcpu_args * )data ;
117- struct kvm_vm * vm = args -> vm ;
118- int vcpu_id = args -> vcpu_id ;
49+ struct vcpu_args * vcpu_args = (struct vcpu_args * )data ;
50+ int vcpu_id = vcpu_args -> vcpu_id ;
51+ struct kvm_vm * vm = perf_test_args . vm ;
11952 struct kvm_run * run ;
12053 struct timespec start , end , ts_diff ;
12154
@@ -141,39 +74,6 @@ static void *vcpu_worker(void *data)
14174 return NULL ;
14275}
14376
144- #define PAGE_SHIFT_4K 12
145- #define PTES_PER_4K_PT 512
146-
147- static struct kvm_vm * create_vm (enum vm_guest_mode mode , int vcpus ,
148- uint64_t vcpu_memory_bytes )
149- {
150- struct kvm_vm * vm ;
151- uint64_t pages = DEFAULT_GUEST_PHY_PAGES ;
152-
153- /* Account for a few pages per-vCPU for stacks */
154- pages += DEFAULT_STACK_PGS * vcpus ;
155-
156- /*
157- * Reserve twice the ammount of memory needed to map the test region and
158- * the page table / stacks region, at 4k, for page tables. Do the
159- * calculation with 4K page size: the smallest of all archs. (e.g., 64K
160- * page size guest will need even less memory for page tables).
161- */
162- pages += (2 * pages ) / PTES_PER_4K_PT ;
163- pages += ((2 * vcpus * vcpu_memory_bytes ) >> PAGE_SHIFT_4K ) /
164- PTES_PER_4K_PT ;
165- pages = vm_adjust_num_guest_pages (mode , pages );
166-
167- pr_info ("Testing guest mode: %s\n" , vm_guest_mode_string (mode ));
168-
169- vm = _vm_create (mode , pages , O_RDWR );
170- kvm_vm_elf_load (vm , program_invocation_name , 0 , 0 );
171- #ifdef __x86_64__
172- vm_create_irqchip (vm );
173- #endif
174- return vm ;
175- }
176-
17777static int handle_uffd_page_request (int uffd , uint64_t addr )
17878{
17979 pid_t tid ;
@@ -186,7 +86,7 @@ static int handle_uffd_page_request(int uffd, uint64_t addr)
18686
18787 copy .src = (uint64_t )guest_data_prototype ;
18888 copy .dst = addr ;
189- copy .len = host_page_size ;
89+ copy .len = perf_test_args . host_page_size ;
19090 copy .mode = 0 ;
19191
19292 clock_gettime (CLOCK_MONOTONIC , & start );
@@ -203,7 +103,7 @@ static int handle_uffd_page_request(int uffd, uint64_t addr)
203103 PER_PAGE_DEBUG ("UFFDIO_COPY %d \t%ld ns\n" , tid ,
204104 timespec_to_ns (timespec_sub (end , start )));
205105 PER_PAGE_DEBUG ("Paged in %ld bytes at 0x%lx from thread %d\n" ,
206- host_page_size , addr , tid );
106+ perf_test_args . host_page_size , addr , tid );
207107
208108 return 0 ;
209109}
@@ -360,64 +260,21 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd,
360260 struct timespec start , end , ts_diff ;
361261 int * pipefds = NULL ;
362262 struct kvm_vm * vm ;
363- uint64_t guest_num_pages ;
364263 int vcpu_id ;
365264 int r ;
366265
367266 vm = create_vm (mode , vcpus , vcpu_memory_bytes );
368267
369- guest_page_size = vm_get_page_size (vm );
370-
371- TEST_ASSERT (vcpu_memory_bytes % guest_page_size == 0 ,
372- "Guest memory size is not guest page size aligned." );
373-
374- guest_num_pages = (vcpus * vcpu_memory_bytes ) / guest_page_size ;
375- guest_num_pages = vm_adjust_num_guest_pages (mode , guest_num_pages );
376-
377- /*
378- * If there should be more memory in the guest test region than there
379- * can be pages in the guest, it will definitely cause problems.
380- */
381- TEST_ASSERT (guest_num_pages < vm_get_max_gfn (vm ),
382- "Requested more guest memory than address space allows.\n"
383- " guest pages: %lx max gfn: %x vcpus: %d wss: %lx]\n" ,
384- guest_num_pages , vm_get_max_gfn (vm ), vcpus ,
385- vcpu_memory_bytes );
386-
387- host_page_size = getpagesize ();
388- TEST_ASSERT (vcpu_memory_bytes % host_page_size == 0 ,
389- "Guest memory size is not host page size aligned." );
390-
391- guest_test_phys_mem = (vm_get_max_gfn (vm ) - guest_num_pages ) *
392- guest_page_size ;
393- guest_test_phys_mem &= ~(host_page_size - 1 );
394-
395- #ifdef __s390x__
396- /* Align to 1M (segment size) */
397- guest_test_phys_mem &= ~((1 << 20 ) - 1 );
398- #endif
399-
400- pr_info ("guest physical test memory offset: 0x%lx\n" , guest_test_phys_mem );
401-
402- /* Add an extra memory slot for testing demand paging */
403- vm_userspace_mem_region_add (vm , VM_MEM_SRC_ANONYMOUS ,
404- guest_test_phys_mem ,
405- TEST_MEM_SLOT_INDEX ,
406- guest_num_pages , 0 );
407-
408- /* Do mapping for the demand paging memory slot */
409- virt_map (vm , guest_test_virt_mem , guest_test_phys_mem , guest_num_pages , 0 );
410-
411- ucall_init (vm , NULL );
412-
413- guest_data_prototype = malloc (host_page_size );
268+ guest_data_prototype = malloc (perf_test_args .host_page_size );
414269 TEST_ASSERT (guest_data_prototype ,
415270 "Failed to allocate buffer for guest data pattern" );
416- memset (guest_data_prototype , 0xAB , host_page_size );
271+ memset (guest_data_prototype , 0xAB , perf_test_args . host_page_size );
417272
418273 vcpu_threads = malloc (vcpus * sizeof (* vcpu_threads ));
419274 TEST_ASSERT (vcpu_threads , "Memory allocation failed" );
420275
276+ add_vcpus (vm , vcpus , vcpu_memory_bytes );
277+
421278 if (use_uffd ) {
422279 uffd_handler_threads =
423280 malloc (vcpus * sizeof (* uffd_handler_threads ));
@@ -428,22 +285,18 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd,
428285
429286 pipefds = malloc (sizeof (int ) * vcpus * 2 );
430287 TEST_ASSERT (pipefds , "Unable to allocate memory for pipefd" );
431- }
432288
433- for (vcpu_id = 0 ; vcpu_id < vcpus ; vcpu_id ++ ) {
434- vm_paddr_t vcpu_gpa ;
435- void * vcpu_hva ;
436-
437- vm_vcpu_add_default (vm , vcpu_id , guest_code );
289+ for (vcpu_id = 0 ; vcpu_id < vcpus ; vcpu_id ++ ) {
290+ vm_paddr_t vcpu_gpa ;
291+ void * vcpu_hva ;
438292
439- vcpu_gpa = guest_test_phys_mem + (vcpu_id * vcpu_memory_bytes );
440- PER_VCPU_DEBUG ("Added VCPU %d with test mem gpa [%lx, %lx)\n" ,
441- vcpu_id , vcpu_gpa , vcpu_gpa + vcpu_memory_bytes );
293+ vcpu_gpa = guest_test_phys_mem + (vcpu_id * vcpu_memory_bytes );
294+ PER_VCPU_DEBUG ("Added VCPU %d with test mem gpa [%lx, %lx)\n" ,
295+ vcpu_id , vcpu_gpa , vcpu_gpa + vcpu_memory_bytes );
442296
443- /* Cache the HVA pointer of the region */
444- vcpu_hva = addr_gpa2hva (vm , vcpu_gpa );
297+ /* Cache the HVA pointer of the region */
298+ vcpu_hva = addr_gpa2hva (vm , vcpu_gpa );
445299
446- if (use_uffd ) {
447300 /*
448301 * Set up user fault fd to handle demand paging
449302 * requests.
@@ -460,30 +313,18 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd,
460313 if (r < 0 )
461314 exit (- r );
462315 }
463-
464- #ifdef __x86_64__
465- vcpu_set_cpuid (vm , vcpu_id , kvm_get_supported_cpuid ());
466- #endif
467-
468- vcpu_args [vcpu_id ].vm = vm ;
469- vcpu_args [vcpu_id ].vcpu_id = vcpu_id ;
470- vcpu_args [vcpu_id ].gva = guest_test_virt_mem +
471- (vcpu_id * vcpu_memory_bytes );
472- vcpu_args [vcpu_id ].pages = vcpu_memory_bytes / guest_page_size ;
473316 }
474317
475318 /* Export the shared variables to the guest */
476- sync_global_to_guest (vm , host_page_size );
477- sync_global_to_guest (vm , guest_page_size );
478- sync_global_to_guest (vm , vcpu_args );
319+ sync_global_to_guest (vm , perf_test_args );
479320
480321 pr_info ("Finished creating vCPUs and starting uffd threads\n" );
481322
482323 clock_gettime (CLOCK_MONOTONIC , & start );
483324
484325 for (vcpu_id = 0 ; vcpu_id < vcpus ; vcpu_id ++ ) {
485326 pthread_create (& vcpu_threads [vcpu_id ], NULL , vcpu_worker ,
486- & vcpu_args [vcpu_id ]);
327+ & perf_test_args . vcpu_args [vcpu_id ]);
487328 }
488329
489330 pr_info ("Started all vCPUs\n" );
@@ -514,7 +355,8 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd,
514355 pr_info ("Total guest execution time: %ld.%.9lds\n" ,
515356 ts_diff .tv_sec , ts_diff .tv_nsec );
516357 pr_info ("Overall demand paging rate: %f pgs/sec\n" ,
517- guest_num_pages / ((double )ts_diff .tv_sec + (double )ts_diff .tv_nsec / 100000000.0 ));
358+ perf_test_args .vcpu_args [0 ].pages * vcpus /
359+ ((double )ts_diff .tv_sec + (double )ts_diff .tv_nsec / 100000000.0 ));
518360
519361 ucall_uninit (vm );
520362 kvm_vm_free (vm );
0 commit comments