Skip to content

Commit

Permalink
arm/kvm: Enable support for KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
shamiali2008 authored and pm215 committed Sep 8, 2023
1 parent d03396a commit c8f2eb5
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 0 deletions.
1 change: 1 addition & 0 deletions accel/kvm/kvm-all.c
Original file line number Diff line number Diff line change
Expand Up @@ -3763,6 +3763,7 @@ static void kvm_accel_instance_init(Object *obj)
/* KVM dirty ring is by default off */
s->kvm_dirty_ring_size = 0;
s->kvm_dirty_ring_with_bitmap = false;
s->kvm_eager_split_size = 0;
s->notify_vmexit = NOTIFY_VMEXIT_OPTION_RUN;
s->notify_window = 0;
s->xen_version = 0;
Expand Down
1 change: 1 addition & 0 deletions include/sysemu/kvm_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ struct KVMState
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 */
bool kvm_dirty_ring_with_bitmap;
uint64_t kvm_eager_split_size; /* Eager Page Splitting chunk size */
struct KVMDirtyRingReaper reaper;
NotifyVmexitOption notify_vmexit;
uint32_t notify_window;
Expand Down
15 changes: 15 additions & 0 deletions qemu-options.hx
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ DEF("accel", HAS_ARG, QEMU_OPTION_accel,
" split-wx=on|off (enable TCG split w^x mapping)\n"
" tb-size=n (TCG translation block cache size)\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"
" thread=single|multi (enable multi-threaded TCG)\n", QEMU_ARCH_ALL)
SRST
Expand Down Expand Up @@ -244,6 +245,20 @@ SRST
is disabled (dirty-ring-size=0). When enabled, KVM will instead
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``
Enables or disables notify VM exit support on x86 host and specify
the corresponding notify window to trigger the VM exit if enabled.
Expand Down
61 changes: 61 additions & 0 deletions target/arm/kvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "exec/address-spaces.h"
#include "hw/boards.h"
#include "hw/irq.h"
#include "qapi/visitor.h"
#include "qemu/log.h"

const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
Expand Down Expand Up @@ -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);

return ret;
Expand Down Expand Up @@ -1069,6 +1090,46 @@ bool kvm_arch_cpu_check_are_resettable(void)
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)
{
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)");
}

0 comments on commit c8f2eb5

Please sign in to comment.