diff mbox series

[kvm-unit-tests,3/4] chaos: add timer interrupt to the workload

Message ID 20201223010850.111882-4-pbonzini@redhat.com (mailing list archive)
State New, archived
Headers show
Series add generic stress test | expand

Commit Message

Paolo Bonzini Dec. 23, 2020, 1:08 a.m. UTC
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 x86/chaos.c  | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 64 insertions(+)
diff mbox series

Patch

diff --git a/x86/chaos.c b/x86/chaos.c
index e723a3b..0b1e29c 100644
--- a/x86/chaos.c
+++ b/x86/chaos.c
@@ -1,5 +1,7 @@ 
 #include "libcflat.h"
 #include "smp.h"
+#include "isr.h"
+#include "apic.h"
 #include "bitops.h"
 #include "string.h"
 #include "alloc.h"
@@ -9,14 +11,24 @@ 
 
 #define MAX_NR_CPUS 256
 
+#define TIMER_IRQ 0x44
+
 struct chaos_args {
 	long npages;		/* 0 for CPU workload. */
 	const char *mem;
 	int invtlb;
+
+	int hz;
+	bool hlt;
+};
+
+struct counters {
+	int ticks_left;
 };
 
 int ncpus;
 struct chaos_args all_args[MAX_NR_CPUS];
+struct counters cnt[MAX_NR_CPUS];
 
 static void parse_arg(struct chaos_args *args, const char *arg)
 {
@@ -58,6 +70,20 @@  static void parse_arg(struct chaos_args *args, const char *arg)
 			}
 			args->invtlb = i;
 			printf("CPU %d: invtlb=%ld\n", smp_id(), i);
+		} else if (!strcmp(word, "hz")) {
+			if (!have_arg)
+				i = 1000;
+			args->hz = i;
+			printf("CPU %d: hz=%ld\n", smp_id(), i);
+		} else if (!strcmp(word, "hlt")) {
+			if (!have_arg)
+				i = 1;
+			else if (i != 0 && i != 1) {
+				printf("hlt argument must be 0 or 1\n");
+				i = 1;
+			}
+			args->hlt = i;
+			printf("CPU %d: hlt=%ld\n", smp_id(), i);
 		} else {
 			printf("invalid argument %s\n", word);
 		}
@@ -65,6 +91,31 @@  static void parse_arg(struct chaos_args *args, const char *arg)
 	free(s);
 }
 
+static void do_timer(void)
+{
+	int cpu = smp_id();
+	struct counters *c = &cnt[cpu];
+	char out[4];
+	if (c->ticks_left > 0) {
+		c->ticks_left--;
+		return;
+	}
+
+	c->ticks_left = all_args[cpu].hz;
+
+	/* Print current CPU number.  */
+	out[2] = (cpu % 10) + '0'; cpu /= 10;
+	out[1] = (cpu % 10) + '0'; cpu /= 10;
+	out[0] = (cpu % 10) + '0'; cpu /= 10;
+	puts(out + (ncpus < 100) + (ncpus < 10));
+}
+
+static void timer(isr_regs_t *regs)
+{
+	do_timer();
+        eoi();
+}
+
 static void __attribute__((noreturn)) stress(void *data)
 {
     const char *arg = data;
@@ -73,6 +124,15 @@  static void __attribute__((noreturn)) stress(void *data)
     printf("starting CPU %d workload: %s\n", smp_id(), arg);
     parse_arg(args, arg);
 
+    apic_write(APIC_TDCR, 0x0000000b);
+    if (args->hz) {
+	    /* FIXME: assumes that the LAPIC timer counts in nanoseconds.  */
+
+	    apic_write(APIC_TMICT, 1000000000 / args->hz);
+	    apic_write(APIC_LVTT, TIMER_IRQ | APIC_LVT_TIMER_PERIODIC);
+    }
+
+    irq_enable();
     for (;;) {
 	    if (args->mem) {
 		    const char *s = args->mem;
@@ -85,6 +145,8 @@  static void __attribute__((noreturn)) stress(void *data)
 			    s += sizeof(unsigned long);
 		    }
 	    }
+	    if (args->hlt)
+		    asm volatile("hlt");
     }
 }
 
@@ -103,6 +165,8 @@  int main(int argc, char *argv[])
     if (ncpus > MAX_NR_CPUS)
 	    ncpus = MAX_NR_CPUS;
 
+    handle_irq(TIMER_IRQ, timer);
+
     for (i = 1; i < ncpus; ++i) {
         if (i >= argc) {
             break;