test: parallel vmexit
cover test: parallel vmexit
Run the vmexit tests in parallel on each present cpu.
PATCH 1/2 test: add wait parameter to on_cpu
To determine whether to wait for IPI to finish on remote cpu.
kvm/user/test/lib/x86/smp.c +7 -5
@@ -82,7 +82,7 @@ static void setup_smp_id(void *data) asm ("mov %0, %%gs:0" : :"r" (apic_id ()) :"memory" ); } -void on_cpu (int cpu,void (*function)(void *data),void *data) +void on_cpu (int cpu,void (*function)(void *data),void *data,int wait) {spin_lock (&ipi_lock);if (cpu ==smp_id ())
@@ -93,9 +93,11 @@ void on_cpu(int cpu, void (*function)(voapic_icr_write (APIC_INT_ASSERT |APIC_DEST_PHYSICAL |APIC_DM_FIXED |IPI_VECTOR , cpu); -while (!ipi_done) - ; - ipi_done =0 ; +if (wait) { +while (!ipi_done) + ; + ipi_done =0 ; + } }spin_unlock (&ipi_lock); }
@@ -109,6 +111,6 @@ void smp_init(void)setup_smp_id (0 );for (i =1 ; i <cpu_count (); ++i) -on_cpu (i, setup_smp_id,0 ); +on_cpu (i, setup_smp_id,0 ,1 ); }
kvm/user/test/lib/x86/smp.h +1 -1
@@ -9,7 +9,7 @@ void smp_init(void);int cpu_count (void );int smp_id (void ); -void on_cpu (int cpu,void (*function)(void *data),void *data); +void on_cpu (int cpu,void (*function)(void *data),void *data,int wait);void spin_lock (struct spinlock *lock);void spin_unlock (struct spinlock *lock);
kvm/user/test/x86/smptest.c +1 -1
@@ -20,6 +20,6 @@ int main() ncpus =cpu_count ();printf ("found %d cpus\n" , ncpus);for (i =0 ; i < ncpus; ++i) -on_cpu (i, ipi_test, (void *)(long )i); +on_cpu (i, ipi_test, (void *)(long )i,1 );return 0 ; }
kvm/user/test/x86/vmexit.c +2 -2
@@ -63,14 +63,14 @@ static void nop(void *junk)static void ipi (void ) { -on_cpu (1 , nop,0 ); +on_cpu (1 , nop,0 ,1 ); }static void ipi_halt (void ) {unsigned long long t; -on_cpu (1 , nop,0 ); +on_cpu (1 , nop,0 ,1 ); t =rdtsc () +2000 ;while (rdtsc () < t) ;
Re: [patch 1/2] test: add wait parameter to on_cpu
Quoted 78 lines · Marcelo Tosatti
To determine whether to wait for IPI to finish on remote cpu.
Signed-off-by Marcelo Tosatti<[email protected]>Index:
qemu-kvm/kvm/user/test/lib/x86/smp.c
===================================================================kvm/user/test/lib/x86/smp.c +7
-5@@ -82,7 +82,7 @@ static void setup_smp_id(void *data) asm ("mov %0, %%gs:0" : :"r" (apic_id ()) :"memory" ); } -void on_cpu (int cpu,void (*function)(void *data),void *data) +void on_cpu (int cpu,void (*function)(void *data),void *data,int wait) {spin_lock (&ipi_lock);if (cpu ==smp_id ())@@ -93,9 +93,11 @@ void on_cpu(int cpu, void (*function)(voapic_icr_write (APIC_INT_ASSERT |APIC_DEST_PHYSICAL |APIC_DM_FIXED |IPI_VECTOR , cpu); -while (!ipi_done) - ; - ipi_done =0 ; +if (wait) { +while (!ipi_done) + ; + ipi_done =0 ; + } }spin_unlock (&ipi_lock); }@@ -109,6 +111,6 @@ void smp_init(void)setup_smp_id (0 );for (i =1 ; i<cpu_count (); ++i) -on_cpu (i, setup_smp_id,0 ); +on_cpu (i, setup_smp_id,0 ,1 ); }Index:
qemu-kvm/kvm/user/test/lib/x86/smp.h
===================================================================kvm/user/test/lib/x86/smp.h +1
-1@@ -9,7 +9,7 @@ void smp_init(void);int cpu_count (void );int smp_id (void ); -void on_cpu (int cpu,void (*function)(void *data),void *data); +void on_cpu (int cpu,void (*function)(void *data),void *data,int wait);void spin_lock (struct spinlock *lock);void spin_unlock (struct spinlock *lock);Index:
qemu-kvm/kvm/user/test/x86/smptest.c
===================================================================kvm/user/test/x86/smptest.c +1
-1@@ -20,6 +20,6 @@ int main() ncpus =cpu_count ();printf ("found %d cpus\n" , ncpus);for (i =0 ; i< ncpus; ++i) -on_cpu (i, ipi_test, (void *)(long )i); +on_cpu (i, ipi_test, (void *)(long )i,1 );return 0 ; }Index:
qemu-kvm/kvm/user/test/x86/vmexit.c
===================================================================kvm/user/test/x86/vmexit.c +1
-1@@ -63,14 +63,14 @@ static void nop(void *junk)static void ipi (void ) { -on_cpu (1 , nop,0 ); +on_cpu (1 , nop,0 ,1 ); }
kvm/user/test/x86/vmexit.c static void nop(void *junk) · line 76
Quoted 10 lines
kvm/user/test/x86/vmexit.c +1
-1static void ipi_halt (void ) {unsigned long long t; -on_cpu (1 , nop,0 ); +on_cpu (1 , nop,0 ,1 ); t =rdtsc () +2000 ;while (rdtsc ()< t) ;
Boolean parameters are unreadable at the call site. I'd much prefer a new API (on_cpu_async(), with on_cpu_join() to wait for completion).
Signature · 1 line
error compiling committee.c: too many arguments to function
PATCH 2/2 test: vmexit: run parallel tests on each cpu
In reply to Marcelo TosattiSo one can measure SMP overhead.
kvm/user/test/x86/vmexit.c +17 -3
@@ -85,6 +85,9 @@ static struct test { { vmcall, "vmcall", }, { mov_from_cr8, "mov_from_cr8" }, { mov_to_cr8, "mov_to_cr8" }, +}; + +static struct test smp_tests[] = { { ipi,"ipi" , is_smp }, { ipi_halt,"ipi+halt" , is_smp }, };
@@ -113,14 +116,25 @@ static void do_test(struct test *test)#define ARRAY_SIZE (_x) (sizeof(_x) / sizeof((_x)[0])) -int main (void ) +static void do_tests (void *junk) {int i; -smp_init (); -for (i =0 ; i <ARRAY_SIZE (tests); ++i)do_test (&tests[i]); +} + +int main (void ) +{ +int i, n; + +smp_init (); + +for (n =cpu_count (); n >0 ; n--) +on_cpu (n-1 , do_tests,0 ,0 ); + +for (i =0 ; i <ARRAY_SIZE (smp_tests); ++i) +do_test (&smp_tests[i]);return 0 ; }
Re: [patch 2/2] test: vmexit: run parallel tests on each cpu
kvm/user/test/x86/vmexit.c static void do_test(struct test *test) · line 134
Quoted 6 lines · Marcelo Tosatti
So one can measure SMP overhead.
kvm/user/test/x86/vmexit.c +3
-0+ +for (n =cpu_count (); n>0 ; n--) +on_cpu (n-1 , do_tests,0 ,0 );
Should be done inside do_test(), so we can start the measurement on all cpus at the same time (right now, if some cpus calibrate earlier, they will finish sooner and the others will have an easier time).
Signature · 1 line
error compiling committee.c: too many arguments to function
cover kvm: test: parallel vmexit (v2)
In reply to Marcelo TosattiAddressing comments.
PATCH 1/2 test: add on_cpu_async
Non-wait version of on_cpu.
kvm/user/test/lib/x86/smp.c +18 -4
@@ -82,24 +82,38 @@ static void setup_smp_id(void *data) asm ("mov %0, %%gs:0" : :"r" (apic_id ()) :"memory" ); } -void on_cpu (int cpu,void (*function)(void *data),void *data) +static void __on_cpu (int cpu,void (*function)(void *data),void *data, +int wait) {spin_lock (&ipi_lock);if (cpu ==smp_id ())function (data);else { + ipi_done =0 ; ipi_function = function; ipi_data = data;apic_icr_write (APIC_INT_ASSERT |APIC_DEST_PHYSICAL |APIC_DM_FIXED |IPI_VECTOR , cpu); -while (!ipi_done) - ; - ipi_done =0 ; +if (wait) { +while (!ipi_done) + ; + } }spin_unlock (&ipi_lock); } +void on_cpu (int cpu,void (*function)(void *data),void *data) +{ +__on_cpu (cpu, function, data,1 ); +} + +void on_cpu_async (int cpu,void (*function)(void *data),void *data) +{ +__on_cpu (cpu, function, data,0 ); +} + +void smp_init (void ) {int i;
kvm/user/test/lib/x86/smp.h +1 -0
@@ -10,6 +10,7 @@ void smp_init(void);int cpu_count (void );int smp_id (void );void on_cpu (int cpu,void (*function)(void *data),void *data); +void on_cpu_async (int cpu,void (*function)(void *data),void *data);void spin_lock (struct spinlock *lock);void spin_unlock (struct spinlock *lock);
PATCH 2/2 test: vmexit: run parallel tests on each cpu
In reply to Marcelo TosattiSo one can measure SMP overhead.
kvm/user/test/x86/vmexit.c +34 -9
@@ -80,22 +80,38 @@ static struct test {void (*func)(void );const char *name;int (*valid)(void ); +int parallel; } tests[] = { - { cpuid, "cpuid", }, - { vmcall, "vmcall", }, - { mov_from_cr8, "mov_from_cr8" }, - { mov_to_cr8, "mov_to_cr8" }, - { ipi, "ipi", is_smp }, - { ipi_halt, "ipi+halt", is_smp }, + { cpuid, "cpuid", .parallel = 1, }, + { vmcall, "vmcall", .parallel = 1, }, + { mov_from_cr8, "mov_from_cr8", .parallel = 1, }, + { mov_to_cr8, "mov_to_cr8" , .parallel = 1, }, + { ipi, "ipi", is_smp, .parallel = 0, }, + { ipi_halt, "ipi+halt", is_smp, .parallel = 0, }, }; +unsigned iterations; +volatile int nr_cpus_done; + +static void run_test(void *_func) +{ + int i; + void (*func)(void) = _func; + + for (i = 0; i < iterations; ++i) + func(); + + nr_cpus_done++; +} + static void do_test(struct test *test) { int i; unsigned long long t1, t2; - unsigned iterations = 32; void (*func)(void) = test->func; + iterations = 32; + if (test->valid && !test->valid()) { printf("%s (skipped)\n", test->name); return;
@@ -104,8 +120,17 @@ static void do_test(struct test *test)do { iterations *=2 ; t1 =rdtsc (); -for (i =0 ; i < iterations; ++i) -func (); + +if (!test->parallel) { +for (i =0 ; i < iterations; ++i) +func (); + }else { + nr_cpus_done =0 ; +for (i =cpu_count (); i >0 ; i--) +on_cpu_async (i-1 , run_test, func); +while (nr_cpus_done <cpu_count ()) + ; + } t2 =rdtsc (); }while ((t2 - t1) <GOAL );printf ("%s %d\n" , test->name, (int )((t2 - t1) / iterations));
PATCH 3/3 test: vmexit: inl from pmtimer
Add inl(ACPI_PMTIMER_PORT) test.
kvm/user/test/x86/vmexit.c +13 -0
@@ -17,6 +17,13 @@ static inline unsigned long long rdtsc()return r; } +static unsigned int inl (unsigned short port) +{ +unsigned int val; + asmvolatile ("inl %w1, %0" :"=a" (val) :"Nd" (port)); +return val; +} +#define GOAL (1ull << 30)#ifdef __x86_64__
@@ -76,6 +83,11 @@ static void ipi_halt(void) ; } +static void inl_pmtimer (void ) +{ +inl (0xb008 ); +} + static struct test { void (*func)(void); const char *name;
@@ -86,6 +98,7 @@ static struct test { { vmcall, "vmcall", .parallel = 1, }, { mov_from_cr8, "mov_from_cr8", .parallel = 1, }, { mov_to_cr8, "mov_to_cr8" , .parallel = 1, }, + { inl_pmtimer, "inl_from_pmtimer", .parallel = 1, }, { ipi, "ipi", is_smp, .parallel = 0, }, { ipi_halt, "ipi+halt", is_smp, .parallel = 0, }, };
Avi Kivity
AppliedRe: [patch 0/2] kvm: test: parallel vmexit (v2)
In reply to Marcelo TosattiQuoted 4 lines · Marcelo Tosatti
Addressing comments.
Applied all three, thanks.
Signature · 1 line
error compiling committee.c: too many arguments to function