arm/kvm: Enable support for KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE

Now that we have Eager Page Split support added for ARM in the kernel,
enable it in Qemu. This adds,
 -eager-split-size to -accel sub-options to set the eager page split chunk size.
 -enable KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE.

The chunk size specifies how many pages to break at a time, using a
single allocation. Bigger the chunk size, more pages need to be
allocated ahead of time.

Reviewed-by: Gavin Shan <gshan@redhat.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Message-id: 20230905091246.1931-1-shameerali.kolothum.thodi@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Shameer Kolothum 2023-09-05 10:12:46 +01:00 committed by Peter Maydell
parent d03396a8bb
commit c8f2eb5d41
4 changed files with 78 additions and 0 deletions

View File

@ -3763,6 +3763,7 @@ static void kvm_accel_instance_init(Object *obj)
/* KVM dirty ring is by default off */ /* KVM dirty ring is by default off */
s->kvm_dirty_ring_size = 0; s->kvm_dirty_ring_size = 0;
s->kvm_dirty_ring_with_bitmap = false; s->kvm_dirty_ring_with_bitmap = false;
s->kvm_eager_split_size = 0;
s->notify_vmexit = NOTIFY_VMEXIT_OPTION_RUN; s->notify_vmexit = NOTIFY_VMEXIT_OPTION_RUN;
s->notify_window = 0; s->notify_window = 0;
s->xen_version = 0; s->xen_version = 0;

View File

@ -116,6 +116,7 @@ struct KVMState
uint64_t kvm_dirty_ring_bytes; /* Size of the per-vcpu dirty ring */ uint64_t kvm_dirty_ring_bytes; /* Size of the per-vcpu dirty ring */
uint32_t kvm_dirty_ring_size; /* Number of dirty GFNs per ring */ uint32_t kvm_dirty_ring_size; /* Number of dirty GFNs per ring */
bool kvm_dirty_ring_with_bitmap; bool kvm_dirty_ring_with_bitmap;
uint64_t kvm_eager_split_size; /* Eager Page Splitting chunk size */
struct KVMDirtyRingReaper reaper; struct KVMDirtyRingReaper reaper;
NotifyVmexitOption notify_vmexit; NotifyVmexitOption notify_vmexit;
uint32_t notify_window; uint32_t notify_window;

View File

@ -186,6 +186,7 @@ DEF("accel", HAS_ARG, QEMU_OPTION_accel,
" split-wx=on|off (enable TCG split w^x mapping)\n" " split-wx=on|off (enable TCG split w^x mapping)\n"
" tb-size=n (TCG translation block cache size)\n" " tb-size=n (TCG translation block cache size)\n"
" dirty-ring-size=n (KVM dirty ring GFN count, default 0)\n" " dirty-ring-size=n (KVM dirty ring GFN count, default 0)\n"
" eager-split-size=n (KVM Eager Page Split chunk size, default 0, disabled. ARM only)\n"
" notify-vmexit=run|internal-error|disable,notify-window=n (enable notify VM exit and set notify window, x86 only)\n" " notify-vmexit=run|internal-error|disable,notify-window=n (enable notify VM exit and set notify window, x86 only)\n"
" thread=single|multi (enable multi-threaded TCG)\n", QEMU_ARCH_ALL) " thread=single|multi (enable multi-threaded TCG)\n", QEMU_ARCH_ALL)
SRST SRST
@ -244,6 +245,20 @@ SRST
is disabled (dirty-ring-size=0). When enabled, KVM will instead is disabled (dirty-ring-size=0). When enabled, KVM will instead
record dirty pages in a bitmap. record dirty pages in a bitmap.
``eager-split-size=n``
KVM implements dirty page logging at the PAGE_SIZE granularity and
enabling dirty-logging on a huge-page requires breaking it into
PAGE_SIZE pages in the first place. KVM on ARM does this splitting
lazily by default. There are performance benefits in doing huge-page
split eagerly, especially in situations where TLBI costs associated
with break-before-make sequences are considerable and also if guest
workloads are read intensive. The size here specifies how many pages
to break at a time and needs to be a valid block size which is
1GB/2MB/4KB, 32MB/16KB and 512MB/64KB for 4KB/16KB/64KB PAGE_SIZE
respectively. Be wary of specifying a higher size as it will have an
impact on the memory. By default, this feature is disabled
(eager-split-size=0).
``notify-vmexit=run|internal-error|disable,notify-window=n`` ``notify-vmexit=run|internal-error|disable,notify-window=n``
Enables or disables notify VM exit support on x86 host and specify Enables or disables notify VM exit support on x86 host and specify
the corresponding notify window to trigger the VM exit if enabled. the corresponding notify window to trigger the VM exit if enabled.

View File

@ -30,6 +30,7 @@
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/irq.h" #include "hw/irq.h"
#include "qapi/visitor.h"
#include "qemu/log.h" #include "qemu/log.h"
const KVMCapabilityInfo kvm_arch_required_capabilities[] = { const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
@ -287,6 +288,26 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
} }
} }
if (s->kvm_eager_split_size) {
uint32_t sizes;
sizes = kvm_vm_check_extension(s, KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES);
if (!sizes) {
s->kvm_eager_split_size = 0;
warn_report("Eager Page Split support not available");
} else if (!(s->kvm_eager_split_size & sizes)) {
error_report("Eager Page Split requested chunk size not valid");
ret = -EINVAL;
} else {
ret = kvm_vm_enable_cap(s, KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE, 0,
s->kvm_eager_split_size);
if (ret < 0) {
error_report("Enabling of Eager Page Split failed: %s",
strerror(-ret));
}
}
}
kvm_arm_init_debug(s); kvm_arm_init_debug(s);
return ret; return ret;
@ -1069,6 +1090,46 @@ bool kvm_arch_cpu_check_are_resettable(void)
return true; return true;
} }
static void kvm_arch_get_eager_split_size(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
KVMState *s = KVM_STATE(obj);
uint64_t value = s->kvm_eager_split_size;
visit_type_size(v, name, &value, errp);
}
static void kvm_arch_set_eager_split_size(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
KVMState *s = KVM_STATE(obj);
uint64_t value;
if (s->fd != -1) {
error_setg(errp, "Unable to set early-split-size after KVM has been initialized");
return;
}
if (!visit_type_size(v, name, &value, errp)) {
return;
}
if (value && !is_power_of_2(value)) {
error_setg(errp, "early-split-size must be a power of two");
return;
}
s->kvm_eager_split_size = value;
}
void kvm_arch_accel_class_init(ObjectClass *oc) void kvm_arch_accel_class_init(ObjectClass *oc)
{ {
object_class_property_add(oc, "eager-split-size", "size",
kvm_arch_get_eager_split_size,
kvm_arch_set_eager_split_size, NULL, NULL);
object_class_property_set_description(oc, "eager-split-size",
"Eager Page Split chunk size for hugepages. (default: 0, disabled)");
} }