Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- lib/x86/processor.h | 2 +- x86/Makefile.x86_64 | 1 + x86/chaos.c | 114 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 x86/chaos.c diff --git a/lib/x86/processor.h b/lib/x86/processor.h index 291d24b..a53654a 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -546,7 +546,7 @@ static inline void irq_enable(void) asm volatile("sti"); } -static inline void invlpg(volatile void *va) +static inline void invlpg(const volatile void *va) { asm volatile("invlpg (%0)" ::"r" (va) : "memory"); } diff --git a/x86/Makefile.x86_64 b/x86/Makefile.x86_64 index af61d85..761a1d9 100644 --- a/x86/Makefile.x86_64 +++ b/x86/Makefile.x86_64 @@ -20,6 +20,7 @@ tests += $(TEST_DIR)/tscdeadline_latency.flat tests += $(TEST_DIR)/intel-iommu.flat tests += $(TEST_DIR)/vmware_backdoors.flat tests += $(TEST_DIR)/rdpru.flat +tests += $(TEST_DIR)/chaos.flat include $(SRCDIR)/$(TEST_DIR)/Makefile.common diff --git a/x86/chaos.c b/x86/chaos.c new file mode 100644 index 0000000..e723a3b --- /dev/null +++ b/x86/chaos.c @@ -0,0 +1,114 @@ +#include "libcflat.h" +#include "smp.h" +#include "bitops.h" +#include "string.h" +#include "alloc.h" +#include "alloc_page.h" +#include "asm/page.h" +#include "processor.h" + +#define MAX_NR_CPUS 256 + +struct chaos_args { + long npages; /* 0 for CPU workload. */ + const char *mem; + int invtlb; +}; + +int ncpus; +struct chaos_args all_args[MAX_NR_CPUS]; + +static void parse_arg(struct chaos_args *args, const char *arg) +{ + char *s = strdup(arg); + char *p = s; + + while (*p) { + char *word = p; + char delim = strdelim(&p, ",="); + long i = 0; + bool have_arg = false; + if (delim == '=') { + char *num = p; + strdelim(&p, ","); + if (!parse_long(num, &i)) + printf("invalid argument for %s\n", word); + else + have_arg = true; + } + + if (!strcmp(word, "mem")) { + if (!have_arg) + i = 12; + else if (i >= BITS_PER_LONG - 1 - PAGE_SHIFT) { + printf("mem argument too large, using 12\n"); + i = 12; + } + args->npages = 1 << i; + args->mem = alloc_pages(i); + if (!args->mem) + printf("could not allocate memory\n"); + printf("CPU %d: mem=%ld @ %p\n", smp_id(), i, args->mem); + } else if (!strcmp(word, "invtlb")) { + if (!have_arg) + i = 1; + else if (i != 0 && i != 1) { + printf("invtlb argument must be 0 or 1\n"); + i = 1; + } + args->invtlb = i; + printf("CPU %d: invtlb=%ld\n", smp_id(), i); + } else { + printf("invalid argument %s\n", word); + } + } + free(s); +} + +static void __attribute__((noreturn)) stress(void *data) +{ + const char *arg = data; + struct chaos_args *args = &all_args[smp_id()]; + + printf("starting CPU %d workload: %s\n", smp_id(), arg); + parse_arg(args, arg); + + for (;;) { + if (args->mem) { + const char *s = args->mem; + const char *e = s + (args->npages << PAGE_SHIFT); + long i; + for (i = args->npages; args->invtlb && i--; ) + invlpg(s + ((args->npages - i) << PAGE_SHIFT)); + while (s < e) { + (*(unsigned long *)s)++; + s += sizeof(unsigned long); + } + } + } +} + +int main(int argc, char *argv[]) +{ + int i; + + setup_vm(); + if (argc <= 1) { + return 1; + } + + argv++; + argc--; + ncpus = cpu_count(); + if (ncpus > MAX_NR_CPUS) + ncpus = MAX_NR_CPUS; + + for (i = 1; i < ncpus; ++i) { + if (i >= argc) { + break; + } + on_cpu_async(i, stress, argv[i]); + } + + stress(argv[0]); +} -- 2.29.2