[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v10 3/3] cpus-common: implement dirty page limit on virtual CPU
From: |
huangy81 |
Subject: |
[PATCH v10 3/3] cpus-common: implement dirty page limit on virtual CPU |
Date: |
Tue, 14 Dec 2021 19:07:34 +0800 |
From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn>
Implement dirtyrate calculation periodically basing on
dirty-ring and throttle virtual CPU until it reachs the quota
dirty page rate given by user.
Introduce qmp commands "vcpu-dirty-limit", "query-vcpu-dirty-limit"
to enable, disable, query dirty page limit for virtual CPU.
Meanwhile, introduce corresponding hmp commands "vcpu_dirty_limit",
"info vcpu_dirty_limit" so developers can play with them easier.
Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn>
---
cpus-common.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++
hmp-commands-info.hx | 13 +++++
hmp-commands.hx | 17 ++++++
include/monitor/hmp.h | 2 +
qapi/migration.json | 44 ++++++++++++++
5 files changed, 231 insertions(+)
diff --git a/cpus-common.c b/cpus-common.c
index 6e73d3e..37c3584 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -23,6 +23,15 @@
#include "hw/core/cpu.h"
#include "sysemu/cpus.h"
#include "qemu/lockable.h"
+#include "sysemu/dirtylimit.h"
+#include "sysemu/cpu-throttle.h"
+#include "sysemu/kvm.h"
+#include "monitor/hmp.h"
+#include "monitor/monitor.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-migration.h"
+#include "hw/boards.h"
static QemuMutex qemu_cpu_list_lock;
static QemuCond exclusive_cond;
@@ -352,3 +361,149 @@ void process_queued_cpu_work(CPUState *cpu)
qemu_mutex_unlock(&cpu->work_mutex);
qemu_cond_broadcast(&qemu_work_cond);
}
+
+void qmp_vcpu_dirty_limit(bool enable,
+ bool has_cpu_index,
+ uint64_t cpu_index,
+ bool has_dirty_rate,
+ uint64_t dirty_rate,
+ Error **errp)
+{
+ static bool initialized;
+
+ if (!kvm_enabled() || !kvm_dirty_ring_enabled()) {
+ if (enable) {
+ error_setg(errp, "dirty page limit feature requires KVM with"
+ " accelerator property 'dirty-ring-size' set'");
+ }
+ return;
+ }
+
+ if (!enable && !dirtylimit_in_service()) {
+ return;
+ }
+
+ if (!initialized) {
+ MachineState *ms = MACHINE(qdev_get_machine());
+ dirtylimit_calc_state_init(ms->smp.max_cpus);
+ dirtylimit_state_init(ms->smp.max_cpus);
+ initialized = true;
+ }
+
+ if (enable && !has_dirty_rate) {
+ error_setg(errp, "enable dirty page limit feature requires"
+ " 'dirty-rate' set'");
+ return;
+ }
+
+ if (has_cpu_index && !dirtylimit_is_vcpu_index_valid(cpu_index)) {
+ error_setg(errp, "incorrect cpu index specified");
+ return;
+ }
+
+ if (enable) {
+ dirtylimit_calc_start();
+ if (has_cpu_index) {
+ dirtylimit_vcpu(cpu_index, dirty_rate);
+ } else {
+ dirtylimit_all(dirty_rate);
+ }
+ } else {
+ if (has_cpu_index) {
+ dirtylimit_cancel_vcpu(cpu_index);
+ } else {
+ dirtylimit_cancel_all();
+ }
+
+ if (!dirtylimit_in_service()) {
+ dirtylimit_calc_quit();
+ dirtylimit_state_finalize();
+ dirtylimit_calc_state_finalize();
+ initialized = false;
+ }
+ }
+}
+
+void hmp_vcpu_dirty_limit(Monitor *mon, const QDict *qdict)
+{
+ bool global = qdict_get_try_bool(qdict, "global", false);
+ bool enable = qdict_get_bool(qdict, "enable");
+ int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1);
+ int64_t dirty_rate = qdict_get_try_int(qdict, "dirty_rate", -1);
+ Error *err = NULL;
+
+ if (enable && dirty_rate < 0) {
+ monitor_printf(mon, "Dirty page limit requires dirty_rate set!\n");
+ return;
+ }
+
+ if (enable && !global && cpu_index < 0) {
+ monitor_printf(mon, "Dirty page limit requires cpu_index set!\n");
+ return;
+ }
+
+ if (global && cpu_index != -1) {
+ monitor_printf(mon, "Either global option or cpu_index can be set!\n");
+ return;
+ }
+
+ if (global) {
+ if (enable) {
+ qmp_vcpu_dirty_limit(true, false, -1, true, dirty_rate, &err);
+ } else {
+ qmp_vcpu_dirty_limit(false, false, -1, false, -1, &err);
+ }
+ } else {
+ if (enable) {
+ qmp_vcpu_dirty_limit(true, true, cpu_index, true, dirty_rate,
&err);
+ } else {
+ qmp_vcpu_dirty_limit(false, true, cpu_index, false, -1, &err);
+ }
+ }
+
+ if (err) {
+ hmp_handle_error(mon, err);
+ return;
+ }
+
+ monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query "
+ "dirty limit for virtual CPU]\n");
+}
+
+struct DirtyLimitInfoList *qmp_query_vcpu_dirty_limit(Error **errp)
+{
+ if (!dirtylimit_in_service()) {
+ error_setg(errp, "dirty page limit not enabled");
+ return NULL;
+ }
+
+ return dirtylimit_query_all();
+}
+
+void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict)
+{
+ DirtyLimitInfoList *limit, *head, *info = NULL;
+ Error *err = NULL;
+
+ if (!dirtylimit_in_service()) {
+ monitor_printf(mon, "Dirty page limit not enabled!\n");
+ return;
+ }
+
+ info = qmp_query_vcpu_dirty_limit(&err);
+ if (err) {
+ hmp_handle_error(mon, err);
+ return;
+ }
+
+ head = info;
+ for (limit = head; limit != NULL; limit = limit->next) {
+ monitor_printf(mon, "vcpu[%"PRIi64"], limit rate %"PRIi64 " (MB/s),"
+ " current rate %"PRIi64 " (MB/s)\n",
+ limit->value->cpu_index,
+ limit->value->limit_rate,
+ limit->value->current_rate);
+ }
+
+ g_free(info);
+}
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 407a1da..5dd3001 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -863,6 +863,19 @@ SRST
Display the vcpu dirty rate information.
ERST
+ {
+ .name = "vcpu_dirty_limit",
+ .args_type = "",
+ .params = "",
+ .help = "show dirty page limit information of all vCPU",
+ .cmd = hmp_info_vcpu_dirty_limit,
+ },
+
+SRST
+ ``info vcpu_dirty_limit``
+ Display the vcpu dirty page limit information.
+ERST
+
#if defined(TARGET_I386)
{
.name = "sgx",
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 70a9136..ef0f7cc 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1744,3 +1744,20 @@ ERST
"\n\t\t\t -b to specify dirty bitmap as method of
calculation)",
.cmd = hmp_calc_dirty_rate,
},
+
+SRST
+``vcpu_dirty_limit``
+ Start dirty page rate limit on a virtual CPU, the information about all the
+ virtual CPU dirty limit status can be observed with ``info vcpu_dirty_limit``
+ command.
+ERST
+
+ {
+ .name = "vcpu_dirty_limit",
+ .args_type = "global:-g,enable:b,cpu_index:l?,dirty_rate:l?",
+ .params = "[-g] on|off [cpu_index] [dirty_rate]",
+ .help = "turn on,off dirty page rate limit"
+ "\n\t\t (use -g to affect all vCPU, cpu_index required
be set to -1 if"
+ "\n\t\t enable all vCPU. dirty_rate should be specified
if turned on)",
+ .cmd = hmp_vcpu_dirty_limit,
+ },
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index 96d0148..04879a2 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -131,6 +131,8 @@ void hmp_replay_delete_break(Monitor *mon, const QDict
*qdict);
void hmp_replay_seek(Monitor *mon, const QDict *qdict);
void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict);
void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict);
+void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict);
+void hmp_vcpu_dirty_limit(Monitor *mon, const QDict *qdict);
void hmp_human_readable_text_helper(Monitor *mon,
HumanReadableText *(*qmp_handler)(Error
**));
diff --git a/qapi/migration.json b/qapi/migration.json
index ac5fa56..7d8da4f 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1869,6 +1869,50 @@
'current-rate': 'int64' } }
##
+# @vcpu-dirty-limit:
+#
+# Set or cancel the upper limit of dirty page rate for a virtual CPU.
+#
+# Requires KVM with accelerator property "dirty-ring-size" set.
+# A virtual CPU's dirty page rate is a measure of its memory load.
+# To observe dirty page rates, use @calc-dirty-rate.
+#
+# @enable: true to enable, false to disable.
+#
+# @cpu-index: index of virtual CPU, default is all.
+#
+# @dirty-rate: upper limit of dirty page rate for virtual CPU, to
+# cancel dirty limit, this field will be ignored.
+#
+# Since: 7.0
+#
+# Example:
+# {"execute": "vcpu-dirty-limit"}
+# "arguments": { "enable": true,
+# "cpu-index": 1,
+# "dirty-rate": 200 } }
+#
+##
+{ 'command': 'vcpu-dirty-limit',
+ 'data': { 'enable': 'bool',
+ '*cpu-index': 'uint64',
+ '*dirty-rate': 'uint64'} }
+
+##
+# @query-vcpu-dirty-limit:
+#
+# Returns information about all virtual CPU dirty limit if enabled.
+#
+# Since: 7.0
+#
+# Example:
+# {"execute": "query-vcpu-dirty-limit"}
+#
+##
+{ 'command': 'query-vcpu-dirty-limit',
+ 'returns': [ 'DirtyLimitInfo' ] }
+
+##
# @snapshot-save:
#
# Save a VM snapshot
--
1.8.3.1
- [PATCH v10 2/3] cpu-throttle: implement virtual CPU throttle, (continued)
- [PATCH v10 3/3] cpus-common: implement dirty page limit on virtual CPU,
huangy81 <=
- Re: [PATCH v10 3/3] cpus-common: implement dirty page limit on virtual CPU, Markus Armbruster, 2021/12/15
- Re: [PATCH v10 3/3] cpus-common: implement dirty page limit on virtual CPU, Markus Armbruster, 2021/12/15
- Re: [PATCH v10 3/3] cpus-common: implement dirty page limit on virtual CPU, Peter Xu, 2021/12/16
- Re: [PATCH v10 3/3] cpus-common: implement dirty page limit on virtual CPU, Hyman Huang, 2021/12/16
- Re: [PATCH v10 3/3] cpus-common: implement dirty page limit on virtual CPU, Markus Armbruster, 2021/12/16
- Re: [PATCH v10 3/3] cpus-common: implement dirty page limit on virtual CPU, Peter Xu, 2021/12/24