Skip to contentSkip to conversation

test: parallel vmexit

PATCH In review Marcelo Tosatti 2 participants 10 messages Sep 28, 2009 – Oct 6, 2009 KVM

lore
Share & tools
lore
#0 lore raw

cover test: parallel vmexit

Run the vmexit tests in parallel on each present cpu.

#1 lore raw

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
Index: qemu-kvm/kvm/user/test/lib/x86/smp.c
===================================================================
@@ -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)(vo
 	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)
+		    ;
+		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
Index: qemu-kvm/kvm/user/test/lib/x86/smp.h
===================================================================
@@ -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
Index: qemu-kvm/kvm/user/test/x86/smptest.c
===================================================================
@@ -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
Index: qemu-kvm/kvm/user/test/x86/vmexit.c
===================================================================
@@ -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)
 		;
#2 lore raw

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.

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)(vo
  	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)
+		    ;
+		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 -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)
  		;

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
#3 lore raw

PATCH 2/2 test: vmexit: run parallel tests on each cpu

In reply to Marcelo Tosatti

So one can measure SMP overhead.

kvm/user/test/x86/vmexit.c +17 -3
Index: qemu-kvm-test/kvm/user/test/x86/vmexit.c
===================================================================
@@ -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;
 }
#4 lore raw

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
#6 lore raw

PATCH 1/2 test: add on_cpu_async

Non-wait version of on_cpu.

kvm/user/test/lib/x86/smp.c +18 -4
Index: qemu-kvm-parallel-vmexit/kvm/user/test/lib/x86/smp.c
===================================================================
@@ -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
Index: qemu-kvm-parallel-vmexit/kvm/user/test/lib/x86/smp.h
===================================================================
@@ -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);
 
#7 lore raw

PATCH 2/2 test: vmexit: run parallel tests on each cpu

In reply to Marcelo Tosatti

So one can measure SMP overhead.

kvm/user/test/x86/vmexit.c +34 -9
Index: qemu-kvm-parallel-vmexit/kvm/user/test/x86/vmexit.c
===================================================================
@@ -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));
#8 lore raw

PATCH 3/3 test: vmexit: inl from pmtimer

Add inl(ACPI_PMTIMER_PORT) test.

kvm/user/test/x86/vmexit.c +13 -0
Index: qemu-kvm-parallel-vmexit/kvm/user/test/x86/vmexit.c
===================================================================
@@ -17,6 +17,13 @@ static inline unsigned long long rdtsc()
 	return r;
 }
 
+static unsigned int inl(unsigned short port)
+{
+    unsigned int val;
+    asm volatile("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, },
 };
Applied
#9 lore raw

Re: [patch 0/2] kvm: test: parallel vmexit (v2)

In reply to Marcelo Tosatti
Quoted 4 lines · Marcelo Tosatti

Addressing comments.

Applied all three, thanks.

Signature · 1 line
error compiling committee.c: too many arguments to function