KVM: selftests: Allowing running dirty_log_perf_test on specific CPUs

Add a command line option, -c, to pin vCPUs to physical CPUs (pCPUs),
i.e.  to force vCPUs to run on specific pCPUs.

Requirement to implement this feature came in discussion on the patch
"Make page tables for eager page splitting NUMA aware"
https://lore.kernel.org/lkml/YuhPT2drgqL+osLl@google.com/

This feature is useful as it provides a way to analyze performance based
on the vCPUs and dirty log worker locations, like on the different NUMA
nodes or on the same NUMA nodes.

To keep things simple, implementation is intentionally very limited,
either all of the vCPUs will be pinned followed by an optional main
thread or nothing will be pinned.

Signed-off-by: Vipin Sharma <vipinsh@google.com>
Suggested-by: David Matlack <dmatlack@google.com>
Reviewed-by: Sean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/r/20221103191719.1559407-8-vipinsh@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
Vipin Sharma
2022-11-03 12:17:19 -07:00
committed by Sean Christopherson
parent 0001725d0f
commit d886724ea8
5 changed files with 92 additions and 3 deletions

View File

@@ -11,6 +11,7 @@
#include "processor.h"
#include <assert.h>
#include <sched.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -443,6 +444,59 @@ struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm)
return vm_vcpu_recreate(vm, 0);
}
void kvm_pin_this_task_to_pcpu(uint32_t pcpu)
{
cpu_set_t mask;
int r;
CPU_ZERO(&mask);
CPU_SET(pcpu, &mask);
r = sched_setaffinity(0, sizeof(mask), &mask);
TEST_ASSERT(!r, "sched_setaffinity() failed for pCPU '%u'.\n", pcpu);
}
static uint32_t parse_pcpu(const char *cpu_str, const cpu_set_t *allowed_mask)
{
uint32_t pcpu = atoi_non_negative("CPU number", cpu_str);
TEST_ASSERT(CPU_ISSET(pcpu, allowed_mask),
"Not allowed to run on pCPU '%d', check cgroups?\n", pcpu);
return pcpu;
}
void kvm_parse_vcpu_pinning(const char *pcpus_string, uint32_t vcpu_to_pcpu[],
int nr_vcpus)
{
cpu_set_t allowed_mask;
char *cpu, *cpu_list;
char delim[2] = ",";
int i, r;
cpu_list = strdup(pcpus_string);
TEST_ASSERT(cpu_list, "strdup() allocation failed.\n");
r = sched_getaffinity(0, sizeof(allowed_mask), &allowed_mask);
TEST_ASSERT(!r, "sched_getaffinity() failed");
cpu = strtok(cpu_list, delim);
/* 1. Get all pcpus for vcpus. */
for (i = 0; i < nr_vcpus; i++) {
TEST_ASSERT(cpu, "pCPU not provided for vCPU '%d'\n", i);
vcpu_to_pcpu[i] = parse_pcpu(cpu, &allowed_mask);
cpu = strtok(NULL, delim);
}
/* 2. Check if the main worker needs to be pinned. */
if (cpu) {
kvm_pin_this_task_to_pcpu(parse_pcpu(cpu, &allowed_mask));
cpu = strtok(NULL, delim);
}
TEST_ASSERT(!cpu, "pCPU list contains trailing garbage characters '%s'", cpu);
free(cpu_list);
}
/*
* Userspace Memory Region Find
*