[PATCH] NEWS: Document domain memory dirty rate APIs

2021-03-18 Thread Hao Wang
Signed-off-by: Hao Wang 
---
 NEWS.rst | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/NEWS.rst b/NEWS.rst
index bd40373a80..df35044ef0 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -13,6 +13,17 @@ v7.2.0 (unreleased)
 
 * **New features**
 
+  * qemu: Implement domain memory dirty rate calculation API
+
+New API (``virDomainStartDirtyRateCalc()``) and virsh command
+(``domdirtyrate-calc``) are added to start calculating a live domain's
+memory dirty rate.
+
+  * qemu: Support reporting memory dirty rate stats
+
+The memory dirty rate stats can be obtained through ``virsh domstats
+--dirtyrate`` via the virConnectGetAllDomainStats API.
+
 * **Improvements**
 
 * **Bug fixes**
-- 
2.23.0




Re: [PATCH v7 0/7] migration/dirtyrate: Introduce APIs for getting domain memory dirty rate

2021-03-18 Thread Hao Wang
Sure. I'll post NEWS.rst information soon, and really appreciate your help!

Best Regards,
Hao

On 2021/3/18 15:49, Michal Privoznik wrote:
> On 3/16/21 1:32 PM, Hao Wang wrote:
>> Hao Wang (7):
>>    migration/dirtyrate: Introduce virDomainStartDirtyRateCalc API
>>    migration/dirtyrate: Implement qemuDomainStartDirtyRateCalc
>>    migration/dirtyrate: Introduce domdirtyrate-calc virsh api
>>    migration/dirtyrate: Introduce virDomainDirtyRateStatus enum
>>    migration/dirtyrate: Implement qemuMonitorQueryDirtyRate
>>    migration/dirtyrate: Extend dirtyrate statistics for domGetStats
>>    migration/dirtyrate: Introduce command 'virsh domstats --dirtyrate'
>>
>>   docs/manpages/virsh.rst  |  33 +-
>>   include/libvirt/libvirt-domain.h |  23 +++
>>   src/driver-hypervisor.h  |   6 ++
>>   src/libvirt-domain.c |  59 +
>>   src/libvirt_public.syms  |   5 ++
>>   src/qemu/qemu_driver.c   | 110 +++
>>   src/qemu/qemu_monitor.c  |  24 +++
>>   src/qemu/qemu_monitor.h  |  19 +
>>   src/qemu/qemu_monitor_json.c | 101 
>>   src/qemu/qemu_monitor_json.h |   8 +++
>>   src/remote/remote_driver.c   |   1 +
>>   src/remote/remote_protocol.x |  14 +++-
>>   src/remote_protocol-structs  |   6 ++
>>   tools/virsh-domain-monitor.c |   7 ++
>>   tools/virsh-domain.c |  58 
>>   15 files changed, 471 insertions(+), 3 deletions(-)
>>
> 
> Looks good to me.
> 
> Reviewed-by: Michal Privoznik 
> 
> Will push shortly. Can you please post a follow up patch that adds NEWS.rst 
> entry? I think this deserves to be mention in release notes.
> 
> Michal
> 
> .




[PATCH v7 0/7] migration/dirtyrate: Introduce APIs for getting domain memory dirty rate

2021-03-16 Thread Hao Wang
V6 -> V7:
add virDomainDirtyRateStatus enum
define calc_status as int
split 5/5 in v6 into two parts:
6/7 in v7: extend dirtyrate statistics for domGetStats
7/7 in v7: extend corresponding virsh command

V5 -> V6:
split DomainGetDirtyRateInfo(domdirtyrate) API into two parts:
1. DomainStartDirtyRateCalc(domdirtyrate-calc) for starting dirty rate
   calculation;
2. qemuDomainGetStatsDirtyRate(domstats --dirtyrate) for querying dirty
   rate infomation.

V4 -> V5:
squash 1/7 and bits of 5/7 and 6/7 into 2/7 in v4 (to be 1/5 in v5)
squash left of 5/7 into 4/7 in v4 (to be 3/5 in v5)
add VIR_DOMAIN_DIRTYRATE_DEFAULT flag
remove redundant error report
rename virsh api to "domdirtyrate"
use vshTablePtr for virsh api output
add description in docs/manpages/virsh.rst
other format optimize

V3 -> V4:
define flags to unsigned int
fix some compile warnings

V2 -> V3:
reorganize patchset to fix compile warning

V1 -> V2:
replace QEMU_JOB_ASYNC with QEMU_JOB_QUERY


Sometimes domain's memory dirty rate is expected by user in order to
decide whether it's proper to be migrated out or not.

We have already completed the QEMU part of the capability:
https://patchew.org/QEMU/1600237327-33618-1-git-send-email-zhengch...@huawei.com/
And this serial of patches introduce the corresponding LIBVIRT part:

1. Calculating
Introduce a new API DomainStartDirtyRateCalc and corresponding virsh api
(domdirtyrate-calc) for starting dirty rate calculation by calling qmp
'calc-dirty-rate'.

# virsh domdirtyrate-calc  [--seconds ]

2. Querying
Introduce command 'virsh domstats --dirtyrate' for reporting memory
dirty rate infomation by calling qmp 'query-dirty-rate'.

The info is listed as:
Domain: 'vm0'
  dirtyrate.calc_status=2
  dirtyrate.calc_start_time=1534523
  dirtyrate.calc_period=1
  dirtyrate.megabytes_per_second=5


Hao Wang (7):
  migration/dirtyrate: Introduce virDomainStartDirtyRateCalc API
  migration/dirtyrate: Implement qemuDomainStartDirtyRateCalc
  migration/dirtyrate: Introduce domdirtyrate-calc virsh api
  migration/dirtyrate: Introduce virDomainDirtyRateStatus enum
  migration/dirtyrate: Implement qemuMonitorQueryDirtyRate
  migration/dirtyrate: Extend dirtyrate statistics for domGetStats
  migration/dirtyrate: Introduce command 'virsh domstats --dirtyrate'

 docs/manpages/virsh.rst  |  33 +-
 include/libvirt/libvirt-domain.h |  23 +++
 src/driver-hypervisor.h  |   6 ++
 src/libvirt-domain.c |  59 +
 src/libvirt_public.syms  |   5 ++
 src/qemu/qemu_driver.c   | 110 +++
 src/qemu/qemu_monitor.c  |  24 +++
 src/qemu/qemu_monitor.h  |  19 ++
 src/qemu/qemu_monitor_json.c | 101 
 src/qemu/qemu_monitor_json.h |   8 +++
 src/remote/remote_driver.c   |   1 +
 src/remote/remote_protocol.x |  14 +++-
 src/remote_protocol-structs  |   6 ++
 tools/virsh-domain-monitor.c |   7 ++
 tools/virsh-domain.c |  58 
 15 files changed, 471 insertions(+), 3 deletions(-)

-- 
2.23.0




[PATCH v7 4/7] migration/dirtyrate: Introduce virDomainDirtyRateStatus enum

2021-03-16 Thread Hao Wang
Introduce virDomainDirtyRateStatus enum.

Signed-off-by: Hao Wang 
---
 include/libvirt/libvirt-domain.h | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 7aa5ef4543..b05bb94131 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5128,6 +5128,24 @@ int virDomainGetMessages(virDomainPtr domain,
  char ***msgs,
  unsigned int flags);
 
+/**
+ * virDomainDirtyRateStatus:
+ *
+ * Details on the cause of a dirty rate calculation status.
+ */
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_UNSTARTED = 0, /* the dirtyrate calculation has
+   not been started */
+VIR_DOMAIN_DIRTYRATE_MEASURING = 1, /* the dirtyrate calculation is
+   measuring */
+VIR_DOMAIN_DIRTYRATE_MEASURED  = 2, /* the dirtyrate calculation is
+   completed */
+
+# ifdef VIR_ENUM_SENTINELS
+VIR_DOMAIN_DIRTYRATE_LAST
+# endif
+} virDomainDirtyRateStatus;
+
 int virDomainStartDirtyRateCalc(virDomainPtr domain,
 int seconds,
 unsigned int flags);
-- 
2.23.0




[PATCH v7 2/7] migration/dirtyrate: Implement qemuDomainStartDirtyRateCalc

2021-03-16 Thread Hao Wang
Implement qemuDomainStartDirtyRateCalc which calculates domain's memory
dirty rate calling qmp "calc-dirty-rate".

Signed-off-by: Hao Wang 
---
 src/qemu/qemu_driver.c   | 59 
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 +++
 src/qemu/qemu_monitor_json.c | 22 ++
 src/qemu/qemu_monitor_json.h |  4 +++
 5 files changed, 101 insertions(+)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 16c5ccae45..8836d9fd16 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20342,6 +20342,64 @@ qemuDomainGetMessages(virDomainPtr dom,
 }
 
 
+#define MIN_DIRTYRATE_CALC_PERIOD 1  /* supported min dirtyrate calculating 
time: 1s */
+#define MAX_DIRTYRATE_CALC_PERIOD 60 /* supported max dirtyrate calculating 
time: 60s */
+
+static int
+qemuDomainStartDirtyRateCalc(virDomainPtr dom,
+ int seconds,
+ unsigned int flags)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+virDomainObjPtr vm;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+virCheckFlags(0, -1);
+
+if (seconds < MIN_DIRTYRATE_CALC_PERIOD ||
+seconds > MAX_DIRTYRATE_CALC_PERIOD) {
+virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+   _("seconds=%d is invalid, please choose value within 
[%d, %d]."),
+   seconds,
+   MIN_DIRTYRATE_CALC_PERIOD,
+   MAX_DIRTYRATE_CALC_PERIOD);
+return -1;
+}
+
+if (!(vm = qemuDomainObjFromDomain(dom)))
+return -1;
+
+if (virDomainStartDirtyRateCalcEnsureACL(dom->conn, vm->def) < 0)
+goto cleanup;
+
+if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
+goto cleanup;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+goto endjob;
+}
+
+VIR_DEBUG("Calculate dirty rate in next %d seconds", seconds);
+
+priv = vm->privateData;
+qemuDomainObjEnterMonitor(driver, vm);
+ret = qemuMonitorStartDirtyRateCalc(priv->mon, seconds);
+
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+ endjob:
+qemuDomainObjEndJob(driver, vm);
+
+ cleanup:
+virDomainObjEndAPI();
+return ret;
+}
+
+
 static virHypervisorDriver qemuHypervisorDriver = {
 .name = QEMU_DRIVER_NAME,
 .connectURIProbe = qemuConnectURIProbe,
@@ -20584,6 +20642,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
 .domainAuthorizedSSHKeysGet = qemuDomainAuthorizedSSHKeysGet, /* 6.10.0 */
 .domainAuthorizedSSHKeysSet = qemuDomainAuthorizedSSHKeysSet, /* 6.10.0 */
 .domainGetMessages = qemuDomainGetMessages, /* 7.1.0 */
+.domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 7.2.0 */
 };
 
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index b4f2641504..ce927687e3 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4742,3 +4742,15 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 return qemuMonitorJSONTransactionBackup(actions, device, jobname, target,
 bitmap, syncmode);
 }
+
+
+int
+qemuMonitorStartDirtyRateCalc(qemuMonitorPtr mon,
+  int seconds)
+{
+VIR_DEBUG("seconds=%d", seconds);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONStartDirtyRateCalc(mon, seconds);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index d25c26343a..94813906b4 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1526,3 +1526,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
  const char *target,
  const char *bitmap,
  qemuMonitorTransactionBackupSyncMode syncmode);
+
+int
+qemuMonitorStartDirtyRateCalc(qemuMonitorPtr mon,
+  int seconds);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index ad62e24cfc..588fcd3a1c 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9480,3 +9480,25 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 return virJSONValueGetBoolean(virJSONValueObjectGet(reply, "return"),
   migratable);
 }
+
+
+int
+qemuMonitorJSONStartDirtyRateCalc(qemuMonitorPtr mon,
+  int seconds)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("calc-dirty-rate",
+   "i:calc-time", seconds,
+   NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0

[PATCH v7 3/7] migration/dirtyrate: Introduce domdirtyrate-calc virsh api

2021-03-16 Thread Hao Wang
Introduce domdirtyrate-calc virsh api to start calculating domain's
memory dirty rate:
# virsh domdirtyrate-calc  [--seconds ]

Signed-off-by: Hao Wang 
---
 docs/manpages/virsh.rst | 17 
 tools/virsh-domain.c| 58 +
 2 files changed, 75 insertions(+)

diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index 9ff31a0160..367b4bddeb 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -1704,6 +1704,23 @@ states other than "ok" or "error" the command also 
prints number of
 seconds elapsed since the control interface entered its current state.
 
 
+domdirtyrate-calc
+-
+
+**Syntax:**
+
+::
+
+   domdirtyrate-calc  [--seconds ]
+
+Calculate an active domain's memory dirty rate which may be expected by
+user in order to decide whether it's proper to be migrated out or not.
+The ``seconds`` parameter can be used to calculate dirty rate in a
+specific time which allows 60s at most now and would be default to 1s
+if missing. The calculated dirty rate information is available by calling
+'domstats --dirtyrate'.
+
+
 domdisplay
 --
 
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index f8f36ce361..7db88f700a 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -14402,6 +14402,58 @@ cmdSetUserSSHKeys(vshControl *ctl, const vshCmd *cmd)
 }
 
 
+/*
+ * "domdirtyrate" command
+ */
+static const vshCmdInfo info_domdirtyrate_calc[] = {
+{.name = "help",
+ .data = N_("Calculate a vm's memory dirty rate")
+},
+{.name = "desc",
+ .data = N_("Calculate memory dirty rate of a domain in order to "
+"decide whether it's proper to be migrated out or not.\n"
+"The calculated dirty rate information is available by "
+"calling 'domstats --dirtyrate'.")
+},
+{.name = NULL}
+};
+
+static const vshCmdOptDef opts_domdirtyrate_calc[] = {
+VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+{.name = "seconds",
+ .type = VSH_OT_INT,
+ .help = N_("calculate memory dirty rate within specified seconds, "
+"the supported value range from 1 to 60, default to 1.")
+},
+{.name = NULL}
+};
+
+static bool
+cmdDomDirtyRateCalc(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom = NULL;
+int seconds = 1; /* the default value is 1 */
+bool ret = false;
+
+if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+if (vshCommandOptInt(ctl, cmd, "seconds", ) < 0)
+goto cleanup;
+
+if (virDomainStartDirtyRateCalc(dom, seconds, 0) < 0)
+goto cleanup;
+
+vshPrintExtra(ctl, _("Start to calculate domain's memory "
+ "dirty rate successfully.\n"));
+ret = true;
+
+ cleanup:
+virshDomainFree(dom);
+return ret;
+}
+
+
 const vshCmdDef domManagementCmds[] = {
 {.name = "attach-device",
  .handler = cmdAttachDevice,
@@ -15041,5 +15093,11 @@ const vshCmdDef domManagementCmds[] = {
  .info = info_guestinfo,
  .flags = 0
 },
+{.name = "domdirtyrate-calc",
+ .handler = cmdDomDirtyRateCalc,
+ .opts = opts_domdirtyrate_calc,
+ .info = info_domdirtyrate_calc,
+ .flags = 0
+},
 {.name = NULL}
 };
-- 
2.23.0




[PATCH v7 5/7] migration/dirtyrate: Implement qemuMonitorQueryDirtyRate

2021-03-16 Thread Hao Wang
Implement qemuMonitorQueryDirtyRate which query domain's memory
dirty rate calling qmp "query-dirty-rate".

Signed-off-by: Hao Wang 
---
 src/qemu/qemu_monitor.c  | 12 ++
 src/qemu/qemu_monitor.h  | 15 +++
 src/qemu/qemu_monitor_json.c | 79 
 src/qemu/qemu_monitor_json.h |  4 ++
 4 files changed, 110 insertions(+)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index ce927687e3..9f1f645b0b 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4754,3 +4754,15 @@ qemuMonitorStartDirtyRateCalc(qemuMonitorPtr mon,
 
 return qemuMonitorJSONStartDirtyRateCalc(mon, seconds);
 }
+
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  qemuMonitorDirtyRateInfoPtr info)
+{
+VIR_DEBUG("info=%p", info);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONQueryDirtyRate(mon, info);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 94813906b4..c812aa9cc3 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1530,3 +1530,18 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 int
 qemuMonitorStartDirtyRateCalc(qemuMonitorPtr mon,
   int seconds);
+
+typedef struct _qemuMonitorDirtyRateInfo qemuMonitorDirtyRateInfo;
+typedef qemuMonitorDirtyRateInfo *qemuMonitorDirtyRateInfoPtr;
+
+struct _qemuMonitorDirtyRateInfo {
+int status; /* the status of last dirtyrate calculation,
+   one of virDomainDirtyRateStatus */
+int calcTime;   /* the period of dirtyrate calculation */
+long long startTime;/* the start time of dirtyrate calculation */
+long long dirtyRate;/* the dirtyrate in MiB/s */
+};
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  qemuMonitorDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 588fcd3a1c..b669630bc8 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9502,3 +9502,82 @@ qemuMonitorJSONStartDirtyRateCalc(qemuMonitorPtr mon,
 
 return 0;
 }
+
+VIR_ENUM_DECL(qemuMonitorDirtyRateStatus);
+VIR_ENUM_IMPL(qemuMonitorDirtyRateStatus,
+  VIR_DOMAIN_DIRTYRATE_LAST,
+  "unstarted",
+  "measuring",
+  "measured");
+
+static int
+qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
+qemuMonitorDirtyRateInfoPtr info)
+{
+const char *statusstr;
+int status;
+
+if (!(statusstr = virJSONValueObjectGetString(data, "status"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'status' data"));
+return -1;
+}
+
+if ((status = qemuMonitorDirtyRateStatusTypeFromString(statusstr)) < 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR,
+   _("Unknown dirty rate status: %s"), statusstr);
+return -1;
+}
+info->status = status;
+
+/* `query-dirty-rate` replies `dirty-rate` data only if the status of the 
latest
+ * calculation is `measured`.
+ */
+if ((info->status == VIR_DOMAIN_DIRTYRATE_MEASURED) &&
+(virJSONValueObjectGetNumberLong(data, "dirty-rate", >dirtyRate) 
< 0)) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'dirty-rate' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "start-time", >startTime) 
< 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'start-time' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberInt(data, "calc-time", >calcTime) < 
0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'calc-time' 
data"));
+return -1;
+}
+
+return 0;
+}
+
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  qemuMonitorDirtyRateInfoPtr info)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+virJSONValuePtr data = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("query-dirty-rate", NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'return' data"));
+return -1;
+}

[PATCH v7 1/7] migration/dirtyrate: Introduce virDomainStartDirtyRateCalc API

2021-03-16 Thread Hao Wang
Introduce virDomainStartDirtyRateCalc API for start calculation of
a domain's memory dirty rate with a specified time.

Signed-off-by: Hao Wang 
---
 include/libvirt/libvirt-domain.h |  4 +++
 src/driver-hypervisor.h  |  6 +
 src/libvirt-domain.c | 44 
 src/libvirt_public.syms  |  5 
 src/remote/remote_driver.c   |  1 +
 src/remote/remote_protocol.x | 14 +-
 src/remote_protocol-structs  |  6 +
 7 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 8011cf9fe1..7aa5ef4543 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5128,4 +5128,8 @@ int virDomainGetMessages(virDomainPtr domain,
  char ***msgs,
  unsigned int flags);
 
+int virDomainStartDirtyRateCalc(virDomainPtr domain,
+int seconds,
+unsigned int flags);
+
 #endif /* LIBVIRT_DOMAIN_H */
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index 05d7dfb5c7..2ec7b8b24a 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1405,6 +1405,11 @@ typedef int
char ***msgs,
unsigned int flags);
 
+typedef int
+(*virDrvDomainStartDirtyRateCalc)(virDomainPtr domain,
+  int seconds,
+  unsigned int flags);
+
 typedef struct _virHypervisorDriver virHypervisorDriver;
 typedef virHypervisorDriver *virHypervisorDriverPtr;
 
@@ -1671,4 +1676,5 @@ struct _virHypervisorDriver {
 virDrvDomainAuthorizedSSHKeysGet domainAuthorizedSSHKeysGet;
 virDrvDomainAuthorizedSSHKeysSet domainAuthorizedSSHKeysSet;
 virDrvDomainGetMessages domainGetMessages;
+virDrvDomainStartDirtyRateCalc domainStartDirtyRateCalc;
 };
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index e54d11e513..91001fc4ed 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -13158,3 +13158,47 @@ virDomainGetMessages(virDomainPtr domain,
 virDispatchError(conn);
 return -1;
 }
+
+
+/**
+ * virDomainStartDirtyRateCalc:
+ * @domain: a domain object
+ * @seconds: specified calculating time in seconds
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Calculate the current domain's memory dirty rate in next @seconds.
+ * The calculated dirty rate information is available by calling
+ * virConnectGetAllDomainStats.
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainStartDirtyRateCalc(virDomainPtr domain,
+int seconds,
+unsigned int flags)
+{
+virConnectPtr conn;
+
+VIR_DOMAIN_DEBUG(domain, "seconds=%d, flags=0x%x", seconds, flags);
+
+virResetLastError();
+
+virCheckDomainReturn(domain, -1);
+conn = domain->conn;
+
+virCheckReadOnlyGoto(conn->flags, error);
+
+if (conn->driver->domainStartDirtyRateCalc) {
+int ret;
+ret = conn->driver->domainStartDirtyRateCalc(domain, seconds, flags);
+if (ret < 0)
+goto error;
+return ret;
+}
+
+virReportUnsupportedError();
+
+ error:
+virDispatchError(conn);
+return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index d851333eb0..51a3d7265a 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -884,4 +884,9 @@ LIBVIRT_7.1.0 {
 virDomainGetMessages;
 } LIBVIRT_6.10.0;
 
+LIBVIRT_7.2.0 {
+global:
+virDomainStartDirtyRateCalc;
+} LIBVIRT_7.1.0;
+
 #  define new API here using predicted next version number 
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 31868269b1..494f4b6dc5 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -8571,6 +8571,7 @@ static virHypervisorDriver hypervisor_driver = {
 .domainAuthorizedSSHKeysGet = remoteDomainAuthorizedSSHKeysGet, /* 6.10.0 
*/
 .domainAuthorizedSSHKeysSet = remoteDomainAuthorizedSSHKeysSet, /* 6.10.0 
*/
 .domainGetMessages = remoteDomainGetMessages, /* 7.1.0 */
+.domainStartDirtyRateCalc = remoteDomainStartDirtyRateCalc, /* 7.2.0 */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index d3724bc305..7fdc65f029 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3811,6 +3811,12 @@ struct remote_domain_get_messages_ret {
 remote_nonnull_string msgs;
 };
 
+struct remote_domain_start_dirty_rate_calc_args {
+remote_nonnull_domain dom;
+int seconds;
+unsigned int flags;
+};
+
 
 /*- Protocol. -*/
 
@@ -6733,5 +6739,11 @@ enum remote_procedure {
  * @generate: none
  * @acl: domain:read
  */
-REMOTE_PROC_DOMAIN_GET_MESSAGES = 426
+REMOTE

[PATCH v7 6/7] migration/dirtyrate: Extend dirtyrate statistics for domGetStats

2021-03-16 Thread Hao Wang
Extend dirtyrate statistics for domGetStats to display the information
of a domain's memory dirty rate produced by domainStartDirtyRateCalc.

Signed-off-by: Hao Wang 
---
 include/libvirt/libvirt-domain.h |  1 +
 src/libvirt-domain.c | 15 ++
 src/qemu/qemu_driver.c   | 51 
 3 files changed, 67 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index b05bb94131..03c119fe26 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -2185,6 +2185,7 @@ typedef enum {
 VIR_DOMAIN_STATS_PERF = (1 << 6), /* return domain perf event info */
 VIR_DOMAIN_STATS_IOTHREAD = (1 << 7), /* return iothread poll info */
 VIR_DOMAIN_STATS_MEMORY = (1 << 8), /* return domain memory info */
+VIR_DOMAIN_STATS_DIRTYRATE = (1 << 9), /* return domain dirty rate info */
 } virDomainStatsTypes;
 
 typedef enum {
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 91001fc4ed..83ff7df9fe 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -11887,6 +11887,21 @@ virConnectGetDomainCapabilities(virConnectPtr conn,
  *   bytes consumed by @vcpus that passing through all
  *   memory controllers, either local or remote controller.
  *
+ * VIR_DOMAIN_STATS_DIRTYRATE:
+ * Return memory dirty rate information. The typed parameter keys are in
+ * this format:
+ *
+ * "dirtyrate.calc_status" - the status of last memory dirty rate 
calculation,
+ *   returned as int from virDomainDirtyRateStatus
+ *   enum.
+ * "dirtyrate.calc_start_time" - the start time of last memory dirty rate
+ *   calculation as long long.
+ * "dirtyrate.calc_period" - the period of last memory dirty rate 
calculation
+ *   as int.
+ * "dirtyrate.megabytes_per_second" - the calculated memory dirty rate in
+ *MiB/s as long long. It is produced
+ *only if the calc_status is measured.
+ *
  * Note that entire stats groups or individual stat fields may be missing from
  * the output in case they are not supported by the given hypervisor, are not
  * applicable for the current state of the guest domain, or their retrieval
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 8836d9fd16..f3f8caab44 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -18577,6 +18577,56 @@ qemuDomainGetStatsPerf(virQEMUDriverPtr driver 
G_GNUC_UNUSED,
 return 0;
 }
 
+static int
+qemuDomainGetStatsDirtyRateMon(virQEMUDriverPtr driver,
+   virDomainObjPtr vm,
+   qemuMonitorDirtyRateInfoPtr info)
+{
+qemuDomainObjPrivatePtr priv = vm->privateData;
+int ret;
+
+qemuDomainObjEnterMonitor(driver, vm);
+ret = qemuMonitorQueryDirtyRate(priv->mon, info);
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
+
+static int
+qemuDomainGetStatsDirtyRate(virQEMUDriverPtr driver,
+   virDomainObjPtr dom,
+   virTypedParamListPtr params,
+   unsigned int privflags)
+{
+qemuMonitorDirtyRateInfo info;
+
+if (!HAVE_JOB(privflags) || !virDomainObjIsActive(dom))
+return 0;
+
+if (qemuDomainGetStatsDirtyRateMon(driver, dom, ) < 0)
+return -1;
+
+if (virTypedParamListAddInt(params, info.status,
+"dirtyrate.calc_status") < 0)
+return -1;
+
+if (virTypedParamListAddLLong(params, info.startTime,
+  "dirtyrate.calc_start_time") < 0)
+return -1;
+
+if (virTypedParamListAddInt(params, info.calcTime,
+"dirtyrate.calc_period") < 0)
+return -1;
+
+if ((info.status == VIR_DOMAIN_DIRTYRATE_MEASURED) &&
+virTypedParamListAddLLong(params, info.dirtyRate,
+  "dirtyrate.megabytes_per_second") < 0)
+return -1;
+
+return 0;
+}
+
 typedef int
 (*qemuDomainGetStatsFunc)(virQEMUDriverPtr driver,
   virDomainObjPtr dom,
@@ -18599,6 +18649,7 @@ static struct qemuDomainGetStatsWorker 
qemuDomainGetStatsWorkers[] = {
 { qemuDomainGetStatsPerf, VIR_DOMAIN_STATS_PERF, false },
 { qemuDomainGetStatsIOThread, VIR_DOMAIN_STATS_IOTHREAD, true },
 { qemuDomainGetStatsMemory, VIR_DOMAIN_STATS_MEMORY, false },
+{ qemuDomainGetStatsDirtyRate, VIR_DOMAIN_STATS_DIRTYRATE, true },
 { NULL, 0, false }
 };
 
-- 
2.23.0




[PATCH v7 7/7] migration/dirtyrate: Introduce command 'virsh domstats --dirtyrate'

2021-03-16 Thread Hao Wang
Introduce command 'virsh domstats --dirtyrate' for reporting memory
dirty rate information. The info is listed as:

Domain: 'vm0'
  dirtyrate.calc_status=2
  dirtyrate.calc_start_time=1534523
  dirtyrate.calc_period=1
  dirtyrate.megabytes_per_second=5

Signed-off-by: Hao Wang 
---
 docs/manpages/virsh.rst  | 16 ++--
 tools/virsh-domain-monitor.c |  7 +++
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index 367b4bddeb..813fb0bd60 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -2219,7 +2219,7 @@ domstats
 
domstats [--raw] [--enforce] [--backing] [--nowait] [--state]
   [--cpu-total] [--balloon] [--vcpu] [--interface]
-  [--block] [--perf] [--iothread] [--memory]
+  [--block] [--perf] [--iothread] [--memory] [--dirtyrate]
   [[--list-active] [--list-inactive]
[--list-persistent] [--list-transient] [--list-running]y
[--list-paused] [--list-shutoff] [--list-other]] | [domain ...]
@@ -2238,7 +2238,8 @@ behavior use the *--raw* flag.
 The individual statistics groups are selectable via specific flags. By
 default all supported statistics groups are returned. Supported
 statistics groups flags are: *--state*, *--cpu-total*, *--balloon*,
-*--vcpu*, *--interface*, *--block*, *--perf*, *--iothread*, *--memory*.
+*--vcpu*, *--interface*, *--block*, *--perf*, *--iothread*, *--memory*,
+*--dirtyrate*.
 
 Note that - depending on the hypervisor type and version or the domain state
 - not all of the following statistics may be returned.
@@ -2435,6 +2436,17 @@ not available for statistical purposes.
   bytes consumed by @vcpus that passing through all memory controllers, either
   local or remote controller.
 
+*--dirtyrate* returns:
+
+* ``dirtyrate.calc_status`` - the status of last memory dirty rate
+  calculation, returned as number from virDomainDirtyRateStatus enum.
+* ``dirtyrate.calc_start_time`` - the start time of last memory dirty
+  rate calculation.
+* ``dirtyrate.calc_period`` - the period of last memory dirty rate
+  calculation.
+* ``dirtyrate.megabytes_per_second`` - the calculated memory dirty
+  rate in MiB/s.
+
 
 Selecting a specific statistics groups doesn't guarantee that the
 daemon supports the selected group of stats. Flag *--enforce*
diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c
index 897339b6f9..c4d7464695 100644
--- a/tools/virsh-domain-monitor.c
+++ b/tools/virsh-domain-monitor.c
@@ -2148,6 +2148,10 @@ static const vshCmdOptDef opts_domstats[] = {
  .type = VSH_OT_BOOL,
  .help = N_("report domain memory usage"),
 },
+{.name = "dirtyrate",
+ .type = VSH_OT_BOOL,
+ .help = N_("report domain dirty rate information"),
+},
 {.name = "list-active",
  .type = VSH_OT_BOOL,
  .help = N_("list only active domains"),
@@ -2267,6 +2271,9 @@ cmdDomstats(vshControl *ctl, const vshCmd *cmd)
 if (vshCommandOptBool(cmd, "memory"))
 stats |= VIR_DOMAIN_STATS_MEMORY;
 
+if (vshCommandOptBool(cmd, "dirtyrate"))
+stats |= VIR_DOMAIN_STATS_DIRTYRATE;
+
 if (vshCommandOptBool(cmd, "list-active"))
 flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_ACTIVE;
 
-- 
2.23.0




Re: [PATCH v6 0/5] migration/dirtyrate: Introduce APIs for getting domain memory dirty rate

2021-03-04 Thread Hao Wang
Great thanks for your reviewing!
I will update 5/5 and possibly 4/5 according to expected more suggestion in the 
next version.

BR,
Hao

On 2021/3/3 19:31, Michal Privoznik wrote:
> On 2/26/21 9:35 AM, Hao Wang wrote:
>>
>> Hao Wang (5):
>>    migration/dirtyrate: Introduce virDomainStartDirtyRateCalc API
>>    migration/dirtyrate: Implement qemuDomainStartDirtyRateCalc
>>    migration/dirtyrate: Introduce domdirtyrate-calc virsh api
>>    migration/dirtyrate: Implement qemuMonitorQueryDirtyRate
>>    migration/dirtyrate: Introduce command 'virsh domstats --dirtyrate'
>>
>>   docs/manpages/virsh.rst  |  33 -
>>   include/libvirt/libvirt-domain.h |   5 ++
>>   src/driver-hypervisor.h  |   6 ++
>>   src/libvirt-domain.c |  57 +++
>>   src/libvirt_public.syms  |   5 ++
>>   src/qemu/qemu_driver.c   | 115 +++
>>   src/qemu/qemu_monitor.c  |  24 +++
>>   src/qemu/qemu_monitor.h  |  18 +
>>   src/qemu/qemu_monitor_json.c |  88 +++
>>   src/qemu/qemu_monitor_json.h |   8 +++
>>   src/remote/remote_driver.c   |   1 +
>>   src/remote/remote_protocol.x |  14 +++-
>>   src/remote_protocol-structs  |   6 ++
>>   tools/virsh-domain-monitor.c |   7 ++
>>   tools/virsh-domain.c |  63 +
>>   15 files changed, 447 insertions(+), 3 deletions(-)
>>
> 
> To patches 1-4:
> 
> Reviewed-by: Michal Privoznik 
> 
> The last one 5/5 should be split. And I'd wait for others to give opinion on 
> the enum vs string representation of calc_status. If we go with enum, then I 
> think _qemuMonitorDirtyRateInfo struct in 4/5 should be updated to reflect 
> this change.
> 
> We are almost there!
> 
> Michal
> 
> .




[PATCH v6 0/5] migration/dirtyrate: Introduce APIs for getting domain memory dirty rate

2021-02-26 Thread Hao Wang
V5 -> V6:
split DomainGetDirtyRateInfo(domdirtyrate) API into two parts:
1. DomainStartDirtyRateCalc(domdirtyrate-calc) for starting dirty rate
   calculation;
2. qemuDomainGetStatsDirtyRate(domstats --dirtyrate) for querying dirty
   rate infomation.

V4 -> V5:
squash 1/7 and bits of 5/7 and 6/7 into 2/7 in v4 (to be 1/5 in v5)
squash left of 5/7 into 4/7 in v4 (to be 3/5 in v5)
add VIR_DOMAIN_DIRTYRATE_DEFAULT flag
remove redundant error report
rename virsh api to "domdirtyrate"
use vshTablePtr for virsh api output
add description in docs/manpages/virsh.rst
other format optimize

V3 -> V4:
define flags to unsigned int
fix some compile warnings

V2 -> V3:
reorganize patchset to fix compile warning

V1 -> V2:
replace QEMU_JOB_ASYNC with QEMU_JOB_QUERY


Sometimes domain's memory dirty rate is expected by user in order to
decide whether it's proper to be migrated out or not.

We have already completed the QEMU part of the capability:
https://patchew.org/QEMU/1600237327-33618-1-git-send-email-zhengch...@huawei.com/
And this serial of patches introduce the corresponding LIBVIRT part:

1. Calculating
Introduce a new API DomainStartDirtyRateCalc and corresponding virsh api
(domdirtyrate-calc) for starting dirty rate calculation by calling qmp
'calc-dirty-rate'.

# virsh domdirtyrate-calc  [--seconds ]

2. Querying
Introduce command 'virsh domstats --dirtyrate' for reporting memory
dirty rate infomation by calling qmp 'query-dirty-rate'.

The info is listed as:
Domain: 'vm0'
  dirtyrate.calc_status=measured
  dirtyrate.calc_start_time=502814
  dirtyrate.calc_period=1
  dirtyrate.megabytes_per_second=2


Hao Wang (5):
  migration/dirtyrate: Introduce virDomainStartDirtyRateCalc API
  migration/dirtyrate: Implement qemuDomainStartDirtyRateCalc
  migration/dirtyrate: Introduce domdirtyrate-calc virsh api
  migration/dirtyrate: Implement qemuMonitorQueryDirtyRate
  migration/dirtyrate: Introduce command 'virsh domstats --dirtyrate'

 docs/manpages/virsh.rst  |  33 -
 include/libvirt/libvirt-domain.h |   5 ++
 src/driver-hypervisor.h  |   6 ++
 src/libvirt-domain.c |  57 +++
 src/libvirt_public.syms  |   5 ++
 src/qemu/qemu_driver.c   | 115 +++
 src/qemu/qemu_monitor.c  |  24 +++
 src/qemu/qemu_monitor.h  |  18 +
 src/qemu/qemu_monitor_json.c |  88 +++
 src/qemu/qemu_monitor_json.h |   8 +++
 src/remote/remote_driver.c   |   1 +
 src/remote/remote_protocol.x |  14 +++-
 src/remote_protocol-structs  |   6 ++
 tools/virsh-domain-monitor.c |   7 ++
 tools/virsh-domain.c |  63 +
 15 files changed, 447 insertions(+), 3 deletions(-)

-- 
2.23.0




[PATCH v6 4/5] migration/dirtyrate: Implement qemuMonitorQueryDirtyRate

2021-02-26 Thread Hao Wang
Implement qemuMonitorQueryDirtyRate which query domain's memory
dirty rate calling qmp "query-dirty-rate".

Signed-off-by: Hao Wang 
---
 src/qemu/qemu_monitor.c  | 12 +++
 src/qemu/qemu_monitor.h  | 14 
 src/qemu/qemu_monitor_json.c | 66 
 src/qemu/qemu_monitor_json.h |  4 +++
 4 files changed, 96 insertions(+)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 05c57f5f1d..dcc529b405 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4754,3 +4754,15 @@ qemuMonitorStartDirtyRateCalc(qemuMonitorPtr mon,
 
 return qemuMonitorJSONStartDirtyRateCalc(mon, seconds);
 }
+
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  qemuMonitorDirtyRateInfoPtr info)
+{
+VIR_DEBUG("info=%p", info);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONQueryDirtyRate(mon, info);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 94813906b4..9958657c2c 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1530,3 +1530,17 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 int
 qemuMonitorStartDirtyRateCalc(qemuMonitorPtr mon,
   int seconds);
+
+typedef struct _qemuMonitorDirtyRateInfo qemuMonitorDirtyRateInfo;
+typedef qemuMonitorDirtyRateInfo *qemuMonitorDirtyRateInfoPtr;
+
+struct _qemuMonitorDirtyRateInfo {
+char *status;   /* the status of last dirtyrate calculation */
+long long dirtyRate;/* the dirtyrate in MiB/s */
+long long startTime;/* the start time of dirtyrate calculation */
+int calcTime;   /* the period of dirtyrate calculation */
+};
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  qemuMonitorDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index e6c127ab61..409fb817bf 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9505,3 +9505,69 @@ qemuMonitorJSONStartDirtyRateCalc(qemuMonitorPtr mon,
 
 return 0;
 }
+
+
+static int
+qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
+qemuMonitorDirtyRateInfoPtr info)
+{
+const char *status;
+
+if (!(status = virJSONValueObjectGetString(data, "status"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'status' data"));
+return -1;
+}
+info->status = g_strdup(status);
+
+/* `query-dirty-rate` replies `dirty-rate` data only if the status of the 
latest
+ * calculation is `measured`.
+ */
+if (STREQ(info->status, "measured") &&
+(virJSONValueObjectGetNumberLong(data, "dirty-rate", >dirtyRate) 
< 0)) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'dirty-rate' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "start-time", >startTime) 
< 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'start-time' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberInt(data, "calc-time", >calcTime) < 
0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'calc-time' 
data"));
+return -1;
+}
+
+return 0;
+}
+
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  qemuMonitorDirtyRateInfoPtr info)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+virJSONValuePtr data = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("query-dirty-rate", NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'return' data"));
+return -1;
+}
+
+return qemuMonitorJSONExtractDirtyRateInfo(data, info);
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 32782cf681..8d4232f67b 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -715,3 +715,7 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 int
 qemuMonitorJSONStartDirtyRateCalc(qemuMonitorPtr mon,
   int seconds);
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  qemuMonitorDirtyRateInfoPtr info);
-- 
2.23.0




[PATCH v6 5/5] migration/dirtyrate: Introduce command 'virsh domstats --dirtyrate'

2021-02-26 Thread Hao Wang
Introduce command 'virsh domstats --dirtyrate' for reporting memory
dirty rate infomation. The info is listed as:

Domain: 'vm0'
  dirtyrate.calc_status=measured
  dirtyrate.calc_start_time=502814
  dirtyrate.calc_period=1
  dirtyrate.megabytes_per_second=2

Signed-off-by: Hao Wang 
---
 docs/manpages/virsh.rst  | 16 +++--
 include/libvirt/libvirt-domain.h |  1 +
 src/libvirt-domain.c | 13 
 src/qemu/qemu_driver.c   | 56 
 tools/virsh-domain-monitor.c |  7 
 5 files changed, 91 insertions(+), 2 deletions(-)

diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index 417ea444f4..b0fab3e781 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -2219,7 +2219,7 @@ domstats
 
domstats [--raw] [--enforce] [--backing] [--nowait] [--state]
   [--cpu-total] [--balloon] [--vcpu] [--interface]
-  [--block] [--perf] [--iothread] [--memory]
+  [--block] [--perf] [--iothread] [--memory] [--dirtyrate]
   [[--list-active] [--list-inactive]
[--list-persistent] [--list-transient] [--list-running]y
[--list-paused] [--list-shutoff] [--list-other]] | [domain ...]
@@ -2238,7 +2238,8 @@ behavior use the *--raw* flag.
 The individual statistics groups are selectable via specific flags. By
 default all supported statistics groups are returned. Supported
 statistics groups flags are: *--state*, *--cpu-total*, *--balloon*,
-*--vcpu*, *--interface*, *--block*, *--perf*, *--iothread*, *--memory*.
+*--vcpu*, *--interface*, *--block*, *--perf*, *--iothread*, *--memory*,
+*--dirtyrate*.
 
 Note that - depending on the hypervisor type and version or the domain state
 - not all of the following statistics may be returned.
@@ -2431,6 +2432,17 @@ not available for statistical purposes.
   bytes consumed by @vcpus that passing through all memory controllers, either
   local or remote controller.
 
+*--dirtyrate* returns:
+
+* ``dirtyrate.calc_status`` - the status of last memory dirty rate
+  calculation
+* ``dirtyrate.calc_start_time`` - the start time of last memory dirty
+  rate calculation
+* ``dirtyrate.calc_period`` - the period of last memory dirty rate
+  calculation
+* ``dirtyrate.megabytes_per_second`` - the calculated memory dirty
+  rate in MiB/s
+
 
 Selecting a specific statistics groups doesn't guarantee that the
 daemon supports the selected group of stats. Flag *--enforce*
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 7aa5ef4543..81371f54b7 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -2185,6 +2185,7 @@ typedef enum {
 VIR_DOMAIN_STATS_PERF = (1 << 6), /* return domain perf event info */
 VIR_DOMAIN_STATS_IOTHREAD = (1 << 7), /* return iothread poll info */
 VIR_DOMAIN_STATS_MEMORY = (1 << 8), /* return domain memory info */
+VIR_DOMAIN_STATS_DIRTYRATE = (1 << 9), /* return domain dirty rate info */
 } virDomainStatsTypes;
 
 typedef enum {
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index b1cc2ebbf3..0a03b2ca90 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -11883,6 +11883,19 @@ virConnectGetDomainCapabilities(virConnectPtr conn,
  *   bytes consumed by @vcpus that passing through all
  *   memory controllers, either local or remote controller.
  *
+ * VIR_DOMAIN_STATS_DIRTYRATE:
+ * Return memory dirty rate information. The typed parameter keys are in
+ * this format:
+ *
+ * "dirtyrate.calc_status" - the status of last memory dirty rate
+ *   calculation
+ * "dirtyrate.calc_start_time" - the start time of last memory dirty
+ *   rate calculation
+ * "dirtyrate.calc_period" - the period of last memory dirty rate
+ *   calculation
+ * "dirtyrate.megabytes_per_second" - the calculated memory dirty
+ *rate in MiB/s
+ *
  * Note that entire stats groups or individual stat fields may be missing from
  * the output in case they are not supported by the given hypervisor, are not
  * applicable for the current state of the guest domain, or their retrieval
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 7420937cf7..f847650e22 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -18535,6 +18535,61 @@ qemuDomainGetStatsPerf(virQEMUDriverPtr driver 
G_GNUC_UNUSED,
 return 0;
 }
 
+static int
+qemuDomainGetStatsDirtyRateMon(virQEMUDriverPtr driver,
+   virDomainObjPtr vm,
+   qemuMonitorDirtyRateInfoPtr info)
+{
+qemuDomainObjPrivatePtr priv = vm->privateData;
+int ret;
+
+qemuDomainObjEnterMonitor(driver, vm);
+ret = qemuMonitorQueryDirtyRate(priv->mon, info);
+if (qemuDomainObjExitMonitor(d

[PATCH v6 2/5] migration/dirtyrate: Implement qemuDomainStartDirtyRateCalc

2021-02-26 Thread Hao Wang
Implement qemuDomainStartDirtyRateCalc which calculates domain's memory
dirty rate calling qmp "calc-dirty-rate".

Signed-off-by: Hao Wang 
---
 src/qemu/qemu_driver.c   | 59 
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 +++
 src/qemu/qemu_monitor_json.c | 22 ++
 src/qemu/qemu_monitor_json.h |  4 +++
 5 files changed, 101 insertions(+)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b9bbdf8d48..7420937cf7 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20302,6 +20302,64 @@ qemuDomainGetMessages(virDomainPtr dom,
 }
 
 
+#define MIN_DIRTYRATE_CALC_PERIOD 1  /* supported min dirtyrate calculating 
time: 1s */
+#define MAX_DIRTYRATE_CALC_PERIOD 60 /* supported max dirtyrate calculating 
time: 60s */
+
+static int
+qemuDomainStartDirtyRateCalc(virDomainPtr dom,
+ int seconds,
+ unsigned int flags)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+virDomainObjPtr vm;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+virCheckFlags(0, -1);
+
+if (seconds < MIN_DIRTYRATE_CALC_PERIOD ||
+seconds > MAX_DIRTYRATE_CALC_PERIOD) {
+virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+   _("seconds=%d is invalid, please choose value within 
[%d, %d]."),
+   seconds,
+   MIN_DIRTYRATE_CALC_PERIOD,
+   MAX_DIRTYRATE_CALC_PERIOD);
+return -1;
+}
+
+if (!(vm = qemuDomainObjFromDomain(dom)))
+return -1;
+
+if (virDomainStartDirtyRateCalcEnsureACL(dom->conn, vm->def) < 0)
+goto cleanup;
+
+if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
+goto cleanup;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+goto endjob;
+}
+
+VIR_DEBUG("Calculate dirty rate in next %d seconds", seconds);
+
+priv = vm->privateData;
+qemuDomainObjEnterMonitor(driver, vm);
+ret = qemuMonitorStartDirtyRateCalc(priv->mon, seconds);
+
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+ endjob:
+qemuDomainObjEndJob(driver, vm);
+
+ cleanup:
+virDomainObjEndAPI();
+return ret;
+}
+
+
 static virHypervisorDriver qemuHypervisorDriver = {
 .name = QEMU_DRIVER_NAME,
 .connectURIProbe = qemuConnectURIProbe,
@@ -20544,6 +20602,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
 .domainAuthorizedSSHKeysGet = qemuDomainAuthorizedSSHKeysGet, /* 6.10.0 */
 .domainAuthorizedSSHKeysSet = qemuDomainAuthorizedSSHKeysSet, /* 6.10.0 */
 .domainGetMessages = qemuDomainGetMessages, /* 7.1.0 */
+.domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 7.2.0 */
 };
 
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 73f337a6be..05c57f5f1d 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4742,3 +4742,15 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 return qemuMonitorJSONTransactionBackup(actions, device, jobname, target,
 bitmap, syncmode);
 }
+
+
+int
+qemuMonitorStartDirtyRateCalc(qemuMonitorPtr mon,
+  int seconds)
+{
+VIR_DEBUG("seconds=%d", seconds);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONStartDirtyRateCalc(mon, seconds);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index d25c26343a..94813906b4 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1526,3 +1526,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
  const char *target,
  const char *bitmap,
  qemuMonitorTransactionBackupSyncMode syncmode);
+
+int
+qemuMonitorStartDirtyRateCalc(qemuMonitorPtr mon,
+  int seconds);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index b2034b3a40..e6c127ab61 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9483,3 +9483,25 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 return virJSONValueGetBoolean(virJSONValueObjectGet(reply, "return"),
   migratable);
 }
+
+
+int
+qemuMonitorJSONStartDirtyRateCalc(qemuMonitorPtr mon,
+  int seconds)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("calc-dirty-rate",
+   "i:calc-time", seconds,
+   NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0

[PATCH v6 1/5] migration/dirtyrate: Introduce virDomainStartDirtyRateCalc API

2021-02-26 Thread Hao Wang
Introduce virDomainStartDirtyRateCalc API for start calculation of
a domain's memory dirty rate with a specified time.

Signed-off-by: Hao Wang 
---
 include/libvirt/libvirt-domain.h |  4 +++
 src/driver-hypervisor.h  |  6 +
 src/libvirt-domain.c | 44 
 src/libvirt_public.syms  |  5 
 src/remote/remote_driver.c   |  1 +
 src/remote/remote_protocol.x | 14 +-
 src/remote_protocol-structs  |  6 +
 7 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 8011cf9fe1..7aa5ef4543 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5128,4 +5128,8 @@ int virDomainGetMessages(virDomainPtr domain,
  char ***msgs,
  unsigned int flags);
 
+int virDomainStartDirtyRateCalc(virDomainPtr domain,
+int seconds,
+unsigned int flags);
+
 #endif /* LIBVIRT_DOMAIN_H */
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index 05d7dfb5c7..2ec7b8b24a 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1405,6 +1405,11 @@ typedef int
char ***msgs,
unsigned int flags);
 
+typedef int
+(*virDrvDomainStartDirtyRateCalc)(virDomainPtr domain,
+  int seconds,
+  unsigned int flags);
+
 typedef struct _virHypervisorDriver virHypervisorDriver;
 typedef virHypervisorDriver *virHypervisorDriverPtr;
 
@@ -1671,4 +1676,5 @@ struct _virHypervisorDriver {
 virDrvDomainAuthorizedSSHKeysGet domainAuthorizedSSHKeysGet;
 virDrvDomainAuthorizedSSHKeysSet domainAuthorizedSSHKeysSet;
 virDrvDomainGetMessages domainGetMessages;
+virDrvDomainStartDirtyRateCalc domainStartDirtyRateCalc;
 };
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 4af0166872..b1cc2ebbf3 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -13154,3 +13154,47 @@ virDomainGetMessages(virDomainPtr domain,
 virDispatchError(conn);
 return -1;
 }
+
+
+/**
+ * virDomainStartDirtyRateCalc:
+ * @domain: a domain object
+ * @seconds: specified calculating time in seconds
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Calculate the current domain's memory dirty rate in next @seconds.
+ * The calculated dirty rate infomation is available by calling
+ * virConnectGetAllDomainStats.
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainStartDirtyRateCalc(virDomainPtr domain,
+int seconds,
+unsigned int flags)
+{
+virConnectPtr conn;
+
+VIR_DOMAIN_DEBUG(domain, "seconds=%d, flags=0x%x", seconds, flags);
+
+virResetLastError();
+
+virCheckDomainReturn(domain, -1);
+conn = domain->conn;
+
+virCheckReadOnlyGoto(conn->flags, error);
+
+if (conn->driver->domainStartDirtyRateCalc) {
+int ret;
+ret = conn->driver->domainStartDirtyRateCalc(domain, seconds, flags);
+if (ret < 0)
+goto error;
+return ret;
+}
+
+virReportUnsupportedError();
+
+ error:
+virDispatchError(conn);
+return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index d851333eb0..51a3d7265a 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -884,4 +884,9 @@ LIBVIRT_7.1.0 {
 virDomainGetMessages;
 } LIBVIRT_6.10.0;
 
+LIBVIRT_7.2.0 {
+global:
+virDomainStartDirtyRateCalc;
+} LIBVIRT_7.1.0;
+
 #  define new API here using predicted next version number 
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index a83cd866e7..3968472931 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -8575,6 +8575,7 @@ static virHypervisorDriver hypervisor_driver = {
 .domainAuthorizedSSHKeysGet = remoteDomainAuthorizedSSHKeysGet, /* 6.10.0 
*/
 .domainAuthorizedSSHKeysSet = remoteDomainAuthorizedSSHKeysSet, /* 6.10.0 
*/
 .domainGetMessages = remoteDomainGetMessages, /* 7.1.0 */
+.domainStartDirtyRateCalc = remoteDomainStartDirtyRateCalc, /* 7.2.0 */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index d3724bc305..7fdc65f029 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3811,6 +3811,12 @@ struct remote_domain_get_messages_ret {
 remote_nonnull_string msgs;
 };
 
+struct remote_domain_start_dirty_rate_calc_args {
+remote_nonnull_domain dom;
+int seconds;
+unsigned int flags;
+};
+
 
 /*- Protocol. -*/
 
@@ -6733,5 +6739,11 @@ enum remote_procedure {
  * @generate: none
  * @acl: domain:read
  */
-REMOTE_PROC_DOMAIN_GET_MESSAGES = 426
+REMOTE

[PATCH v6 3/5] migration/dirtyrate: Introduce domdirtyrate-calc virsh api

2021-02-26 Thread Hao Wang
Introduce domdirtyrate-calc virsh api to start calculating domain's
memory dirty rate:
# virsh domdirtyrate-calc  [--seconds ]

Signed-off-by: Hao Wang 
---
 docs/manpages/virsh.rst | 17 +++
 tools/virsh-domain.c| 63 +
 2 files changed, 80 insertions(+)

diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index 8a4328faa0..417ea444f4 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -1704,6 +1704,23 @@ states other than "ok" or "error" the command also 
prints number of
 seconds elapsed since the control interface entered its current state.
 
 
+domdirtyrate-calc
+-
+
+**Syntax:**
+
+::
+
+   domdirtyrate-calc  [--seconds ]
+
+Calculate an active domain's memory dirty rate which may be expected by
+user in order to decide whether it's proper to be migrated out or not.
+The ``seconds`` parameter can be used to calculate dirty rate in a
+specific time which allows 60s at most now and would be default to 1s
+if missing. The calculated dirty rate infomation is available by calling
+'domstats --dirtyrate'.
+
+
 domdisplay
 --
 
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index df33467646..ccb5d61a25 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -14412,6 +14412,63 @@ cmdSetUserSSHKeys(vshControl *ctl, const vshCmd *cmd)
 }
 
 
+/*
+ * "domdirtyrate" command
+ */
+static const vshCmdInfo info_domdirtyrate_calc[] = {
+{.name = "help",
+ .data = N_("Calculate a vm's memory dirty rate")
+},
+{.name = "desc",
+ .data = N_("Calculate memory dirty rate of a domain in order to decide 
whether "
+"it's proper to be migrated out or not.\n"
+"The calculated dirty rate infomation is available by calling "
+"'domstats --dirtyrate'.")
+},
+{.name = NULL}
+};
+
+static const vshCmdOptDef opts_domdirtyrate_calc[] = {
+VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+{.name = "seconds",
+ .type = VSH_OT_INT,
+ .help = N_("calculate memory dirty rate within specified seconds, "
+"the supported value range from 1 to 60, default to 1.")
+},
+{.name = NULL}
+};
+
+static bool
+cmdDomDirtyRateCalc(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom = NULL;
+int seconds;
+int rc;
+bool ret = false;
+
+if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+rc = vshCommandOptInt(ctl, cmd, "seconds", );
+if (rc < 0)
+goto cleanup;
+
+/* if no inputted seconds, default to 1s */
+if (!rc)
+seconds = 1;
+
+if (virDomainStartDirtyRateCalc(dom, seconds, 0) < 0)
+goto cleanup;
+
+vshPrint(ctl, _("Start to calculate domain's memory dirty rate 
successfully.\n"));
+ret = true;
+
+ cleanup:
+virshDomainFree(dom);
+return ret;
+}
+
+
 const vshCmdDef domManagementCmds[] = {
 {.name = "attach-device",
  .handler = cmdAttachDevice,
@@ -15051,5 +15108,11 @@ const vshCmdDef domManagementCmds[] = {
  .info = info_guestinfo,
  .flags = 0
 },
+{.name = "domdirtyrate-calc",
+ .handler = cmdDomDirtyRateCalc,
+ .opts = opts_domdirtyrate_calc,
+ .info = info_domdirtyrate_calc,
+ .flags = 0
+},
 {.name = NULL}
 };
-- 
2.23.0




Re: [PATCH v5 1/5] migration/dirtyrate: Introduce DomainGetDirtyRateInfo API

2021-02-01 Thread Hao Wang
This's quite helpful suggestions. I'll refactor the APIs following the advices.

BR,
Hao

On 2021/2/1 22:32, Michal Privoznik wrote:
> On 2/1/21 10:55 AM, Hao Wang wrote:
>> Introduce DomainGetDirtyRateInfo API to get domain's memory dirty rate
>> info which may be expected by user in order to decide whether it's proper
>> to be migrated out or not. Using flags to control the action of the API:
>>
>> If the VIR_DOMAIN_DIRTYRATE_CALC flag is set, this will calculate
>> domain's memory dirty rate within specific time.
>>
>> If the VIR_DOMAIN_DIRTYRATE_QUERY flag is set, this will query the
>> dirty rate info calculated last time.
>>
>> The VIR_DOMAIN_DIRTYRATE_DEFAULT flag is equal to both
>> VIR_DOMAIN_DIRTYRATE_CALC and VIR_DOMAIN_DIRTYRATE_QUERY.
>>
>> Signed-off-by: Hao Wang 
>> Signed-off-by: Zhou Yimin 
>> Reviewed-by: Chuan Zheng 
>> ---
>>   include/libvirt/libvirt-domain.h | 59 
>>   src/driver-hypervisor.h  |  7 
>>   src/libvirt-domain.c | 56 ++
>>   src/libvirt_public.syms  |  5 +++
>>   src/remote/remote_driver.c   |  1 +
>>   src/remote/remote_protocol.x | 21 +++-
>>   6 files changed, 148 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/libvirt/libvirt-domain.h 
>> b/include/libvirt/libvirt-domain.h
>> index de2456812c..77b46c2018 100644
>> --- a/include/libvirt/libvirt-domain.h
>> +++ b/include/libvirt/libvirt-domain.h
>> @@ -5119,4 +5119,63 @@ int virDomainAuthorizedSSHKeysSet(virDomainPtr domain,
>>     unsigned int nkeys,
>>     unsigned int flags);
>>   +/**
>> + * virDomainDirtyRateStatus:
>> + *
>> + * Details on the cause of a dirty rate calculation status.
>> + */
>> +typedef enum {
>> +    VIR_DOMAIN_DIRTYRATE_UNSTARTED = 0, /* the dirtyrate calculation has
>> +   not been started */
>> +    VIR_DOMAIN_DIRTYRATE_MEASURING = 1, /* the dirtyrate calculation is
>> +   measuring */
>> +    VIR_DOMAIN_DIRTYRATE_MEASURED  = 2, /* the dirtyrate calculation is
>> +   completed */
>> +
>> +# ifdef VIR_ENUM_SENTINELS
>> +    VIR_DOMAIN_DIRTYRATE_LAST
>> +# endif
>> +} virDomainDirtyRateStatus;
>> +
>> +/**
>> + * virDomainDirtyRateInfo:
>> + *
>> + * a virDomainDirtyRateInfo is a structure filled by virDomainGetDirtyRate()
>> + * and extracting dirty rate infomation for a given active Domain.
>> + */
>> +
>> +typedef struct _virDomainDirtyRateInfo virDomainDirtyRateInfo;
>> +struct _virDomainDirtyRateInfo {
>> +    int status; /* the status of dirtyrate calculation, one of
>> +   virDomainDirtyRateStatus */
>> +    long long dirtyRate;    /* the dirtyrate in MB/s */
> 
> I guess you meant MiB/s.
> 
>> +    long long startTime;    /* the start time of dirtyrate calculation */
>> +    int calcTime;   /* the period of dirtyrate calculation */
>> +};
> 
> Do we need to expose this as a struct? IIRC, in review of v4 Peter was 
> suggesting this to be exposed as a new set of virTypedParameter under 
> virDomainListGetStats() and virConnectGetAllDomainStats().
> 
> Problem with structures is that once they are released, we can not ever 
> change them (the best we can do is update comments), we can not even change 
> order of members, because might break how structure is organized in memory 
> (compiler might put padding at different place than originally) and thus we 
> would break ABI. Therefore, if we ever need to report one member more, we 
> can't. Well, various projects approach this differently. Some put intentional 
> padding at the end of structure to reserve extra bytes for future use. That's 
> ugly and not scalable.
> 
> What we invented for this purpose are so called typed parameters: basically 
> an array of  tuples. Users can then iterate over returned 
> array and look for items interesting to them. For instance:
> 
> virsh domstats fedora
> Domain: 'fedora'
>   state.state=1
>   state.reason=1
>   cpu.time=77689980240
>   cpu.user=7
>   cpu.system=7449000
>   cpu.cache.monitor.count=0
>   ...
> 
>> +
>> +/**
>> + * virDomainDirtyRateInfoPtr:
>> + *
>> + * a virDomainDirtyRateInfoPtr is a pointer to a virDomainDirtyRateInfo 
>> structure.
>> + */
>> +
>> +typedef virDomainDirtyRateInfo *v

Re: [PATCH v5 1/5] migration/dirtyrate: Introduce DomainGetDirtyRateInfo API

2021-02-01 Thread Hao Wang
Thanks for reviewing my patchset.

Actually I remember that I have passed all tests in my env before uploading. 
However, I doubel-check the results after receving
Daniel's reply, and found that 'check-remote-protocol'does not lie in my test 
list for the reason that dwarves is missing in my env.
After installing dwarves, I got same test error with Daniel.

Hao

On 2021/2/1 21:24, Michal Privoznik wrote:
> On 2/1/21 1:11 PM, Daniel Henrique Barboza wrote:
>> This patch is making the 'check-remote-protocol' test error out in
>> my env:
>>
> 
> Indeed, any change to remote_protocol.x has to be coupled with change to 
> src/remote_protocol-structs. The idea for this test is that we take compiled 
> version of our RPC and use pdwtags to "decompile" it. Then, the output 
> generated by pwdtags is compared against well known output stored in git 
> (src/remote_protocol-structs). The idea is that we will catch incompatible 
> changes made by rpcgen/compiler/developer. BTW, that is the reasoning behind 
> Dan's patch:
> 
> 
> commit e603efb6ec5d1a2295adfda934e79f022bb7bb0e
> Author: Daniel P. Berrangé 
> AuthorDate: Mon Jan 25 18:13:57 2021 +
> Commit: Daniel P. Berrangé 
> CommitDate: Tue Jan 26 12:33:31 2021 +
> 
>     gitlab: force dwarf4 format for debuginfo in Fedora rawhide
> 
>     Fedora 34 rawhide has pulled in a new GCC 11 build which now
>     defaults to dwarf5 format. This format is not compatible with
>     the pdwtags program used in our test suite to validate the
>     RPC files.
> 
>     We have no need for debuginfo in CI except for pdwtags,
>     so the simplest short term fix is to force the older dwarf
>     version in the hope that a fixed dwarves release will
>     arrive before Fedora 34 is released, or GCC 11 becomes more
>     widespread. Eventually we might need to figure out a way to
>     probe for compatibility but for now, we'll hope that any
>     distro with GCC 11 will be able to have a fixed dwarves too.
> 
>     https://bugzilla.redhat.com/show_bug.cgi?id=1919965
>     Reviewed-by: Erik Skultety 
>     Signed-off-by: Daniel P. Berrangé 
> 
> 
> In this case, it's developer's fault for not updating remote_protocol-structs 
> to contain additions made to remote_protocol.x.
> 
> Anyway, I don't think we will need new RPC anyway. Let me comment to the 
> patch itself.
> 
> Michal
> 
> .




[PATCH v5 1/5] migration/dirtyrate: Introduce DomainGetDirtyRateInfo API

2021-02-01 Thread Hao Wang
Introduce DomainGetDirtyRateInfo API to get domain's memory dirty rate
info which may be expected by user in order to decide whether it's proper
to be migrated out or not. Using flags to control the action of the API:

If the VIR_DOMAIN_DIRTYRATE_CALC flag is set, this will calculate
domain's memory dirty rate within specific time.

If the VIR_DOMAIN_DIRTYRATE_QUERY flag is set, this will query the
dirty rate info calculated last time.

The VIR_DOMAIN_DIRTYRATE_DEFAULT flag is equal to both
VIR_DOMAIN_DIRTYRATE_CALC and VIR_DOMAIN_DIRTYRATE_QUERY.

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 59 
 src/driver-hypervisor.h  |  7 
 src/libvirt-domain.c | 56 ++
 src/libvirt_public.syms  |  5 +++
 src/remote/remote_driver.c   |  1 +
 src/remote/remote_protocol.x | 21 +++-
 6 files changed, 148 insertions(+), 1 deletion(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index de2456812c..77b46c2018 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5119,4 +5119,63 @@ int virDomainAuthorizedSSHKeysSet(virDomainPtr domain,
   unsigned int nkeys,
   unsigned int flags);
 
+/**
+ * virDomainDirtyRateStatus:
+ *
+ * Details on the cause of a dirty rate calculation status.
+ */
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_UNSTARTED = 0, /* the dirtyrate calculation has
+   not been started */
+VIR_DOMAIN_DIRTYRATE_MEASURING = 1, /* the dirtyrate calculation is
+   measuring */
+VIR_DOMAIN_DIRTYRATE_MEASURED  = 2, /* the dirtyrate calculation is
+   completed */
+
+# ifdef VIR_ENUM_SENTINELS
+VIR_DOMAIN_DIRTYRATE_LAST
+# endif
+} virDomainDirtyRateStatus;
+
+/**
+ * virDomainDirtyRateInfo:
+ *
+ * a virDomainDirtyRateInfo is a structure filled by virDomainGetDirtyRate()
+ * and extracting dirty rate infomation for a given active Domain.
+ */
+
+typedef struct _virDomainDirtyRateInfo virDomainDirtyRateInfo;
+struct _virDomainDirtyRateInfo {
+int status; /* the status of dirtyrate calculation, one of
+   virDomainDirtyRateStatus */
+long long dirtyRate;/* the dirtyrate in MB/s */
+long long startTime;/* the start time of dirtyrate calculation */
+int calcTime;   /* the period of dirtyrate calculation */
+};
+
+/**
+ * virDomainDirtyRateInfoPtr:
+ *
+ * a virDomainDirtyRateInfoPtr is a pointer to a virDomainDirtyRateInfo 
structure.
+ */
+
+typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
+
+/**
+ * virDomainDirtyRateFlags:
+ *
+ * Details on the flags used by getdirtyrate api.
+ */
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_DEFAULT = 0,  /* default domdirtyrate behavior:
+  calculate and query */
+VIR_DOMAIN_DIRTYRATE_CALC= 1 << 0, /* calculate domain's dirtyrate */
+VIR_DOMAIN_DIRTYRATE_QUERY   = 1 << 1, /* query domain's dirtyrate */
+} virDomainDirtyRateFlags;
+
+int virDomainGetDirtyRateInfo(virDomainPtr domain,
+  virDomainDirtyRateInfoPtr info,
+  int sec,
+  unsigned int flags);
+
 #endif /* LIBVIRT_DOMAIN_H */
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index 9e8fe89921..5ad681997b 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1400,6 +1400,12 @@ typedef int
 unsigned int nkeys,
 unsigned int flags);
 
+typedef int
+(*virDrvDomainGetDirtyRateInfo)(virDomainPtr domain,
+virDomainDirtyRateInfoPtr info,
+int sec,
+unsigned int flags);
+
 typedef struct _virHypervisorDriver virHypervisorDriver;
 typedef virHypervisorDriver *virHypervisorDriverPtr;
 
@@ -1665,4 +1671,5 @@ struct _virHypervisorDriver {
 virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc;
 virDrvDomainAuthorizedSSHKeysGet domainAuthorizedSSHKeysGet;
 virDrvDomainAuthorizedSSHKeysSet domainAuthorizedSSHKeysSet;
+virDrvDomainGetDirtyRateInfo domainGetDirtyRateInfo;
 };
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index c9f8ffdb56..777028c499 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -13102,3 +13102,59 @@ virDomainAuthorizedSSHKeysSet(virDomainPtr domain,
 virDispatchError(conn);
 return -1;
 }
+
+
+/**
+ * virDomainGetDirtyRateInfo:
+ * @domain: a domain object
+ * @info: pointer to current domain's memory dirty rate info
+ * @sec: show dirty rate within specified seconds
+ * @flags: extra f

[PATCH v5 0/5] migration/dirtyrate: Introduce APIs for getting domain memory dirty rate

2021-02-01 Thread Hao Wang
V4 -> V5:
squash 1/7 and bits of 5/7 and 6/7 into 2/7 in v4 (to be 1/5 in v5)
squash left of 5/7 into 4/7 in v4 (to be 3/5 in v5)
add VIR_DOMAIN_DIRTYRATE_DEFAULT flag
remove redundant error report
rename virsh api to "domdirtyrate"
use vshTablePtr for virsh api output
add description in docs/manpages/virsh.rst
other format optimize
 
V3 -> V4:
define flags to unsigned int
fix some compile warnings

V2 -> V3:
reorganize patchset to fix compile warning

V1 -> V2:
replace QEMU_JOB_ASYNC with QEMU_JOB_QUERY


Sometimes domain's memory dirty rate is expected by user in order to
decide whether it's proper to be migrated out or not.

We have already completed the QEMU part of the capability:
https://patchew.org/QEMU/1600237327-33618-1-git-send-email-zhengch...@huawei.com/
And this serial of patches introduce the corresponding LIBVIRT part --
DomainGetDirtyRateInfo API and corresponding virsh api -- "domdirtyrate".


instructions:
bash# virsh domdirtyrate --help
  NAME
domdirtyrate - Get a vm's memory dirty rate

  SYNOPSIS
domdirtyrate  [--seconds ] [--calculate] [--query]

  DESCRIPTION
Get memory dirty rate of a domain in order to decide whether it's proper to 
be migrated out or not.

  OPTIONS
[--domain]   domain name, id or uuid
--seconds   calculate memory dirty rate within specified seconds, 
the supported value range is [1, 60], default to 1s.
--calculate  calculate dirty rate only, can be used together with 
--query, either or both is expected, otherwise would default to both.
--query  query dirty rate only, can be used together with 
--calculate, either or both is expected, otherwise would default to both.

example:
bash# virsh domdirtyrate vm0 --calculate --query --seconds 1
 Item  Value
-
 Status:   measured
 Start time:   51585
 Calculate time:   1 s
 Dirty rate:   18 MB/s


Hao Wang (5):
  migration/dirtyrate: Introduce DomainGetDirtyRateInfo API
  migration/dirtyrate: Implement qemuDomainCalculateDirtyRate
  migration/dirtyrate: Implement qemuDomainQueryDirtyRate
  migration/dirtyrate: Implement qemuDomainGetDirtyRateInfo
  migration/dirtyrate: Introduce domdirtyrate virsh api

 docs/manpages/virsh.rst  |  17 +
 include/libvirt/libvirt-domain.h |  59 ++
 src/driver-hypervisor.h  |   7 ++
 src/libvirt-domain.c |  56 ++
 src/libvirt_public.syms  |   5 ++
 src/qemu/qemu_driver.c   |  67 
 src/qemu/qemu_migration.c|  48 
 src/qemu/qemu_migration.h|  10 +++
 src/qemu/qemu_monitor.c  |  24 ++
 src/qemu/qemu_monitor.h  |   8 ++
 src/qemu/qemu_monitor_json.c |  99 
 src/qemu/qemu_monitor_json.h |   8 ++
 src/remote/remote_driver.c   |   1 +
 src/remote/remote_protocol.x |  21 -
 tools/virsh-domain.c | 127 +++
 15 files changed, 556 insertions(+), 1 deletion(-)

-- 
2.23.0




[PATCH v5 5/5] migration/dirtyrate: Introduce domdirtyrate virsh api

2021-02-01 Thread Hao Wang
The new virsh command are:
domdirtyrate  [--calculate] [--query] [--seconds ]

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 docs/manpages/virsh.rst |  17 ++
 tools/virsh-domain.c| 127 
 2 files changed, 144 insertions(+)

diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index e3afa48f7b..c7cff8a647 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -1704,6 +1704,23 @@ states other than "ok" or "error" the command also 
prints number of
 seconds elapsed since the control interface entered its current state.
 
 
+domdirtyrate
+
+
+**Syntax:**
+
+::
+
+   domdirtyrate  [--calculate] [--query] [--seconds ]
+
+Calculate and/or query an active domain's memory dirty rate which may be
+expected by user in order to decide whether it's proper to be migrated out
+or not. Either or both *--calculate* and *--query* flags are expected, and
+it would be default to both if no flags is specified. And the ``seconds``
+parameter can be used to calculate dirty rate in a specific time which allows
+60s at most now and would be default to 1s if missing.
+
+
 domdisplay
 --
 
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 2bb136333f..2cdd26b3b6 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -14416,6 +14416,127 @@ cmdSetUserSSHKeys(vshControl *ctl, const vshCmd *cmd)
 }
 
 
+/*
+ * "domdirtyrate" command
+ */
+static const vshCmdInfo info_domdirtyrate[] = {
+{.name = "help",
+ .data = N_("Get a vm's memory dirty rate")
+},
+{.name = "desc",
+ .data = N_("Get memory dirty rate of a domain in order to decide"
+" whether it's proper to be migrated out or not.")
+},
+{.name = NULL}
+};
+
+static const vshCmdOptDef opts_domdirtyrate[] = {
+VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+{.name = "seconds",
+ .type = VSH_OT_INT,
+ .help = N_("calculate memory dirty rate within specified seconds,"
+" the supported value range is [1, 60], default to 1s.")
+},
+{.name = "calculate",
+ .type = VSH_OT_BOOL,
+ .help = N_("calculate dirty rate only, can be used together with --query,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = "query",
+ .type = VSH_OT_BOOL,
+ .help = N_("query dirty rate only, can be used together with --calculate,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = NULL}
+};
+
+static bool
+cmdDomDirtyRateInfo(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom = NULL;
+virDomainDirtyRateInfo info;
+const char *status = NULL;
+unsigned int flags = VIR_DOMAIN_DIRTYRATE_DEFAULT;
+int sec;
+int rc;
+vshTablePtr table = NULL;
+g_autofree char *startTimeStr = NULL;
+g_autofree char *calcTimeStr = NULL;
+g_autofree char *dirtyRateStr = NULL;
+bool ret = false;
+bool calc = vshCommandOptBool(cmd, "calculate");
+bool query = vshCommandOptBool(cmd, "query");
+
+if (calc)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC;
+
+if (query)
+flags |= VIR_DOMAIN_DIRTYRATE_QUERY;
+
+if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+rc = vshCommandOptInt(ctl, cmd, "seconds", );
+if (rc < 0)
+goto cleanup;
+
+/* if no inputted seconds, default to 1s */
+if (!rc)
+sec = 1;
+
+if (virDomainGetDirtyRateInfo(dom, , sec, flags) < 0)
+goto cleanup;
+
+if (flags == VIR_DOMAIN_DIRTYRATE_DEFAULT ||
+flags & VIR_DOMAIN_DIRTYRATE_QUERY) {
+table = vshTableNew(_("Item"), _("Value"), NULL);
+if (!table)
+goto cleanup;
+
+switch (info.status) {
+case VIR_DOMAIN_DIRTYRATE_UNSTARTED:
+status = _("unstarted");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURING:
+status = _("measuring");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURED:
+status = _("measured");
+dirtyRateStr = g_strdup_printf("%lld MB/s", info.dirtyRate);
+break;
+default:
+status = _("unknown");
+}
+
+if (vshTableRowAppend(table, _("Status:"), status, NULL) < 0)
+goto cleanup;
+
+startTimeStr = g_strdup_printf("%lld", info.startTime);
+if (vshTableRowAppend(table, _("Start time:"), startTimeStr, NULL) < 0)
+goto cleanup;
+
+calcTimeStr = g_strdup_printf("%d s", info.calcTime);
+if (vshTableRowAppend(table, _("Calculate time:"), calcTimeSt

[PATCH v5 2/5] migration/dirtyrate: Implement qemuDomainCalculateDirtyRate

2021-02-01 Thread Hao Wang
Implement qemuDomainCalculateDirtyRate which calculates domain's memory
dirty rate calling qmp "calc-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_migration.c| 25 +
 src/qemu/qemu_migration.h|  5 +
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 22 ++
 src/qemu/qemu_monitor_json.h |  4 
 6 files changed, 72 insertions(+)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 0adfdb9351..226fe5395e 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5891,3 +5891,28 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
 virHashFree(blockinfo);
 return 0;
 }
+
+
+int
+qemuDomainCalculateDirtyRate(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ int sec)
+{
+qemuDomainObjPrivatePtr priv = vm->privateData;
+int ret;
+
+VIR_DEBUG("Calculate dirty rate during %d seconds", sec);
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return -1;
+}
+
+qemuDomainObjEnterMonitor(driver, vm);
+ret = qemuMonitorCalculateDirtyRate(priv->mon, sec);
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index fd9eb7cab0..6b1f4a8eea 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -258,3 +258,8 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
  virDomainObjPtr vm,
  qemuDomainAsyncJob asyncJob,
  qemuDomainJobInfoPtr jobInfo);
+
+int
+qemuDomainCalculateDirtyRate(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ int sec);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 09b8617097..51bc9182f3 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4713,3 +4713,15 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 return qemuMonitorJSONTransactionBackup(actions, device, jobname, target,
 bitmap, syncmode);
 }
+
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  int sec)
+{
+VIR_DEBUG("seconds=%d", sec);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONCalculateDirtyRate(mon, sec);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index a07617ec28..a11a5dc21c 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1516,3 +1516,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
  const char *target,
  const char *bitmap,
  qemuMonitorTransactionBackupSyncMode syncmode);
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  int sec);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 8a75a2734e..bb85513aa6 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9452,3 +9452,25 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 return virJSONValueGetBoolean(virJSONValueObjectGet(reply, "return"),
   migratable);
 }
+
+
+int
+qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
+  int sec)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("calc-dirty-rate",
+   "I:calc-time", sec,
+   NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+return 0;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index ba1531fee8..cc59d2c078 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -705,3 +705,7 @@ int qemuMonitorJSONSetDBusVMStateIdList(qemuMonitorPtr mon,
 int
 qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 bool *migratable);
+
+int
+qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
+  int sec);
-- 
2.23.0




[PATCH v5 4/5] migration/dirtyrate: Implement qemuDomainGetDirtyRateInfo

2021-02-01 Thread Hao Wang
Implement qemuDomainGetDirtyRateInfo: using flags to control behaviors
-- calculate and/or query dirtyrate. Default flag is both calculate
and query.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_driver.c | 67 ++
 1 file changed, 67 insertions(+)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ed840a5c8d..2b9ce1c386 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20289,6 +20289,72 @@ qemuDomainAuthorizedSSHKeysSet(virDomainPtr dom,
 }
 
 
+#define MIN_DIRTYRATE_CALCULATION_PERIOD 1  /* supported min dirtyrate calc 
time: 1s */
+#define MAX_DIRTYRATE_CALCULATION_PERIOD 60 /* supported max dirtyrate calc 
time: 60s */
+
+static int
+qemuDomainGetDirtyRateInfo(virDomainPtr dom,
+   virDomainDirtyRateInfoPtr info,
+   int sec,
+   unsigned int flags)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+virDomainObjPtr vm = NULL;
+int ret = -1;
+
+if (!(vm = qemuDomainObjFromDomain(dom)))
+return -1;
+
+if (virDomainGetDirtyRateInfoEnsureACL(dom->conn, vm->def) < 0)
+goto cleanup;
+
+if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
+goto cleanup;
+
+/* flags is default to both calculate and query */
+if (flags == VIR_DOMAIN_DIRTYRATE_DEFAULT)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC | VIR_DOMAIN_DIRTYRATE_QUERY;
+
+/* calculating */
+if (flags & VIR_DOMAIN_DIRTYRATE_CALC) {
+if (sec < MIN_DIRTYRATE_CALCULATION_PERIOD ||
+sec > MAX_DIRTYRATE_CALCULATION_PERIOD) {
+virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+   _("seconds=%d is invalid, please choose value 
within [%d, %d]."),
+   sec,
+   MIN_DIRTYRATE_CALCULATION_PERIOD,
+   MAX_DIRTYRATE_CALCULATION_PERIOD);
+goto endjob;
+}
+
+if (qemuDomainCalculateDirtyRate(driver, vm, sec) < 0)
+goto endjob;
+}
+
+/* querying */
+if (flags & VIR_DOMAIN_DIRTYRATE_QUERY) {
+/* wait sec and extra 50ms to let last calculation finish */
+if (flags & VIR_DOMAIN_DIRTYRATE_CALC) {
+virObjectUnlock(vm);
+g_usleep((sec * 1000 + 50) * 1000);
+virObjectLock(vm);
+}
+
+if (qemuDomainQueryDirtyRate(driver, vm, info) < 0)
+goto endjob;
+}
+
+ret = 0;
+
+ endjob:
+qemuDomainObjEndJob(driver, vm);
+
+ cleanup:
+virDomainObjEndAPI();
+return ret;
+}
+
+
 static virHypervisorDriver qemuHypervisorDriver = {
 .name = QEMU_DRIVER_NAME,
 .connectURIProbe = qemuConnectURIProbe,
@@ -20530,6 +20596,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
 .domainBackupGetXMLDesc = qemuDomainBackupGetXMLDesc, /* 6.0.0 */
 .domainAuthorizedSSHKeysGet = qemuDomainAuthorizedSSHKeysGet, /* 6.10.0 */
 .domainAuthorizedSSHKeysSet = qemuDomainAuthorizedSSHKeysSet, /* 6.10.0 */
+.domainGetDirtyRateInfo = qemuDomainGetDirtyRateInfo, /* 7.1.0 */
 };
 
 
-- 
2.23.0




[PATCH v5 3/5] migration/dirtyrate: Implement qemuDomainQueryDirtyRate

2021-02-01 Thread Hao Wang
Implement qemuDomainQueryDirtyRate which query domain's memory
dirty rate calling qmp "query-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_migration.c| 23 +++
 src/qemu/qemu_migration.h|  5 +++
 src/qemu/qemu_monitor.c  | 12 ++
 src/qemu/qemu_monitor.h  |  4 ++
 src/qemu/qemu_monitor_json.c | 77 
 src/qemu/qemu_monitor_json.h |  4 ++
 6 files changed, 125 insertions(+)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 226fe5395e..373896e408 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5916,3 +5916,26 @@ qemuDomainCalculateDirtyRate(virQEMUDriverPtr driver,
 
 return ret;
 }
+
+
+int
+qemuDomainQueryDirtyRate(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info)
+{
+qemuDomainObjPrivatePtr priv = vm->privateData;
+int ret;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return -1;
+}
+
+qemuDomainObjEnterMonitor(driver, vm);
+ret = qemuMonitorQueryDirtyRate(priv->mon, info);
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 6b1f4a8eea..a894c3c527 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -263,3 +263,8 @@ int
 qemuDomainCalculateDirtyRate(virQEMUDriverPtr driver,
  virDomainObjPtr vm,
  int sec);
+
+int
+qemuDomainQueryDirtyRate(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 51bc9182f3..b8c428fca8 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4725,3 +4725,15 @@ qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
 
 return qemuMonitorJSONCalculateDirtyRate(mon, sec);
 }
+
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info)
+{
+VIR_DEBUG("info=%p", info);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONQueryDirtyRate(mon, info);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index a11a5dc21c..9814fe0218 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1520,3 +1520,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 int
 qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
   int sec);
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index bb85513aa6..ba301029b0 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9474,3 +9474,80 @@ qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
 
 return 0;
 }
+
+
+VIR_ENUM_DECL(qemuDomainDirtyRateStatus);
+VIR_ENUM_IMPL(qemuDomainDirtyRateStatus,
+  VIR_DOMAIN_DIRTYRATE_LAST,
+  "unstarted",
+  "measuring",
+  "measured");
+
+static int
+qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
+virDomainDirtyRateInfoPtr info)
+{
+const char *status;
+int statusID;
+
+if (!(status = virJSONValueObjectGetString(data, "status"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'status' data"));
+return -1;
+}
+
+if ((statusID = qemuDomainDirtyRateStatusTypeFromString(status)) < 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR,
+   _("Unknown dirty rate status: %s"), status);
+return -1;
+}
+info->status = statusID;
+
+if ((info->status == VIR_DOMAIN_DIRTYRATE_MEASURED) &&
+(virJSONValueObjectGetNumberLong(data, "dirty-rate", >dirtyRate) 
< 0)) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'dirty-rate' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "start-time", >startTime) 
< 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'start-time' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberInt(data, "calc-time", >calcTime) < 
0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate r

Re: [PATCH v4 0/7] migration/dirtyrate: Introduce APIs for getting domain memory dirty rate

2021-01-25 Thread Hao Wang
Yes, and sorry for reply late. I'll try to upload v5 in a week.

BR,
Hao

On 2021/1/25 18:40, Michal Privoznik wrote:
> On 11/7/20 10:41 AM, Hao Wang wrote:
>>
> 
> Hey, any plans on v5?
> 
> Michal
> 
> .



Re: [PATCH v4 6/7] migration/dirtyrate: Implement qemuDomainGetDirtyRateInfo

2020-11-16 Thread Hao Wang
Thanks for the reviews.

On 2020/11/11 4:11, Michal Privoznik wrote:
> On 11/7/20 10:41 AM, Hao Wang wrote:
>> Implement qemuDomainGetDirtyRateInfo:
>> using flags to control behaviors -- calculate and/or query dirtyrate.
>>
>> Signed-off-by: Hao Wang 
>> Reviewed-by: Chuan Zheng 
>> ---
>>   include/libvirt/libvirt-domain.h | 11 ++
>>   src/qemu/qemu_driver.c   | 68 
>>   2 files changed, 79 insertions(+)
>>
>> diff --git a/include/libvirt/libvirt-domain.h 
>> b/include/libvirt/libvirt-domain.h
>> index 51d8685086..fc45f42dcf 100644
>> --- a/include/libvirt/libvirt-domain.h
>> +++ b/include/libvirt/libvirt-domain.h
>> @@ -5096,6 +5096,17 @@ int virDomainBackupBegin(virDomainPtr domain,
>>   char *virDomainBackupGetXMLDesc(virDomainPtr domain,
>>   unsigned int flags);
>>   +/**
>> + * virDomainDirtyRateFlags:
>> + *
>> + * Details on the flags used by getdirtyrate api.
>> + */
>> +
>> +typedef enum {
>> +    VIR_DOMAIN_DIRTYRATE_CALC = 1 << 0,  /* calculate domain's dirtyrate */
>> +    VIR_DOMAIN_DIRTYRATE_QUERY = 1 << 1, /* query domain's dirtyrate */
>> +} virDomainDirtyRateFlags;
>> +
>>   /**
>>    * virDomainDirtyRateStatus:
>>    *
> 
> Again, doesn't belong here.
> 
>> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
>> index cb56fbbfcf..93d5a23630 100644
>> --- a/src/qemu/qemu_driver.c
>> +++ b/src/qemu/qemu_driver.c
>> @@ -20121,6 +20121,73 @@ qemuDomainAgentSetResponseTimeout(virDomainPtr dom,
>>   }
>>     +#define MIN_DIRTYRATE_CALCULATION_PERIOD    1  /* supported min 
>> dirtyrate calc time: 1s */
>> +#define MAX_DIRTYRATE_CALCULATION_PERIOD    60 /* supported max dirtyrate 
>> calc time: 60s */
>> +
>> +static int
>> +qemuDomainGetDirtyRateInfo(virDomainPtr dom,
>> +   virDomainDirtyRateInfoPtr info,
>> +   long long sec,
>> +   unsigned int flags)
>> +{
>> +    virDomainObjPtr vm = NULL;
>> +    virQEMUDriverPtr driver = dom->conn->privateData;
>> +    int ret = -1;
>> +
>> +    if (!(vm = qemuDomainObjFromDomain(dom)))
>> +    return ret;
>> +
>> +    if (virDomainGetDirtyRateInfoEnsureACL(dom->conn, vm->def) < 0)
>> +    goto cleanup;
>> +
>> +    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
>> +    goto cleanup;
>> +
>> +    if (!qemuMigrationSrcIsAllowed(driver, vm, false, 0))
>> +    goto endjob;
>> +
> 
> Why is this check needed? I don't understand it, can you please explain?

It's indeed not necessary. I'll remove it.
> 
>> +    if (flags & VIR_DOMAIN_DIRTYRATE_CALC) {
>> +    if (sec < MIN_DIRTYRATE_CALCULATION_PERIOD || sec > 
>> MAX_DIRTYRATE_CALCULATION_PERIOD) {
>> +    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>> +   _("seconds=%lld is invalid, please choose value 
>> within [1, 60]."),
>> +   sec);
>> +    goto endjob;
>> +    }
>> +
>> +    if (qemuDomainCalculateDirtyRate(dom, vm, sec) < 0) {
>> +    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
>> +   _("can't calculate domain's dirty rate"));
> 
> This overwrites a more accurate error reported by 
> qemuDomainCalculateDirtyRate().
> 
>> +    goto endjob;
>> +    }
>> +    }
>> +
>> +    if (flags & VIR_DOMAIN_DIRTYRATE_QUERY) {
>> +    if (flags & VIR_DOMAIN_DIRTYRATE_CALC) {
>> +    struct timespec ts = { .tv_sec = sec, .tv_nsec = 50 * 1000 * 
>> 1000ull };
>> +
>> +    virObjectUnlock(vm);
>> +    nanosleep(, NULL);
>> +    virObjectLock(vm);
> 
> At first I was afraid, I was petrified that this waits for 50 seconds, until 
> I realized it's nanosleep(). Perhaps g_usleep(50*1000); would look better?
> 
>> +    }
>> +
>> +    if (qemuDomainQueryDirtyRate(dom, vm, info) < 0) {
>> +    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
>> +   _("can't query domain's dirty rate"));
> 
> Again, error overwrite.
> 
>> +    goto endjob;
>> +    }
>> +    }
> 
> So if no flag is specified then nothing happens? I know you handle that in 
> virsh, but I think that logic s

Re: [PATCH v4 5/7] migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo

2020-11-16 Thread Hao Wang
I'll take these reviews in my next version. Thanks again!

On 2020/11/11 4:11, Michal Privoznik wrote:
> On 11/7/20 10:41 AM, Hao Wang wrote:
>> Implement qemuMonitorJSONExtractDirtyRateInfo to deal with the return from
>> qmp "query-dirty-rate", and store them in virDomainDirtyRateInfo.
>>
>> Signed-off-by: Hao Wang 
>> Reviewed-by: Chuan Zheng 
>> ---
>>   include/libvirt/libvirt-domain.h | 17 +
>>   src/qemu/qemu_monitor_json.c | 59 ++--
>>   2 files changed, 73 insertions(+), 3 deletions(-)
>>
>> diff --git a/include/libvirt/libvirt-domain.h 
>> b/include/libvirt/libvirt-domain.h
>> index b950736b67..51d8685086 100644
>> --- a/include/libvirt/libvirt-domain.h
>> +++ b/include/libvirt/libvirt-domain.h
>> @@ -5096,6 +5096,23 @@ int virDomainBackupBegin(virDomainPtr domain,
>>   char *virDomainBackupGetXMLDesc(virDomainPtr domain,
>>   unsigned int flags);
>>   +/**
>> + * virDomainDirtyRateStatus:
>> + *
>> + * Details on the cause of a dirtyrate calculation status.
>> + */
>> +
>> +typedef enum {
>> +    VIR_DOMAIN_DIRTYRATE_UNSTARTED = 0, /* the dirtyrate calculation has 
>> not been started */
>> +    VIR_DOMAIN_DIRTYRATE_MEASURING = 1, /* the dirtyrate calculation is 
>> measuring */
>> +    VIR_DOMAIN_DIRTYRATE_MEASURED  = 2, /* the dirtyrate calculation is
>> +completed */
>> +
>> +# ifdef VIR_ENUM_SENTINELS
>> +    VIR_DOMAIN_DIRTYRATE_LAST
>> +# endif
>> +} virDomainDirtyRateStatus;
>> +
> 
> As advertised earlier, this doesn't belong into this commit really.
> 
>>   /**
>>    * virDomainDirtyRateInfo:
>>    *
>> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
>> index 1924c7229b..ca7d8d23c0 100644
>> --- a/src/qemu/qemu_monitor_json.c
>> +++ b/src/qemu/qemu_monitor_json.c
>> @@ -9659,12 +9659,61 @@ qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
>>   }
>>     +VIR_ENUM_DECL(qemuDomainDirtyRateStatus);
>> +VIR_ENUM_IMPL(qemuDomainDirtyRateStatus,
>> +  VIR_DOMAIN_DIRTYRATE_LAST,
>> +  "unstarted",
>> +  "measuring",
>> +  "measured");
>> +
>> +static int
>> +qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
>> +    virDomainDirtyRateInfoPtr info)
>> +{
>> +    const char *status;
>> +    int statusID;
>> +
>> +    if (!(status = virJSONValueObjectGetString(data, "status"))) {
>> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +   _("query-dirty-rate reply was missing 'status' 
>> data"));
>> +    return -1;
>> +    }
>> +
>> +    if ((statusID = qemuDomainDirtyRateStatusTypeFromString(status)) < 0) {
>> +    return -1;
> 
> So if qemu sends us some other string, this fails silently.
> 
>> +    }
>> +    info->status = statusID;
>> +
>> +    if ((info->status == VIR_DOMAIN_DIRTYRATE_MEASURED) &&
>> +    (virJSONValueObjectGetNumberLong(data, "dirty-rate", 
>> &(info->dirtyRate)) < 0)) {
>> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +   _("query-dirty-rate reply was missing 'dirty-rate' 
>> data"));
>> +    return -1;
>> +    }
>> +
>> +    if (virJSONValueObjectGetNumberLong(data, "start-time", 
>> &(info->startTime)) < 0) {
>> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +   _("query-dirty-rate reply was missing 'start-time' 
>> data"));
>> +    return -1;
>> +    }
>> +
>> +    if (virJSONValueObjectGetNumberLong(data, "calc-time", 
>> &(info->calcTime)) < 0) {
>> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +   _("query-dirty-rate reply was missing 'calc-time' 
>> data"));
>> +    return -1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +
>>   int
>>   qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
>>     virDomainDirtyRateInfoPtr info)
>>   {
>>   g_autoptr(virJSONValue) cmd = NULL;
>>   g_autoptr(virJSONValue) reply = NULL;
>> +    virJSONValuePtr data = NULL;
>>     if (!(cmd = qemuMonitorJSONMakeCommand("query-dirty-rate", NULL

Re: [PATCH v4 4/7] migration/dirtyrate: Implement qemuDomainQueryDirtyRate

2020-11-16 Thread Hao Wang
Thanks for these reviews too. I'll apply all of them.

On 2020/11/11 4:11, Michal Privoznik wrote:
> On 11/7/20 10:41 AM, Hao Wang wrote:
>> Implement qemuDomainQueryDirtyRate which query domain's memory
>> dirty rate calling qmp "query-dirty-rate".
>>
>> Signed-off-by: Hao Wang 
>> Signed-off-by: Zhou Yimin 
>> Reviewed-by: Chuan Zheng 
>> ---
>>   src/qemu/qemu_migration.c    | 31 +++
>>   src/qemu/qemu_migration.h    |  5 +
>>   src/qemu/qemu_monitor.c  | 12 
>>   src/qemu/qemu_monitor.h  |  4 
>>   src/qemu/qemu_monitor_json.c | 22 ++
>>   src/qemu/qemu_monitor_json.h |  4 
>>   6 files changed, 78 insertions(+)
>>
>> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
>> index 8029e24415..3d07ba3ac4 100644
>> --- a/src/qemu/qemu_migration.c
>> +++ b/src/qemu/qemu_migration.c
>> @@ -5864,3 +5864,34 @@ qemuDomainCalculateDirtyRate(virDomainPtr dom,
>>     return ret;
>>   }
>> +
>> +
>> +int
>> +qemuDomainQueryDirtyRate(virDomainPtr dom,
>> + virDomainObjPtr vm,
>> + virDomainDirtyRateInfoPtr info)
>> +{
>> +    virQEMUDriverPtr driver = dom->conn->privateData;
> 
> Again, driver is accessible from the caller, just pass it directly.
> 
>> +    qemuDomainObjPrivatePtr priv;
>> +    int ret = -1;
>> +
>> +    if (!virDomainObjIsActive(vm)) {
>> +    virReportError(VIR_ERR_OPERATION_INVALID,
>> +   "%s", _("domain is not running"));
>> +    return ret;
>> +    }
>> +
>> +    priv = vm->privateData;
>> +
>> +    qemuDomainObjEnterMonitor(driver, vm);
>> +
>> +    ret = qemuMonitorQueryDirtyRate(priv->mon, info);
>> +    if (ret < 0) {
>> +    virReportError(VIR_ERR_OPERATION_FAILED,
>> +   "%s", _("get vm's dirty rate failed."));
> 
> No, this is not correct, qemuMonitorQueryDirtyRate() will report an error if 
> something goes wrong. And with pretty accurate error message. This overwrites 
> it with more generic one.
> 
>> +    }
>> +    if (qemuDomainObjExitMonitor(driver, vm) < 0)
>> +    ret = -1;
>> +
>> +    return ret;
>> +}
>> diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
>> index 0522b375c0..8baae512b7 100644
>> --- a/src/qemu/qemu_migration.h
>> +++ b/src/qemu/qemu_migration.h
>> @@ -263,3 +263,8 @@ int
>>   qemuDomainCalculateDirtyRate(virDomainPtr dom,
>>    virDomainObjPtr vm,
>>    long long sec);
>> +
>> +int
>> +qemuDomainQueryDirtyRate(virDomainPtr dom,
>> + virDomainObjPtr vm,
>> + virDomainDirtyRateInfoPtr info);
>> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
>> index 06603b8691..2fa6879467 100644
>> --- a/src/qemu/qemu_monitor.c
>> +++ b/src/qemu/qemu_monitor.c
>> @@ -4781,3 +4781,15 @@ qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
>>     return qemuMonitorJSONCalculateDirtyRate(mon, sec);
>>   }
>> +
>> +
>> +int
>> +qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
>> +  virDomainDirtyRateInfoPtr info)
>> +{
>> +    VIR_DEBUG("info=%p", info);
>> +
>> +    QEMU_CHECK_MONITOR(mon);
>> +
>> +    return qemuMonitorJSONQueryDirtyRate(mon, info);
>> +}
>> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
>> index afb97780cf..25105c3ad9 100644
>> --- a/src/qemu/qemu_monitor.h
>> +++ b/src/qemu/qemu_monitor.h
>> @@ -1531,3 +1531,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
>>   int
>>   qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
>>     long long sec);
>> +
>> +int
>> +qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
>> +  virDomainDirtyRateInfoPtr info);
>> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
>> index 65691522fb..1924c7229b 100644
>> --- a/src/qemu/qemu_monitor_json.c
>> +++ b/src/qemu/qemu_monitor_json.c
>> @@ -9657,3 +9657,25 @@ qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
>>     return 0;
>>   }
>> +
>> +
>> +int
>> +qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
>> +  virDomainDirtyRateInfoPtr info)
>> 

Re: [PATCH v4 3/7] migration/dirtyrate: Implement qemuDomainCalculateDirtyRate

2020-11-16 Thread Hao Wang
Great thanks for these helpful suggestions. I'll introduce them into my next 
version.

On 2020/11/11 4:11, Michal Privoznik wrote:
> On 11/7/20 10:41 AM, Hao Wang wrote:
>> Implement qemuDomainCalculateDirtyRate which calculates domain's memory
>> dirty rate calling qmp "calc-dirty-rate".
>>
>> Signed-off-by: Hao Wang 
>> Signed-off-by: Zhou Yimin 
>> Reviewed-by: Chuan Zheng 
>> ---
>>   src/qemu/qemu_migration.c    | 28 
>>   src/qemu/qemu_migration.h    |  5 +
>>   src/qemu/qemu_monitor.c  | 12 
>>   src/qemu/qemu_monitor.h  |  4 
>>   src/qemu/qemu_monitor_json.c | 22 ++
>>   src/qemu/qemu_monitor_json.h |  4 
>>   6 files changed, 75 insertions(+)
>>
>> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
>> index 6f764b0c73..8029e24415 100644
>> --- a/src/qemu/qemu_migration.c
>> +++ b/src/qemu/qemu_migration.c
>> @@ -5836,3 +5836,31 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr 
>> driver,
>>   virHashFree(blockinfo);
>>   return 0;
>>   }
>> +
>> +
>> +int
>> +qemuDomainCalculateDirtyRate(virDomainPtr dom,
> 
> The caller (implemented later in the series) has pointer to the driver. Might 
> as well pass it here. Alternativelly, there is a piggy back pointer stored 
> inside @vm's private data: QEMU_DOMAIN_PRIVATE(vm)->driver
> 
>> + virDomainObjPtr vm,
>> + long long sec)
>> +{
>> +    virQEMUDriverPtr driver = dom->conn->privateData;
>> +    qemuDomainObjPrivatePtr priv;
>> +    int ret = -1;
>> +
>> +    if (!virDomainObjIsActive(vm)) {
>> +    virReportError(VIR_ERR_OPERATION_INVALID,
>> +   "%s", _("domain is not running"));
>> +    return ret;
>> +    }
>> +
>> +    priv = vm->privateData;
> 
> It's okay to initialize priv when declaring it.
> 
>> +
>> +    VIR_DEBUG("Calculate dirty rate during %lld seconds", sec);
>> +    qemuDomainObjEnterMonitor(driver, vm);
>> +
>> +    ret = qemuMonitorCalculateDirtyRate(priv->mon, sec);
>> +    if (qemuDomainObjExitMonitor(driver, vm) < 0)
>> +    ret = -1;
>> +
>> +    return ret;
>> +}
>> diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
>> index fd9eb7cab0..0522b375c0 100644
>> --- a/src/qemu/qemu_migration.h
>> +++ b/src/qemu/qemu_migration.h
>> @@ -258,3 +258,8 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
>>    virDomainObjPtr vm,
>>    qemuDomainAsyncJob asyncJob,
>>    qemuDomainJobInfoPtr jobInfo);
>> +
>> +int
>> +qemuDomainCalculateDirtyRate(virDomainPtr dom,
>> + virDomainObjPtr vm,
>> + long long sec);
>> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
>> index 5481bd99a0..06603b8691 100644
>> --- a/src/qemu/qemu_monitor.c
>> +++ b/src/qemu/qemu_monitor.c
>> @@ -4769,3 +4769,15 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
>>   return qemuMonitorJSONTransactionBackup(actions, device, jobname, 
>> target,
>>   bitmap, syncmode);
>>   }
>> +
>> +
>> +int
>> +qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
>> +  long long sec)
>> +{
>> +    VIR_DEBUG("seconds=%lld", sec);
>> +
>> +    QEMU_CHECK_MONITOR(mon);
>> +
>> +    return qemuMonitorJSONCalculateDirtyRate(mon, sec);
>> +}
>> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
>> index 54fbb41ef7..afb97780cf 100644
>> --- a/src/qemu/qemu_monitor.h
>> +++ b/src/qemu/qemu_monitor.h
>> @@ -1527,3 +1527,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
>>    const char *target,
>>    const char *bitmap,
>>    qemuMonitorTransactionBackupSyncMode 
>> syncmode);
>> +
>> +int
>> +qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
>> +  long long sec);
>> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
>> index 843a555952..65691522fb 100644
>> --- a/src/qemu/qemu_monitor_json.c
>> +++ b/src/qemu/qemu_monitor_json.c
>> @@ -9635,3 +9635,25 @@ qemuMonit

Re: [PATCH v4 2/7] migration/dirtyrate: set up framwork of domainGetDirtyRateInfo API

2020-11-16 Thread Hao Wang
Great thanks for these helpful suggestions. I'll introduce them into my next 
version.

On 2020/11/11 4:11, Michal Privoznik wrote:
> On 11/7/20 10:41 AM, Hao Wang wrote:
>> Introduce DomainGetDirtyRateInfo API for domain's memory dirty rate
>> calculation and query.
>>
>> Signed-off-by: Hao Wang 
>> Signed-off-by: Zhou Yimin 
>> Reviewed-by: Chuan Zheng 
>> ---
>>   include/libvirt/libvirt-domain.h |  5 
>>   src/driver-hypervisor.h  |  7 +
>>   src/libvirt-domain.c | 46 
>>   src/libvirt_public.syms  |  5 
>>   src/remote/remote_driver.c   |  1 +
>>   src/remote/remote_protocol.x | 21 ++-
>>   6 files changed, 84 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/libvirt/libvirt-domain.h 
>> b/include/libvirt/libvirt-domain.h
>> index 145f517068..b950736b67 100644
>> --- a/include/libvirt/libvirt-domain.h
>> +++ b/include/libvirt/libvirt-domain.h
>> @@ -5120,4 +5120,9 @@ struct _virDomainDirtyRateInfo {
>>     typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
>>   +int virDomainGetDirtyRateInfo(virDomainPtr domain,
>> +  virDomainDirtyRateInfoPtr info,
>> +  long long sec,
>> +  unsigned int flags);
>> +
>>   #endif /* LIBVIRT_DOMAIN_H */
>> diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
>> index bce023017d..a77c29de54 100644
>> --- a/src/driver-hypervisor.h
>> +++ b/src/driver-hypervisor.h
>> @@ -1387,6 +1387,12 @@ typedef char *
>>   (*virDrvDomainBackupGetXMLDesc)(virDomainPtr domain,
>>   unsigned int flags);
>>   +typedef int
>> +(*virDrvDomainGetDirtyRateInfo)(virDomainPtr domain,
>> +    virDomainDirtyRateInfoPtr info,
>> +    long long sec,
>> +    unsigned int flags);
>> +
>>   typedef struct _virHypervisorDriver virHypervisorDriver;
>>   typedef virHypervisorDriver *virHypervisorDriverPtr;
>>   @@ -1650,4 +1656,5 @@ struct _virHypervisorDriver {
>>   virDrvDomainAgentSetResponseTimeout domainAgentSetResponseTimeout;
>>   virDrvDomainBackupBegin domainBackupBegin;
>>   virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc;
>> +    virDrvDomainGetDirtyRateInfo domainGetDirtyRateInfo;
>>   };
>> diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
>> index 3c5f55176a..ce3c40edf8 100644
>> --- a/src/libvirt-domain.c
>> +++ b/src/libvirt-domain.c
>> @@ -12758,3 +12758,49 @@ virDomainBackupGetXMLDesc(virDomainPtr domain,
>>   virDispatchError(conn);
>>   return NULL;
>>   }
>> +
>> +
>> +/**
>> + * virDomainGetDirtyRateInfo:
>> + * @domain: a domain object.
>> + * @info: return value of current domain's memory dirty rate info.
>> + * @sec: show dirty rate within specified seconds.
>> + * @flags: the flags of getdirtyrate action -- calculate and/or query.
> 
> What are the flags? Which enum should I look at?
> 
>> + *
>> + * Get the current domain's memory dirty rate (in MB/s).
> 
> Can you expand on this a bit? Look at description to other APIs for 
> inspiration.
> 
>> + *
>> + * Returns 0 in case of success, -1 otherwise.
>> + */
>> +int
>> +virDomainGetDirtyRateInfo(virDomainPtr domain,
>> +  virDomainDirtyRateInfoPtr info,
>> +  long long sec,
> 
> Do we really need long long? That's more than 2.9*10^11 years. I don't think 
> any virtual machine will ever run for so long (considering that the age of 
> the universe is ~1.38*10^10 years)
> 
>> +  unsigned int flags)
>> +{
>> +    virConnectPtr conn;
>> +
>> +    VIR_DOMAIN_DEBUG(domain, "info = %p, seconds=%lld", info, sec);
> 
> @flags should also be logged.
> 
>> +
>> +    virResetLastError();
>> +
>> +    virCheckDomainReturn(domain, -1);
>> +    conn = domain->conn;
>> +
>> +    virCheckNonNullArgGoto(info, error);
>> +    virCheckReadOnlyGoto(conn->flags, error);
>> +
>> +    if (info)
>> +    memset(info, 0, sizeof(*info));
> 
> @info was checked for NULL just two lines above.
> 
>> +
>> +    if (conn->driver->domainGetDirtyRateInfo) {
>> +    if (conn->driver->domainGetDirtyRateInfo(domain, info, sec, flags) 
>> < 0)
>> +    goto error;
>> +    VIR_DOMAIN_D

Re: [PATCH v4 1/7] migration/dirtyrate: Introduce virDomainDirtyRateInfo structure

2020-11-16 Thread Hao Wang
Do you mean embed this api into domstats like "virsh domstats --dirtyrate"?

It's indeed a good idea in consideration of extensibility. I will try that in 
my next version, however,
I have no idea about where to place my secondary options (--second, --calculate 
and --query). Any suggestion?

PS: Here is my original design:
virsh getdirtyrate --domain  [--calculate] [--query]  [--seconds ]

BR,
Hao

>>
>> This should be squashed with 2/7 and bits of 5/7 and 6/7 which modify this
>> file. The key here is that public API should go into one patch, driver
>> implementation into other - it's easier to backport patches this way.
> 
> Additionally I'm not sure how likely is that the data will be extened at
> some point in the future, but using a struct is not extensible.
> 
> I'd suggest that this gets reported in the domain stats API
> 
> .
> 



Re: [PATCH v4 0/7] migration/dirtyrate: Introduce APIs for getting domain memory dirty rate

2020-11-09 Thread Hao Wang
I quite agree with you and will modify that in my next realeases. Thanks for 
your suggestion!


On 2020/11/10 9:34, Han Han wrote:
> 
> 
> On Sat, Nov 7, 2020 at 5:54 PM Hao Wang  <mailto:wanghao...@huawei.com>> wrote:
> 
> V3 -> V4:
> define flags to unsigned int
> fix some compile warnings
> 
> V2 -> V3:
> reorganize patchset to fix compile warning
> 
> V1 -> V2:
> replace QEMU_JOB_ASYNC with QEMU_JOB_QUERY
> 
> 
> Sometimes domain's memory dirty rate is expected by user in order to
> decide whether it's proper to be migrated out or not.
> 
> We have already completed the QEMU part of the capability:
> 
> https://patchew.org/QEMU/1600237327-33618-1-git-send-email-zhengch...@huawei.com/
> And this serial of patches introduce the corresponding LIBVIRT part --
> DomainGetDirtyRateInfo API and corresponding virsh api -- "getdirtyrate".
> 
> 
> instructions:
> bash# virsh getdirtyrate --help
>   NAME
>     getdirtyrate - Get a vm's memory dirty rate
> 
> I think it is better to name the virsh cmd as 'domgetdirtyrate' or 
> 'domdirtyrate' because
> the most of virsh cmds for getting the info of VM have the prefix dom.
> 




[PATCH v4 0/7] migration/dirtyrate: Introduce APIs for getting domain memory dirty rate

2020-11-07 Thread Hao Wang
V3 -> V4:
define flags to unsigned int
fix some compile warnings

V2 -> V3:
reorganize patchset to fix compile warning

V1 -> V2:
replace QEMU_JOB_ASYNC with QEMU_JOB_QUERY


Sometimes domain's memory dirty rate is expected by user in order to
decide whether it's proper to be migrated out or not.

We have already completed the QEMU part of the capability:
https://patchew.org/QEMU/1600237327-33618-1-git-send-email-zhengch...@huawei.com/
And this serial of patches introduce the corresponding LIBVIRT part --
DomainGetDirtyRateInfo API and corresponding virsh api -- "getdirtyrate".


instructions:
bash# virsh getdirtyrate --help
  NAME
getdirtyrate - Get a vm's memory dirty rate

  SYNOPSIS
getdirtyrate  [--seconds ] [--calculate] [--query]

  DESCRIPTION
Get memory dirty rate of a domain in order to decide whether it's proper to 
be migrated out or not.

  OPTIONS
[--domain]   domain name, id or uuid
--seconds   calculate memory dirty rate within specified seconds, a 
valid range of values is [1, 60], and would default to 1s.
--calculate  calculate dirty rate only, can be used together with 
--query, either or both is expected, otherwise would default to both.
--query  query dirty rate only, can be used together with 
--calculate, either or both is expected, otherwise would default to both.


example:
bash# virsh getdirtyrate --calculate --query --domain vm0 --seconds 1
status:measured
startTime: 820148
calcTime:  1 s
dirtyRate: 6 MB/s


*** BLURB HERE ***

Hao Wang (7):
  migration/dirtyrate: Introduce virDomainDirtyRateInfo structure
  migration/dirtyrate: set up framwork of domainGetDirtyRateInfo API
  migration/dirtyrate: Implement qemuDomainCalculateDirtyRate
  migration/dirtyrate: Implement qemuDomainQueryDirtyRate
  migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo
  migration/dirtyrate: Implement qemuDomainGetDirtyRateInfo
  migration/dirtyrate: Introduce getdirtyrate virsh api

 include/libvirt/libvirt-domain.h |  57 
 src/driver-hypervisor.h  |   7 ++
 src/libvirt-domain.c |  46 +
 src/libvirt_public.syms  |   5 ++
 src/qemu/qemu_driver.c   |  68 +++
 src/qemu/qemu_migration.c|  59 
 src/qemu/qemu_migration.h|  10 +++
 src/qemu/qemu_monitor.c  |  24 +++
 src/qemu/qemu_monitor.h  |   8 +++
 src/qemu/qemu_monitor_json.c |  97 ++
 src/qemu/qemu_monitor_json.h |   8 +++
 src/remote/remote_driver.c   |   1 +
 src/remote/remote_protocol.x |  21 +-
 tools/virsh-domain.c | 112 +++
 14 files changed, 522 insertions(+), 1 deletion(-)

-- 
2.23.0




[PATCH v4 6/7] migration/dirtyrate: Implement qemuDomainGetDirtyRateInfo

2020-11-07 Thread Hao Wang
Implement qemuDomainGetDirtyRateInfo:
using flags to control behaviors -- calculate and/or query dirtyrate.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 11 ++
 src/qemu/qemu_driver.c   | 68 
 2 files changed, 79 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 51d8685086..fc45f42dcf 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5096,6 +5096,17 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateFlags:
+ *
+ * Details on the flags used by getdirtyrate api.
+ */
+
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_CALC = 1 << 0,  /* calculate domain's dirtyrate */
+VIR_DOMAIN_DIRTYRATE_QUERY = 1 << 1, /* query domain's dirtyrate */
+} virDomainDirtyRateFlags;
+
 /**
  * virDomainDirtyRateStatus:
  *
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index cb56fbbfcf..93d5a23630 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20121,6 +20121,73 @@ qemuDomainAgentSetResponseTimeout(virDomainPtr dom,
 }
 
 
+#define MIN_DIRTYRATE_CALCULATION_PERIOD1  /* supported min dirtyrate calc 
time: 1s */
+#define MAX_DIRTYRATE_CALCULATION_PERIOD60 /* supported max dirtyrate calc 
time: 60s */
+
+static int
+qemuDomainGetDirtyRateInfo(virDomainPtr dom,
+   virDomainDirtyRateInfoPtr info,
+   long long sec,
+   unsigned int flags)
+{
+virDomainObjPtr vm = NULL;
+virQEMUDriverPtr driver = dom->conn->privateData;
+int ret = -1;
+
+if (!(vm = qemuDomainObjFromDomain(dom)))
+return ret;
+
+if (virDomainGetDirtyRateInfoEnsureACL(dom->conn, vm->def) < 0)
+goto cleanup;
+
+if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
+goto cleanup;
+
+if (!qemuMigrationSrcIsAllowed(driver, vm, false, 0))
+goto endjob;
+
+if (flags & VIR_DOMAIN_DIRTYRATE_CALC) {
+if (sec < MIN_DIRTYRATE_CALCULATION_PERIOD || sec > 
MAX_DIRTYRATE_CALCULATION_PERIOD) {
+virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+   _("seconds=%lld is invalid, please choose value 
within [1, 60]."),
+   sec);
+goto endjob;
+}
+
+if (qemuDomainCalculateDirtyRate(dom, vm, sec) < 0) {
+virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+   _("can't calculate domain's dirty rate"));
+goto endjob;
+}
+}
+
+if (flags & VIR_DOMAIN_DIRTYRATE_QUERY) {
+if (flags & VIR_DOMAIN_DIRTYRATE_CALC) {
+struct timespec ts = { .tv_sec = sec, .tv_nsec = 50 * 1000 * 
1000ull };
+
+virObjectUnlock(vm);
+nanosleep(, NULL);
+virObjectLock(vm);
+}
+
+if (qemuDomainQueryDirtyRate(dom, vm, info) < 0) {
+virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+   _("can't query domain's dirty rate"));
+goto endjob;
+}
+}
+
+ret = 0;
+
+ endjob:
+qemuDomainObjEndJob(driver, vm);
+
+ cleanup:
+virDomainObjEndAPI();
+return ret;
+}
+
+
 static virHypervisorDriver qemuHypervisorDriver = {
 .name = QEMU_DRIVER_NAME,
 .connectURIProbe = qemuConnectURIProbe,
@@ -20360,6 +20427,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
 .domainAgentSetResponseTimeout = qemuDomainAgentSetResponseTimeout, /* 
5.10.0 */
 .domainBackupBegin = qemuDomainBackupBegin, /* 6.0.0 */
 .domainBackupGetXMLDesc = qemuDomainBackupGetXMLDesc, /* 6.0.0 */
+.domainGetDirtyRateInfo = qemuDomainGetDirtyRateInfo, /* 6.9.0 */
 };
 
 
-- 
2.23.0




[PATCH v4 2/7] migration/dirtyrate: set up framwork of domainGetDirtyRateInfo API

2020-11-07 Thread Hao Wang
Introduce DomainGetDirtyRateInfo API for domain's memory dirty rate
calculation and query.

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h |  5 
 src/driver-hypervisor.h  |  7 +
 src/libvirt-domain.c | 46 
 src/libvirt_public.syms  |  5 
 src/remote/remote_driver.c   |  1 +
 src/remote/remote_protocol.x | 21 ++-
 6 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 145f517068..b950736b67 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5120,4 +5120,9 @@ struct _virDomainDirtyRateInfo {
 
 typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
 
+int virDomainGetDirtyRateInfo(virDomainPtr domain,
+  virDomainDirtyRateInfoPtr info,
+  long long sec,
+  unsigned int flags);
+
 #endif /* LIBVIRT_DOMAIN_H */
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index bce023017d..a77c29de54 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1387,6 +1387,12 @@ typedef char *
 (*virDrvDomainBackupGetXMLDesc)(virDomainPtr domain,
 unsigned int flags);
 
+typedef int
+(*virDrvDomainGetDirtyRateInfo)(virDomainPtr domain,
+virDomainDirtyRateInfoPtr info,
+long long sec,
+unsigned int flags);
+
 typedef struct _virHypervisorDriver virHypervisorDriver;
 typedef virHypervisorDriver *virHypervisorDriverPtr;
 
@@ -1650,4 +1656,5 @@ struct _virHypervisorDriver {
 virDrvDomainAgentSetResponseTimeout domainAgentSetResponseTimeout;
 virDrvDomainBackupBegin domainBackupBegin;
 virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc;
+virDrvDomainGetDirtyRateInfo domainGetDirtyRateInfo;
 };
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 3c5f55176a..ce3c40edf8 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -12758,3 +12758,49 @@ virDomainBackupGetXMLDesc(virDomainPtr domain,
 virDispatchError(conn);
 return NULL;
 }
+
+
+/**
+ * virDomainGetDirtyRateInfo:
+ * @domain: a domain object.
+ * @info: return value of current domain's memory dirty rate info.
+ * @sec: show dirty rate within specified seconds.
+ * @flags: the flags of getdirtyrate action -- calculate and/or query.
+ *
+ * Get the current domain's memory dirty rate (in MB/s).
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainGetDirtyRateInfo(virDomainPtr domain,
+  virDomainDirtyRateInfoPtr info,
+  long long sec,
+  unsigned int flags)
+{
+virConnectPtr conn;
+
+VIR_DOMAIN_DEBUG(domain, "info = %p, seconds=%lld", info, sec);
+
+virResetLastError();
+
+virCheckDomainReturn(domain, -1);
+conn = domain->conn;
+
+virCheckNonNullArgGoto(info, error);
+virCheckReadOnlyGoto(conn->flags, error);
+
+if (info)
+memset(info, 0, sizeof(*info));
+
+if (conn->driver->domainGetDirtyRateInfo) {
+if (conn->driver->domainGetDirtyRateInfo(domain, info, sec, flags) < 0)
+goto error;
+VIR_DOMAIN_DEBUG(domain, "info = %p, seconds=%lld", info, sec);
+return 0;
+}
+
+virReportUnsupportedError();
+ error:
+virDispatchError(conn);
+return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 539d2e3943..11864f48b1 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -873,4 +873,9 @@ LIBVIRT_6.0.0 {
 virDomainBackupGetXMLDesc;
 } LIBVIRT_5.10.0;
 
+LIBVIRT_6.9.0 {
+global:
+virDomainGetDirtyRateInfo;
+} LIBVIRT_6.0.0;
+
 #  define new API here using predicted next version number 
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 9cd2fd36ae..325968a22b 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -8458,6 +8458,7 @@ static virHypervisorDriver hypervisor_driver = {
 .domainAgentSetResponseTimeout = remoteDomainAgentSetResponseTimeout, /* 
5.10.0 */
 .domainBackupBegin = remoteDomainBackupBegin, /* 6.0.0 */
 .domainBackupGetXMLDesc = remoteDomainBackupGetXMLDesc, /* 6.0.0 */
+.domainGetDirtyRateInfo = remoteDomainGetDirtyRateInfo, /* 6.9.0 */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 5e5e781e76..5e3a75f1b9 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3779,6 +3779,19 @@ struct remote_domain_backup_get_xml_desc_ret {
 remote_nonnull_string xml;
 };
 
+struct remote_domain_get_dirty_rate_info_args {
+remote_nonnull_domain dom;
+hyper se

[PATCH v4 7/7] migration/dirtyrate: Introduce getdirtyrate virsh api

2020-11-07 Thread Hao Wang
Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 tools/virsh-domain.c | 112 +++
 1 file changed, 112 insertions(+)

diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index ef347585e8..52608e2c1b 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -14374,6 +14374,112 @@ cmdGuestInfo(vshControl *ctl, const vshCmd *cmd)
 return ret;
 }
 
+/*
+ * "querydirtyrate" command
+ */
+static const vshCmdInfo info_getdirtyrate[] = {
+{.name = "help",
+ .data = N_("Get a vm's memory dirty rate")
+},
+{.name = "desc",
+ .data = N_("Get memory dirty rate of a domain in order to decide"
+" whether it's proper to be migrated out or not.")
+},
+{.name = NULL}
+};
+
+static const vshCmdOptDef opts_getdirtyrate[] = {
+VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+{.name = "seconds",
+ .type = VSH_OT_INT,
+ .help = N_("calculate memory dirty rate within specified seconds,"
+" a valid range of values is [1, 60], and would default to 
1s.")
+},
+{.name = "calculate",
+ .type = VSH_OT_BOOL,
+ .help = N_("calculate dirty rate only, can be used together with --query,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = "query",
+ .type = VSH_OT_BOOL,
+ .help = N_("query dirty rate only, can be used together with --calculate,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = NULL}
+};
+
+static bool
+cmdGetDirtyRateInfo(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom = NULL;
+virDomainDirtyRateInfo info;
+long long sec = 0;
+const char *status = NULL;
+unsigned int flags = 0;
+int rc;
+bool ret = false;
+bool calc = vshCommandOptBool(cmd, "calculate");
+bool query = vshCommandOptBool(cmd, "query");
+
+if (calc)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC;
+if (query)
+flags |= VIR_DOMAIN_DIRTYRATE_QUERY;
+
+/* if flag option is missing, default to both --calculate and --query */
+if (!calc && !query)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC | VIR_DOMAIN_DIRTYRATE_QUERY;
+
+if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+rc = vshCommandOptLongLong(ctl, cmd, "seconds", );
+if (rc < 0)
+goto done;
+
+/* if --seconds option is missing, default to 1s */
+if (!rc)
+sec = 1;
+
+if (virDomainGetDirtyRateInfo(dom, , sec, flags) < 0) {
+vshError(ctl, "%s", _("Get memory dirty-rate failed."));
+goto done;
+}
+
+if (flags & VIR_DOMAIN_DIRTYRATE_QUERY) {
+switch (info.status) {
+case VIR_DOMAIN_DIRTYRATE_UNSTARTED:
+status = _("unstarted");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURING:
+status = _("measuring");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURED:
+status = _("measured");
+break;
+default:
+status = _("unknown");
+}
+
+vshPrint(ctl, _("status:%s\n"), status);
+vshPrint(ctl, _("start time:%lld\n"), info.startTime);
+vshPrint(ctl, _("calc time: %lld s\n"), info.calcTime);
+
+if (info.status == VIR_DOMAIN_DIRTYRATE_MEASURED)
+vshPrint(ctl, _("dirty rate:%lld MB/s\n"), info.dirtyRate);
+else
+vshPrint(ctl, _("dirty rate:the calculation is %s, please 
query results later\n"),
+ status);
+} else {
+vshPrint(ctl, _("Memory dirty rate is calculating, use --query option 
to display results.\n"));
+}
+
+ret = true;
+ done:
+virshDomainFree(dom);
+return ret;
+}
+
 const vshCmdDef domManagementCmds[] = {
 {.name = "attach-device",
  .handler = cmdAttachDevice,
@@ -15001,5 +15107,11 @@ const vshCmdDef domManagementCmds[] = {
  .info = info_guestinfo,
  .flags = 0
 },
+{.name = "getdirtyrate",
+ .handler = cmdGetDirtyRateInfo,
+ .opts = opts_getdirtyrate,
+ .info = info_getdirtyrate,
+ .flags = 0
+},
 {.name = NULL}
 };
-- 
2.23.0




[PATCH v4 5/7] migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo

2020-11-07 Thread Hao Wang
Implement qemuMonitorJSONExtractDirtyRateInfo to deal with the return from
qmp "query-dirty-rate", and store them in virDomainDirtyRateInfo.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 17 +
 src/qemu/qemu_monitor_json.c | 59 ++--
 2 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index b950736b67..51d8685086 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5096,6 +5096,23 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateStatus:
+ *
+ * Details on the cause of a dirtyrate calculation status.
+ */
+
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_UNSTARTED = 0, /* the dirtyrate calculation has not 
been started */
+VIR_DOMAIN_DIRTYRATE_MEASURING = 1, /* the dirtyrate calculation is 
measuring */
+VIR_DOMAIN_DIRTYRATE_MEASURED  = 2, /* the dirtyrate calculation is
+completed */
+
+# ifdef VIR_ENUM_SENTINELS
+VIR_DOMAIN_DIRTYRATE_LAST
+# endif
+} virDomainDirtyRateStatus;
+
 /**
  * virDomainDirtyRateInfo:
  *
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 1924c7229b..ca7d8d23c0 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9659,12 +9659,61 @@ qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
 }
 
 
+VIR_ENUM_DECL(qemuDomainDirtyRateStatus);
+VIR_ENUM_IMPL(qemuDomainDirtyRateStatus,
+  VIR_DOMAIN_DIRTYRATE_LAST,
+  "unstarted",
+  "measuring",
+  "measured");
+
+static int
+qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
+virDomainDirtyRateInfoPtr info)
+{
+const char *status;
+int statusID;
+
+if (!(status = virJSONValueObjectGetString(data, "status"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'status' data"));
+return -1;
+}
+
+if ((statusID = qemuDomainDirtyRateStatusTypeFromString(status)) < 0) {
+return -1;
+}
+info->status = statusID;
+
+if ((info->status == VIR_DOMAIN_DIRTYRATE_MEASURED) &&
+(virJSONValueObjectGetNumberLong(data, "dirty-rate", 
&(info->dirtyRate)) < 0)) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'dirty-rate' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "start-time", 
&(info->startTime)) < 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'start-time' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "calc-time", &(info->calcTime)) 
< 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'calc-time' 
data"));
+return -1;
+}
+
+return 0;
+}
+
+
 int
 qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
   virDomainDirtyRateInfoPtr info)
 {
 g_autoptr(virJSONValue) cmd = NULL;
 g_autoptr(virJSONValue) reply = NULL;
+virJSONValuePtr data = NULL;
 
 if (!(cmd = qemuMonitorJSONMakeCommand("query-dirty-rate", NULL)))
 return -1;
@@ -9675,7 +9724,11 @@ qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
 return -1;
 
-/* TODO: extract dirtyrate data from reply and store in 
virDomainDirtyRateInfoPtr */
-info->status = 0;
-return 0;
+if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'return' data"));
+return -1;
+}
+
+return qemuMonitorJSONExtractDirtyRateInfo(data, info);
 }
-- 
2.23.0




[PATCH v4 3/7] migration/dirtyrate: Implement qemuDomainCalculateDirtyRate

2020-11-07 Thread Hao Wang
Implement qemuDomainCalculateDirtyRate which calculates domain's memory
dirty rate calling qmp "calc-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_migration.c| 28 
 src/qemu/qemu_migration.h|  5 +
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 22 ++
 src/qemu/qemu_monitor_json.h |  4 
 6 files changed, 75 insertions(+)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 6f764b0c73..8029e24415 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5836,3 +5836,31 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
 virHashFree(blockinfo);
 return 0;
 }
+
+
+int
+qemuDomainCalculateDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ long long sec)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return ret;
+}
+
+priv = vm->privateData;
+
+VIR_DEBUG("Calculate dirty rate during %lld seconds", sec);
+qemuDomainObjEnterMonitor(driver, vm);
+
+ret = qemuMonitorCalculateDirtyRate(priv->mon, sec);
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index fd9eb7cab0..0522b375c0 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -258,3 +258,8 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
  virDomainObjPtr vm,
  qemuDomainAsyncJob asyncJob,
  qemuDomainJobInfoPtr jobInfo);
+
+int
+qemuDomainCalculateDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ long long sec);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 5481bd99a0..06603b8691 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4769,3 +4769,15 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 return qemuMonitorJSONTransactionBackup(actions, device, jobname, target,
 bitmap, syncmode);
 }
+
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec)
+{
+VIR_DEBUG("seconds=%lld", sec);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONCalculateDirtyRate(mon, sec);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 54fbb41ef7..afb97780cf 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1527,3 +1527,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
  const char *target,
  const char *bitmap,
  qemuMonitorTransactionBackupSyncMode syncmode);
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 843a555952..65691522fb 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9635,3 +9635,25 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 return virJSONValueGetBoolean(virJSONValueObjectGet(reply, "return"),
   migratable);
 }
+
+
+int
+qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("calc-dirty-rate",
+   "I:calc-time", (long)sec,
+   NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+return 0;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 38e23ef3c5..c9556fc19a 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -710,3 +710,7 @@ int qemuMonitorJSONSetDBusVMStateIdList(qemuMonitorPtr mon,
 int
 qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 bool *migratable);
+
+int
+qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec);
-- 
2.23.0




[PATCH v4 4/7] migration/dirtyrate: Implement qemuDomainQueryDirtyRate

2020-11-07 Thread Hao Wang
Implement qemuDomainQueryDirtyRate which query domain's memory
dirty rate calling qmp "query-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_migration.c| 31 +++
 src/qemu/qemu_migration.h|  5 +
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 22 ++
 src/qemu/qemu_monitor_json.h |  4 
 6 files changed, 78 insertions(+)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 8029e24415..3d07ba3ac4 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5864,3 +5864,34 @@ qemuDomainCalculateDirtyRate(virDomainPtr dom,
 
 return ret;
 }
+
+
+int
+qemuDomainQueryDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return ret;
+}
+
+priv = vm->privateData;
+
+qemuDomainObjEnterMonitor(driver, vm);
+
+ret = qemuMonitorQueryDirtyRate(priv->mon, info);
+if (ret < 0) {
+virReportError(VIR_ERR_OPERATION_FAILED,
+   "%s", _("get vm's dirty rate failed."));
+}
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 0522b375c0..8baae512b7 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -263,3 +263,8 @@ int
 qemuDomainCalculateDirtyRate(virDomainPtr dom,
  virDomainObjPtr vm,
  long long sec);
+
+int
+qemuDomainQueryDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 06603b8691..2fa6879467 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4781,3 +4781,15 @@ qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
 
 return qemuMonitorJSONCalculateDirtyRate(mon, sec);
 }
+
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info)
+{
+VIR_DEBUG("info=%p", info);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONQueryDirtyRate(mon, info);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index afb97780cf..25105c3ad9 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1531,3 +1531,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 int
 qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
   long long sec);
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 65691522fb..1924c7229b 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9657,3 +9657,25 @@ qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
 
 return 0;
 }
+
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("query-dirty-rate", NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+/* TODO: extract dirtyrate data from reply and store in 
virDomainDirtyRateInfoPtr */
+info->status = 0;
+return 0;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index c9556fc19a..487f2e6e58 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -714,3 +714,7 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 int
 qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
   long long sec);
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info);
-- 
2.23.0




[PATCH v4 1/7] migration/dirtyrate: Introduce virDomainDirtyRateInfo structure

2020-11-07 Thread Hao Wang
Introduce virDomainDirtyRateInfo structure used for domain's memory dirty rate 
query.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 24 
 1 file changed, 24 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index b3310729bf..145f517068 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5096,4 +5096,28 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateInfo:
+ *
+ * a virDomainDirtyRateInfo is a structure filled by virDomainGetDirtyRate() 
and
+ * extracting dirty rate infomation for a given active Domain.
+ */
+
+typedef struct _virDomainDirtyRateInfo virDomainDirtyRateInfo;
+
+struct _virDomainDirtyRateInfo {
+int status; /* the status of dirtyrate calculation */
+long long dirtyRate;/* the dirtyrate in MB/s */
+long long startTime;/* the start time of dirtyrate calculation */
+long long calcTime; /* the period of dirtyrate calculation */
+};
+
+/**
+ * virDomainDirtyRateInfoPtr:
+ *
+ * a virDomainDirtyRateInfoPtr is a pointer to a virDomainDirtyRateInfo 
structure.
+ */
+
+typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
+
 #endif /* LIBVIRT_DOMAIN_H */
-- 
2.23.0




Re: [PATCH v3 2/7] migration/dirtyrate: set up framwork of domainGetDirtyRateInfo API

2020-10-27 Thread Hao Wang
Greate thanks for your suggestions, Daniel. I'll fix that and update my 
patchset later.

BR,
Hao

On 2020/10/28 3:14, Daniel Henrique Barboza wrote:
> 
> This patch does not compile/test successfully in my env. There are
> at least 2 things going wrong here:
> 
> 



[PATCH v3 2/7] migration/dirtyrate: set up framwork of domainGetDirtyRateInfo API

2020-10-27 Thread Hao Wang
Introduce DomainGetDirtyRateInfo API for domain's memory dirty rate
calculation and query.

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h |  5 
 src/driver-hypervisor.h  |  7 +
 src/libvirt-domain.c | 46 
 src/libvirt_public.syms  |  5 
 src/qemu/qemu_driver.c   | 12 +
 src/remote/remote_driver.c   |  1 +
 src/remote/remote_protocol.x | 21 ++-
 7 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 145f517068..1c63191baa 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5120,4 +5120,9 @@ struct _virDomainDirtyRateInfo {
 
 typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
 
+int virDomainGetDirtyRateInfo(virDomainPtr domain,
+  virDomainDirtyRateInfoPtr info,
+  long long sec,
+  int flags);
+
 #endif /* LIBVIRT_DOMAIN_H */
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index bce023017d..dc2aefa910 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1387,6 +1387,12 @@ typedef char *
 (*virDrvDomainBackupGetXMLDesc)(virDomainPtr domain,
 unsigned int flags);
 
+typedef int
+(*virDrvDomainGetDirtyRateInfo)(virDomainPtr domain,
+virDomainDirtyRateInfoPtr info,
+long long sec,
+int flags);
+
 typedef struct _virHypervisorDriver virHypervisorDriver;
 typedef virHypervisorDriver *virHypervisorDriverPtr;
 
@@ -1650,4 +1656,5 @@ struct _virHypervisorDriver {
 virDrvDomainAgentSetResponseTimeout domainAgentSetResponseTimeout;
 virDrvDomainBackupBegin domainBackupBegin;
 virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc;
+virDrvDomainGetDirtyRateInfo domainGetDirtyRateInfo;
 };
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 3c5f55176a..8714c1ca93 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -12758,3 +12758,49 @@ virDomainBackupGetXMLDesc(virDomainPtr domain,
 virDispatchError(conn);
 return NULL;
 }
+
+
+/**
+ * virDomainGetDirtyRateInfo:
+ * @domain: a domain object.
+ * @info: return value of current domain's memory dirty rate info.
+ * @sec: show dirty rate within specified seconds.
+ * @flags: the flags of getdirtyrate action -- calculate and/or query.
+ *
+ * Get the current domain's memory dirty rate (in MB/s).
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainGetDirtyRateInfo(virDomainPtr domain,
+  virDomainDirtyRateInfoPtr info,
+  long long sec,
+  int flags)
+{
+virConnectPtr conn;
+
+VIR_DOMAIN_DEBUG(domain, "info = %p, seconds=%lld", info, sec);
+
+virResetLastError();
+
+virCheckDomainReturn(domain, -1);
+conn = domain->conn;
+
+virCheckNonNullArgGoto(info, error);
+virCheckReadOnlyGoto(conn->flags, error);
+
+if (info)
+memset(info, 0, sizeof(*info));
+
+if (conn->driver->domainGetDirtyRateInfo) {
+if (conn->driver->domainGetDirtyRateInfo(domain, info, sec, flags) < 0)
+goto error;
+VIR_DOMAIN_DEBUG(domain, "info = %p, seconds=%lld", info, sec);
+return 0;
+}
+
+virReportUnsupportedError();
+ error:
+virDispatchError(conn);
+return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 539d2e3943..11864f48b1 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -873,4 +873,9 @@ LIBVIRT_6.0.0 {
 virDomainBackupGetXMLDesc;
 } LIBVIRT_5.10.0;
 
+LIBVIRT_6.9.0 {
+global:
+virDomainGetDirtyRateInfo;
+} LIBVIRT_6.0.0;
+
 #  define new API here using predicted next version number 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f1191c1210..513290c934 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20123,6 +20123,17 @@ qemuDomainAgentSetResponseTimeout(virDomainPtr dom,
 }
 
 
+static int
+qemuDomainGetDirtyRateInfo(virDomainPtr dom,
+   virDomainDirtyRateInfoPtr info,
+   long long sec,
+   int flags)
+{
+/* TODO */
+return 0;
+}
+
+
 static virHypervisorDriver qemuHypervisorDriver = {
 .name = QEMU_DRIVER_NAME,
 .connectURIProbe = qemuConnectURIProbe,
@@ -20362,6 +20373,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
 .domainAgentSetResponseTimeout = qemuDomainAgentSetResponseTimeout, /* 
5.10.0 */
 .domainBackupBegin = qemuDomainBackupBegin, /* 6.0.0 */
 .domainBackupGetXMLDesc = qemuDomainBackupGetXMLDesc, /* 6.0.0 */
+.domainGetDirtyRateInfo = qemuDomainG

migration/dirtyrate: Introduce APIs for getting domain memory dirty rate

2020-10-27 Thread Hao Wang
V2 -> V3:
reorganize patchset to fix compile warning

V1 -> V2:
replace QEMU_JOB_ASYNC with QEMU_JOB_QUERY


Sometimes domain's memory dirty rate is expected by user in order to
decide whether it's proper to be migrated out or not.

We have already completed the QEMU part of the capability:
https://patchew.org/QEMU/1600237327-33618-1-git-send-email-zhengch...@huawei.com/
And this serial of patches introduce the corresponding LIBVIRT part --
DomainGetDirtyRateInfo API and corresponding virsh api -- "getdirtyrate".


instructions:
bash# virsh getdirtyrate --help
  NAME
getdirtyrate - Get a vm's memory dirty rate

  SYNOPSIS
getdirtyrate  [--seconds ] [--calculate] [--query]

  DESCRIPTION
Get memory dirty rate of a domain in order to decide whether it's proper to 
be migrated out or not.

  OPTIONS
[--domain]   domain name, id or uuid
--seconds   calculate memory dirty rate within specified seconds, a 
valid range of values is [1, 60], and would default to 1s.
--calculate  calculate dirty rate only, can be used together with 
--query, either or both is expected, otherwise would default to both.
--query  query dirty rate only, can be used together with 
--calculate, either or both is expected, otherwise would default to both.


example:
bash# virsh getdirtyrate --calculate --query --domain vm0 --seconds 1
status:measured
startTime: 820148
calcTime:  1 s
dirtyRate: 6 MB/s

Hao Wang (7):
  migration/dirtyrate: Introduce virDomainDirtyRateInfo structure
  migration/dirtyrate: set up framwork of domainGetDirtyRateInfo API
  migration/dirtyrate: Implement qemuDomainGetDirtyRateInfo
  migration/dirtyrate: Implement qemuDomainCalculateDirtyRate
  migration/dirtyrate: Implement qemuDomainCalculateDirtyRate
  migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo
  migration/dirtyrate: Introduce getdirtyrate virsh api

 include/libvirt/libvirt-domain.h |  56 
 src/driver-hypervisor.h  |   7 ++
 src/libvirt-domain.c |  46 +
 src/libvirt_public.syms  |   5 ++
 src/qemu/qemu_driver.c   |  67 ++
 src/qemu/qemu_migration.c|  59 
 src/qemu/qemu_migration.h|  10 +++
 src/qemu/qemu_monitor.c  |  24 +++
 src/qemu/qemu_monitor.h  |   8 +++
 src/qemu/qemu_monitor_json.c |  97 ++
 src/qemu/qemu_monitor_json.h |   8 +++
 src/remote/remote_driver.c   |   1 +
 src/remote/remote_protocol.x |  21 +-
 tools/virsh-domain.c | 112 +++
 14 files changed, 520 insertions(+), 1 deletion(-)

-- 
2.23.0




[PATCH v3 3/7] migration/dirtyrate: Implement qemuDomainGetDirtyRateInfo

2020-10-27 Thread Hao Wang
Implement qemuDomainGetDirtyRateInfo:
using flags to control behaviors -- calculate and/or query dirtyrate.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 11 +++
 src/qemu/qemu_driver.c   | 51 ++--
 2 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 1c63191baa..5801ca0f86 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5096,6 +5096,17 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateFlags:
+ *
+ * Details on the flags used by getdirtyrate api.
+ */
+
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_CALC = 1 << 0,  /* calculate domain's dirtyrate */
+VIR_DOMAIN_DIRTYRATE_QUERY = 1 << 1, /* query domain's dirtyrate */
+} virDomainDirtyRateFlags;
+
 /**
  * virDomainDirtyRateInfo:
  *
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 513290c934..a93f99f28a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20123,14 +20123,61 @@ qemuDomainAgentSetResponseTimeout(virDomainPtr dom,
 }
 
 
+#define MIN_DIRTYRATE_CALCULATION_PERIOD1/* 1s */
+#define MAX_DIRTYRATE_CALCULATION_PERIOD60   /* 60s */
+
 static int
 qemuDomainGetDirtyRateInfo(virDomainPtr dom,
virDomainDirtyRateInfoPtr info,
long long sec,
int flags)
 {
-/* TODO */
-return 0;
+virDomainObjPtr vm = NULL;
+virQEMUDriverPtr driver = dom->conn->privateData;
+int ret = -1;
+
+if (!(vm = qemuDomainObjFromDomain(dom)))
+return ret;
+
+if (virDomainGetDirtyRateInfoEnsureACL(dom->conn, vm->def) < 0)
+goto cleanup;
+
+if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
+goto cleanup;
+
+if (!qemuMigrationSrcIsAllowed(driver, vm, false, 0))
+goto endjob;
+
+if (flags & VIR_DOMAIN_DIRTYRATE_CALC) {
+if (sec < MIN_DIRTYRATE_CALCULATION_PERIOD || sec > 
MAX_DIRTYRATE_CALCULATION_PERIOD) {
+virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+   "seconds=%lld is invalid, please choose value 
within [1, 60].", sec);
+goto endjob;
+}
+
+/* TODO: call calc-dirty-rate for dirtyrate calculating */
+}
+
+if (flags & VIR_DOMAIN_DIRTYRATE_QUERY) {
+if (flags & VIR_DOMAIN_DIRTYRATE_CALC) {
+struct timespec ts = { .tv_sec = sec, .tv_nsec = 50 * 1000 * 
1000ull };
+
+virObjectUnlock(vm);
+nanosleep(, NULL);
+virObjectLock(vm);
+}
+
+/* TODO: call query-dirty-rate for dirtyrate querying */
+}
+
+ret = 0;
+
+ endjob:
+qemuDomainObjEndJob(driver, vm);
+
+ cleanup:
+virDomainObjEndAPI();
+return ret;
 }
 
 
-- 
2.23.0




[PATCH v3 6/7] migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo

2020-10-27 Thread Hao Wang
Implement qemuMonitorJSONExtractDirtyRateInfo to deal with the return from
qmp "query-dirty-rate", and store them in virDomainDirtyRateInfo.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 16 +
 src/qemu/qemu_monitor_json.c | 58 ++--
 2 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 5801ca0f86..ad5755cfed 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5107,6 +5107,22 @@ typedef enum {
 VIR_DOMAIN_DIRTYRATE_QUERY = 1 << 1, /* query domain's dirtyrate */
 } virDomainDirtyRateFlags;
 
+/**
+ * virDomainDirtyRateStatus:
+ *
+ * Details on the cause of a dirtyrate calculation status.
+ */
+
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_UNSTARTED = 0, /* the dirtyrate calculation has not 
been started */
+VIR_DOMAIN_DIRTYRATE_MEASURING = 1, /* the dirtyrate calculation is 
measuring */
+VIR_DOMAIN_DIRTYRATE_MEASURED  = 2, /* the dirtyrate calculation is 
completed */
+
+# ifdef VIR_ENUM_SENTINELS
+VIR_DOMAIN_DIRTYRATE_LAST
+# endif
+} virDomainDirtyRateStatus;
+
 /**
  * virDomainDirtyRateInfo:
  *
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index a0616eae2c..ca7d8d23c0 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9659,12 +9659,61 @@ qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
 }
 
 
+VIR_ENUM_DECL(qemuDomainDirtyRateStatus);
+VIR_ENUM_IMPL(qemuDomainDirtyRateStatus,
+  VIR_DOMAIN_DIRTYRATE_LAST,
+  "unstarted",
+  "measuring",
+  "measured");
+
+static int
+qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
+virDomainDirtyRateInfoPtr info)
+{
+const char *status;
+int statusID;
+
+if (!(status = virJSONValueObjectGetString(data, "status"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'status' data"));
+return -1;
+}
+
+if ((statusID = qemuDomainDirtyRateStatusTypeFromString(status)) < 0) {
+return -1;
+}
+info->status = statusID;
+
+if ((info->status == VIR_DOMAIN_DIRTYRATE_MEASURED) &&
+(virJSONValueObjectGetNumberLong(data, "dirty-rate", 
&(info->dirtyRate)) < 0)) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'dirty-rate' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "start-time", 
&(info->startTime)) < 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'start-time' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "calc-time", &(info->calcTime)) 
< 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'calc-time' 
data"));
+return -1;
+}
+
+return 0;
+}
+
+
 int
 qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
   virDomainDirtyRateInfoPtr info)
 {
 g_autoptr(virJSONValue) cmd = NULL;
 g_autoptr(virJSONValue) reply = NULL;
+virJSONValuePtr data = NULL;
 
 if (!(cmd = qemuMonitorJSONMakeCommand("query-dirty-rate", NULL)))
 return -1;
@@ -9675,6 +9724,11 @@ qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
 return -1;
 
-/* TODO: extract dirtyrate data from reply and store in 
virDomainDirtyRateInfoPtr */
-return 0;
+if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'return' data"));
+return -1;
+}
+
+return qemuMonitorJSONExtractDirtyRateInfo(data, info);
 }
-- 
2.23.0




[PATCH v3 4/7] migration/dirtyrate: Implement qemuDomainCalculateDirtyRate

2020-10-27 Thread Hao Wang
Implement qemuDomainCalculateDirtyRate which calculates domain's memory
dirty rate calling qmp "calc-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_driver.c   |  6 +-
 src/qemu/qemu_migration.c| 28 
 src/qemu/qemu_migration.h|  5 +
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 22 ++
 src/qemu/qemu_monitor_json.h |  4 
 7 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a93f99f28a..c84bd17b73 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20155,7 +20155,11 @@ qemuDomainGetDirtyRateInfo(virDomainPtr dom,
 goto endjob;
 }
 
-/* TODO: call calc-dirty-rate for dirtyrate calculating */
+if (qemuDomainCalculateDirtyRate(dom, vm, sec) < 0) {
+virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+   _("can't calculate domain's dirty rate"));
+goto endjob;
+}
 }
 
 if (flags & VIR_DOMAIN_DIRTYRATE_QUERY) {
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 6f764b0c73..8029e24415 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5836,3 +5836,31 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
 virHashFree(blockinfo);
 return 0;
 }
+
+
+int
+qemuDomainCalculateDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ long long sec)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return ret;
+}
+
+priv = vm->privateData;
+
+VIR_DEBUG("Calculate dirty rate during %lld seconds", sec);
+qemuDomainObjEnterMonitor(driver, vm);
+
+ret = qemuMonitorCalculateDirtyRate(priv->mon, sec);
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index fd9eb7cab0..0522b375c0 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -258,3 +258,8 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
  virDomainObjPtr vm,
  qemuDomainAsyncJob asyncJob,
  qemuDomainJobInfoPtr jobInfo);
+
+int
+qemuDomainCalculateDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ long long sec);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 5481bd99a0..06603b8691 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4769,3 +4769,15 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 return qemuMonitorJSONTransactionBackup(actions, device, jobname, target,
 bitmap, syncmode);
 }
+
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec)
+{
+VIR_DEBUG("seconds=%lld", sec);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONCalculateDirtyRate(mon, sec);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 54fbb41ef7..afb97780cf 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1527,3 +1527,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
  const char *target,
  const char *bitmap,
  qemuMonitorTransactionBackupSyncMode syncmode);
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 843a555952..65691522fb 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9635,3 +9635,25 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 return virJSONValueGetBoolean(virJSONValueObjectGet(reply, "return"),
   migratable);
 }
+
+
+int
+qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("calc-dirty-rate",
+   "I:calc-time", (long)sec,
+   NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+

[PATCH v3 7/7] migration/dirtyrate: Introduce getdirtyrate virsh api

2020-10-27 Thread Hao Wang
Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 tools/virsh-domain.c | 112 +++
 1 file changed, 112 insertions(+)

diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index ef347585e8..c1361ea6a9 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -14374,6 +14374,112 @@ cmdGuestInfo(vshControl *ctl, const vshCmd *cmd)
 return ret;
 }
 
+/*
+ * "querydirtyrate" command
+ */
+static const vshCmdInfo info_getdirtyrate[] = {
+{.name = "help",
+ .data = N_("Get a vm's memory dirty rate")
+},
+{.name = "desc",
+ .data = N_("Get memory dirty rate of a domain in order to decide"
+" whether it's proper to be migrated out or not.")
+},
+{.name = NULL}
+};
+
+static const vshCmdOptDef opts_getdirtyrate[] = {
+VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+{.name = "seconds",
+ .type = VSH_OT_INT,
+ .help = N_("calculate memory dirty rate within specified seconds,"
+" a valid range of values is [1, 60], and would default to 
1s.")
+},
+{.name = "calculate",
+ .type = VSH_OT_BOOL,
+ .help = N_("calculate dirty rate only, can be used together with --query,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = "query",
+ .type = VSH_OT_BOOL,
+ .help = N_("query dirty rate only, can be used together with --calculate,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = NULL}
+};
+
+static bool
+cmdGetDirtyRateInfo(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom = NULL;
+virDomainDirtyRateInfo info;
+long long sec = 0;
+const char *status = NULL;
+unsigned int flags = 0;
+int rc;
+bool ret = false;
+bool calc = vshCommandOptBool(cmd, "calculate");
+bool query = vshCommandOptBool(cmd, "query");
+
+if (calc)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC;
+if (query)
+flags |= VIR_DOMAIN_DIRTYRATE_QUERY;
+
+/* if flag option is missing, default to both --calculate and --query */
+if (!calc && !query)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC | VIR_DOMAIN_DIRTYRATE_QUERY;
+
+if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+rc = vshCommandOptLongLong(ctl, cmd, "seconds", );
+if (rc < 0)
+goto done;
+
+/* if --seconds option is missing, default to 1s */
+if (!rc)
+sec = 1;
+
+if (virDomainGetDirtyRateInfo(dom, , sec, flags) < 0) {
+vshError(ctl, "%s", _("Get memory dirty-rate failed."));
+goto done;
+}
+
+if (flags & VIR_DOMAIN_DIRTYRATE_QUERY) {
+switch (info.status) {
+case VIR_DOMAIN_DIRTYRATE_UNSTARTED:
+status = _("unstarted");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURING:
+status = _("measuring");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURED:
+status = _("measured");
+break;
+default:
+status = _("unknown");
+}
+
+vshPrint(ctl, _("status:%s\n"), status);
+vshPrint(ctl, _("start time:%lld\n"), info.startTime);
+vshPrint(ctl, _("calc time: %lld s\n"), info.calcTime);
+
+if (info.status == VIR_DOMAIN_DIRTYRATE_MEASURED)
+vshPrint(ctl, _("dirty rate:%lld MB/s\n"), info.dirtyRate);
+else
+vshPrint(ctl, _("dirty rate:the calculation is %s, please 
query results later\n"),
+ status);
+} else {
+vshPrint(ctl, _("Memory dirty rate is calculating, use --query option 
to display results.\n"));
+}
+
+ret = true;
+ done:
+virDomainFree(dom);
+return ret;
+}
+
 const vshCmdDef domManagementCmds[] = {
 {.name = "attach-device",
  .handler = cmdAttachDevice,
@@ -15001,5 +15107,11 @@ const vshCmdDef domManagementCmds[] = {
  .info = info_guestinfo,
  .flags = 0
 },
+{.name = "getdirtyrate",
+ .handler = cmdGetDirtyRateInfo,
+ .opts = opts_getdirtyrate,
+ .info = info_getdirtyrate,
+ .flags = 0
+},
 {.name = NULL}
 };
-- 
2.23.0




[PATCH v3 5/7] migration/dirtyrate: Implement qemuDomainCalculateDirtyRate

2020-10-27 Thread Hao Wang
Implement qemuDomainCalculateDirtyRate which calculates domain's memory
dirty rate calling qmp "calc-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_driver.c   |  6 +-
 src/qemu/qemu_migration.c| 31 +++
 src/qemu/qemu_migration.h|  5 +
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 21 +
 src/qemu/qemu_monitor_json.h |  4 
 7 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c84bd17b73..3d2a18a21f 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20171,7 +20171,11 @@ qemuDomainGetDirtyRateInfo(virDomainPtr dom,
 virObjectLock(vm);
 }
 
-/* TODO: call query-dirty-rate for dirtyrate querying */
+if (qemuDomainQueryDirtyRate(dom, vm, info) < 0) {
+virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+   _("can't query domain's dirty rate"));
+goto endjob;
+}
 }
 
 ret = 0;
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 8029e24415..3d07ba3ac4 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5864,3 +5864,34 @@ qemuDomainCalculateDirtyRate(virDomainPtr dom,
 
 return ret;
 }
+
+
+int
+qemuDomainQueryDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return ret;
+}
+
+priv = vm->privateData;
+
+qemuDomainObjEnterMonitor(driver, vm);
+
+ret = qemuMonitorQueryDirtyRate(priv->mon, info);
+if (ret < 0) {
+virReportError(VIR_ERR_OPERATION_FAILED,
+   "%s", _("get vm's dirty rate failed."));
+}
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 0522b375c0..8baae512b7 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -263,3 +263,8 @@ int
 qemuDomainCalculateDirtyRate(virDomainPtr dom,
  virDomainObjPtr vm,
  long long sec);
+
+int
+qemuDomainQueryDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 06603b8691..2fa6879467 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4781,3 +4781,15 @@ qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
 
 return qemuMonitorJSONCalculateDirtyRate(mon, sec);
 }
+
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info)
+{
+VIR_DEBUG("info=%p", info);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONQueryDirtyRate(mon, info);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index afb97780cf..25105c3ad9 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1531,3 +1531,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 int
 qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
   long long sec);
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 65691522fb..a0616eae2c 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9657,3 +9657,24 @@ qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
 
 return 0;
 }
+
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("query-dirty-rate", NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+/* TODO: extract dirtyrate data from reply and store in 
virDomainDirtyRateInfoPtr */
+return 0;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index c9556fc19a..487f2e6e58 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -714,3 +714,7 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 int
 qemuMonitorJSONCalculateDirtyRate(qemuMonito

[PATCH v3 1/7] migration/dirtyrate: Introduce virDomainDirtyRateInfo structure

2020-10-27 Thread Hao Wang
Introduce virDomainDirtyRateInfo structure used for domain's memory dirty rate 
query.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 24 
 1 file changed, 24 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index b3310729bf..145f517068 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5096,4 +5096,28 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateInfo:
+ *
+ * a virDomainDirtyRateInfo is a structure filled by virDomainGetDirtyRate() 
and
+ * extracting dirty rate infomation for a given active Domain.
+ */
+
+typedef struct _virDomainDirtyRateInfo virDomainDirtyRateInfo;
+
+struct _virDomainDirtyRateInfo {
+int status; /* the status of dirtyrate calculation */
+long long dirtyRate;/* the dirtyrate in MB/s */
+long long startTime;/* the start time of dirtyrate calculation */
+long long calcTime; /* the period of dirtyrate calculation */
+};
+
+/**
+ * virDomainDirtyRateInfoPtr:
+ *
+ * a virDomainDirtyRateInfoPtr is a pointer to a virDomainDirtyRateInfo 
structure.
+ */
+
+typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
+
 #endif /* LIBVIRT_DOMAIN_H */
-- 
2.23.0




Re: [PATCH v2 2/7] migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo

2020-10-26 Thread Hao Wang
Thanks for the reminding. I would fix that in my V3 patches.


在 2020/10/26 14:24, Peter Krempa 写道:
> On Sun, Oct 25, 2020 at 10:35:03 +0800, Hao Wang wrote:
>> Hi Daniel,
>>
>> For the warning in your compiling -- "error: 
>> ‘qemuMonitorJSONExtractDirtyRateInfo’ defined but not used 
>> [-Werror=unused-function]":
>>
>> " qemuMonitorJSONExtractDirtyRateInfo" would be called by function 
>> "qemuMonitorJSONQueryDirtyRate" in [PATCH 3/7].
>> So please apply all the serial of patches before your compiling. Thanks!
> 
> Note that according to our contributor guidelines [1] a patchset must
> compile cleanly and pass all testsuite after every single patch.
> 
> Please reorganize your series such that this can be achieved. Also note
> that squashing all patches into 1 is not acceptable. Patchet must be
> logically split into separable chunks.
> 
> [1] https://libvirt.org/hacking.html#preparing-patches
> 
> .
> 




Re: [PATCH v2 2/7] migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo

2020-10-24 Thread Hao Wang
Hi Daniel,

For the warning in your compiling -- "error: 
‘qemuMonitorJSONExtractDirtyRateInfo’ defined but not used 
[-Werror=unused-function]":

" qemuMonitorJSONExtractDirtyRateInfo" would be called by function 
"qemuMonitorJSONQueryDirtyRate" in [PATCH 3/7].
So please apply all the serial of patches before your compiling. Thanks!

BR,
Hao


在 2020/10/24 4:05, Daniel Henrique Barboza 写道:
> 
> 
> On 10/19/20 9:58 AM, Hao Wang wrote:
>> Implement qemuMonitorJSONExtractDirtyRateInfo to deal with the return from
>> qmp "query-dirty-rate", and store them in virDomainDirtyRateInfo.
>>
>> Signed-off-by: Hao Wang 
>> Reviewed-by: Chuan Zheng 
>> ---
> 
> This patch failed to compile in my env:
> 
> 
> 
> 
> ../src/qemu/qemu_monitor_json.c:9649:1: error: 
> ‘qemuMonitorJSONExtractDirtyRateInfo’ defined but not used 
> [-Werror=unused-function]
>  9649 | qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
>   | ^~~
> cc1: all warnings being treated as errors
> 
> 
> 
> 
> DHB
> 
> 
> 
>>   include/libvirt/libvirt-domain.h | 16 +++
>>   src/qemu/qemu_monitor_json.c | 48 
>>   2 files changed, 64 insertions(+)
>>
>> diff --git a/include/libvirt/libvirt-domain.h 
>> b/include/libvirt/libvirt-domain.h
>> index c7e22d4af1..9bf4f8a8cf 100644
>> --- a/include/libvirt/libvirt-domain.h
>> +++ b/include/libvirt/libvirt-domain.h
>> @@ -5012,6 +5012,22 @@ int virDomainBackupBegin(virDomainPtr domain,
>>   char *virDomainBackupGetXMLDesc(virDomainPtr domain,
>>   unsigned int flags);
>>   +/**
>> + * virDomainDirtyRateStatus:
>> + *
>> + * Details on the cause of a dirtyrate calculation status.
>> + */
>> +
>> +typedef enum {
>> +    VIR_DOMAIN_DIRTYRATE_UNSTARTED = 0, /* the dirtyrate calculation has 
>> not been started */
>> +    VIR_DOMAIN_DIRTYRATE_MEASURING = 1, /* the dirtyrate calculation is 
>> measuring */
>> +    VIR_DOMAIN_DIRTYRATE_MEASURED  = 2, /* the dirtyrate calculation is 
>> completed */
>> +
>> +# ifdef VIR_ENUM_SENTINELS
>> +    VIR_DOMAIN_DIRTYRATE_LAST
>> +# endif
>> +} virDomainDirtyRateStatus;
>> +
>>   /**
>>    * virDomainDirtyRateInfo:
>>    *
>> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
>> index e88e6aebaf..37612a9bba 100644
>> --- a/src/qemu/qemu_monitor_json.c
>> +++ b/src/qemu/qemu_monitor_json.c
>> @@ -9414,3 +9414,51 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
>>   return virJSONValueGetBoolean(virJSONValueObjectGet(reply, "return"),
>>     migratable);
>>   }
>> +
>> +
>> +VIR_ENUM_DECL(qemuDomainDirtyRateStatus);
>> +VIR_ENUM_IMPL(qemuDomainDirtyRateStatus,
>> +  VIR_DOMAIN_DIRTYRATE_LAST,
>> +  "unstarted",
>> +  "measuring",
>> +  "measured");
>> +
>> +static int
>> +qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
>> +    virDomainDirtyRateInfoPtr info)
>> +{
>> +    const char *status;
>> +    int statusID;
>> +
>> +    if (!(status = virJSONValueObjectGetString(data, "status"))) {
>> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +   _("query-dirty-rate reply was missing 'status' 
>> data"));
>> +    return -1;
>> +    }
>> +
>> +    if ((statusID = qemuDomainDirtyRateStatusTypeFromString(status)) < 0) {
>> +    return -1;
>> +    }
>> +    info->status = statusID;
>> +
>> +    if ((info->status == VIR_DOMAIN_DIRTYRATE_MEASURED) &&
>> +    (virJSONValueObjectGetNumberLong(data, "dirty-rate", 
>> &(info->dirtyRate)) < 0)) {
>> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +   _("query-dirty-rate reply was missing 'dirty-rate' 
>> data"));
>> +    return -1;
>> +    }
>> +
>> +    if (virJSONValueObjectGetNumberLong(data, "start-time", 
>> &(info->startTime)) < 0) {
>> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +   _("query-dirty-rate reply was missing 'start-time' 
>> data"));
>> +    return -1;
>> +    }
>> +
>> +    if (virJSONValueObjectGetNumberLong(data, "calc-time", 
>> &(info->calcTime)) < 0) {
>> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +   _("query-dirty-rate reply was missing 'calc-time' 
>> data"));
>> +    return -1;
>> +    }
>> +
>> +    return 0;
>> +}
>>
> .




[PATCH v2 2/7] migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo

2020-10-19 Thread Hao Wang
Implement qemuMonitorJSONExtractDirtyRateInfo to deal with the return from
qmp "query-dirty-rate", and store them in virDomainDirtyRateInfo.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 16 +++
 src/qemu/qemu_monitor_json.c | 48 
 2 files changed, 64 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index c7e22d4af1..9bf4f8a8cf 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5012,6 +5012,22 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateStatus:
+ *
+ * Details on the cause of a dirtyrate calculation status.
+ */
+
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_UNSTARTED = 0, /* the dirtyrate calculation has not 
been started */
+VIR_DOMAIN_DIRTYRATE_MEASURING = 1, /* the dirtyrate calculation is 
measuring */
+VIR_DOMAIN_DIRTYRATE_MEASURED  = 2, /* the dirtyrate calculation is 
completed */
+
+# ifdef VIR_ENUM_SENTINELS
+VIR_DOMAIN_DIRTYRATE_LAST
+# endif
+} virDomainDirtyRateStatus;
+
 /**
  * virDomainDirtyRateInfo:
  *
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index e88e6aebaf..37612a9bba 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9414,3 +9414,51 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 return virJSONValueGetBoolean(virJSONValueObjectGet(reply, "return"),
   migratable);
 }
+
+
+VIR_ENUM_DECL(qemuDomainDirtyRateStatus);
+VIR_ENUM_IMPL(qemuDomainDirtyRateStatus,
+  VIR_DOMAIN_DIRTYRATE_LAST,
+  "unstarted",
+  "measuring",
+  "measured");
+
+static int
+qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
+virDomainDirtyRateInfoPtr info)
+{
+const char *status;
+int statusID;
+
+if (!(status = virJSONValueObjectGetString(data, "status"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'status' data"));
+return -1;
+}
+
+if ((statusID = qemuDomainDirtyRateStatusTypeFromString(status)) < 0) {
+return -1;
+}
+info->status = statusID;
+
+if ((info->status == VIR_DOMAIN_DIRTYRATE_MEASURED) &&
+(virJSONValueObjectGetNumberLong(data, "dirty-rate", 
&(info->dirtyRate)) < 0)) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'dirty-rate' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "start-time", 
&(info->startTime)) < 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'start-time' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "calc-time", &(info->calcTime)) 
< 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'calc-time' 
data"));
+return -1;
+}
+
+return 0;
+}
-- 
2.23.0




[PATCH v2 5/7] migration/dirtyrate: Introduce virDomainDirtyRateFlags

2020-10-19 Thread Hao Wang
Introduce virDomainDirtyRateFlags for DomainGetDirtyRateInfo API.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 9bf4f8a8cf..ca54ebdb2e 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5012,6 +5012,17 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateFlags:
+ *
+ * Details on the flags used by getdirtyrate api.
+ */
+
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_CALC = 1 << 0,  /* calculate domain's dirtyrate */
+VIR_DOMAIN_DIRTYRATE_QUERY = 1 << 1, /* query domain's dirtyrate */
+} virDomainDirtyRateFlags;
+
 /**
  * virDomainDirtyRateStatus:
  *
-- 
2.23.0




[PATCH v2 0/7] migration/dirtyrate: Introduce APIs for getting domain memory dirty rate

2020-10-19 Thread Hao Wang
V1 -> V2:
replace QEMU_JOB_ASYNC with QEMU_JOB_QUERY


Sometimes domain's memory dirty rate is expected by user in order to
decide whether it's proper to be migrated out or not.

We have already completed the QEMU part of the capability:
https://patchew.org/QEMU/1600237327-33618-1-git-send-email-zhengch...@huawei.com/
And this serial of patches introduce the corresponding LIBVIRT part --
DomainGetDirtyRateInfo API and corresponding virsh api -- "getdirtyrate".


instructions:
bash# virsh getdirtyrate --help
  NAME
getdirtyrate - Get a vm's memory dirty rate

  SYNOPSIS
getdirtyrate  [--seconds ] [--calculate] [--query]

  DESCRIPTION
Get memory dirty rate of a domain in order to decide whether it's proper to 
be migrated out or not.

  OPTIONS
[--domain]   domain name, id or uuid
--seconds   calculate memory dirty rate within specified seconds, a 
valid range of values is [1, 60], and would default to 1s.
--calculate  calculate dirty rate only, can be used together with 
--query, either or both is expected, otherwise would default to both.
--query  query dirty rate only, can be used together with 
--calculate, either or both is expected, otherwise would default to both.


example:
bash# virsh getdirtyrate --calculate --query --domain vm0 --seconds 1
status:measured
startTime: 820148
calcTime:  1 s
dirtyRate:     6 MB/s


Hao Wang (7):
  migration/dirtyrate: Introduce virDomainDirtyRateInfo structure
  migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo
  migration/dirtyrate: Implement qemuDomainQueryDirtyRate
  migration/dirtyrate: Implement qemuDomainCalculateDirtyRate
  migration/dirtyrate: Introduce virDomainDirtyRateFlags
  migration/dirtyrate: Introduce DomainGetDirtyRateInfo API
  migration/dirtyrate: Introduce getdirtyrate virsh api

 include/libvirt/libvirt-domain.h |  64 ++
 src/driver-hypervisor.h  |   7 ++
 src/libvirt-domain.c |  46 +
 src/libvirt_public.syms  |   5 ++
 src/qemu/qemu_driver.c   |  70 +++
 src/qemu/qemu_migration.c|  59 
 src/qemu/qemu_migration.h|  10 +++
 src/qemu/qemu_monitor.c  |  24 +++
 src/qemu/qemu_monitor.h  |   8 +++
 src/qemu/qemu_monitor_json.c |  97 ++
 src/qemu/qemu_monitor_json.h |   8 +++
 src/remote/remote_driver.c   |   1 +
 src/remote/remote_protocol.x |  21 +-
 tools/virsh-domain.c | 112 +++
 14 files changed, 531 insertions(+), 1 deletion(-)

-- 
2.23.0




[PATCH v2 1/7] migration/dirtyrate: Introduce virDomainDirtyRateInfo structure

2020-10-19 Thread Hao Wang
Introduce virDomainDirtyRateInfo structure used for domain's memory dirty rate 
query.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 24 
 1 file changed, 24 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 77f9116675..c7e22d4af1 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5012,4 +5012,28 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateInfo:
+ *
+ * a virDomainDirtyRateInfo is a structure filled by virDomainGetDirtyRate() 
and
+ * extracting dirty rate infomation for a given active Domain.
+ */
+
+typedef struct _virDomainDirtyRateInfo virDomainDirtyRateInfo;
+
+struct _virDomainDirtyRateInfo {
+int status; /* the status of dirtyrate calculation */
+long long dirtyRate;/* the dirtyrate in MB/s */
+long long startTime;/* the start time of dirtyrate calculation */
+long long calcTime; /* the period of dirtyrate calculation */
+};
+
+/**
+ * virDomainDirtyRateInfoPtr:
+ *
+ * a virDomainDirtyRateInfoPtr is a pointer to a virDomainDirtyRateInfo 
structure.
+ */
+
+typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
+
 #endif /* LIBVIRT_DOMAIN_H */
-- 
2.23.0




[PATCH v2 4/7] migration/dirtyrate: Implement qemuDomainCalculateDirtyRate

2020-10-19 Thread Hao Wang
Implement qemuDomainCalculateDirtyRate which calculates domain's memory
dirty rate using qmp "calc-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_migration.c| 28 
 src/qemu/qemu_migration.h|  5 +
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 22 ++
 src/qemu/qemu_monitor_json.h |  4 
 6 files changed, 75 insertions(+)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index a2f6b319de..8c6dd807f5 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5857,3 +5857,31 @@ qemuDomainQueryDirtyRate(virDomainPtr dom,
 
 return ret;
 }
+
+
+int
+qemuDomainCalculateDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ long long sec)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return ret;
+}
+
+priv = vm->privateData;
+
+VIR_DEBUG("Calculate dirty rate during %lld seconds", sec);
+qemuDomainObjEnterMonitor(driver, vm);
+
+ret = qemuMonitorCalculateDirtyRate(priv->mon, sec);
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 0cd12adb27..15f707fb57 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -263,3 +263,8 @@ int
 qemuDomainQueryDirtyRate(virDomainPtr dom,
  virDomainObjPtr vm,
  virDomainDirtyRateInfoPtr info);
+
+int
+qemuDomainCalculateDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ long long sec);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 009aeb759c..4acb5ca5a1 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4668,3 +4668,15 @@ qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
 
 return qemuMonitorJSONQueryDirtyRate(mon, info);
 }
+
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec)
+{
+VIR_DEBUG("seconds=%lld", sec);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONCalculateDirtyRate(mon, sec);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 8813c546f0..936ebf167b 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1451,3 +1451,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 int
 qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
   virDomainDirtyRateInfoPtr info);
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 23b0796101..a8a3432c01 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9489,3 +9489,25 @@ qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
 
 return qemuMonitorJSONExtractDirtyRateInfo(data, info);
 }
+
+
+int
+qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("calc-dirty-rate",
+   "I:calc-time", (long)sec,
+   NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+return 0;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index d6dba4731f..a18a068f50 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -702,3 +702,7 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 int
 qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
   virDomainDirtyRateInfoPtr info);
+
+int
+qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec);
-- 
2.23.0




[PATCH v2 7/7] migration/dirtyrate: Introduce getdirtyrate virsh api

2020-10-19 Thread Hao Wang
Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 tools/virsh-domain.c | 112 +++
 1 file changed, 112 insertions(+)

diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 8f11393197..175b2d7cd3 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -14333,6 +14333,112 @@ cmdGuestInfo(vshControl *ctl, const vshCmd *cmd)
 return ret;
 }
 
+/*
+ * "querydirtyrate" command
+ */
+static const vshCmdInfo info_getdirtyrate[] = {
+{.name = "help",
+ .data = N_("Get a vm's memory dirty rate")
+},
+{.name = "desc",
+ .data = N_("Get memory dirty rate of a domain in order to decide"
+" whether it's proper to be migrated out or not.")
+},
+{.name = NULL}
+};
+
+static const vshCmdOptDef opts_getdirtyrate[] = {
+VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+{.name = "seconds",
+ .type = VSH_OT_INT,
+ .help = N_("calculate memory dirty rate within specified seconds,"
+" a valid range of values is [1, 60], and would default to 
1s.")
+},
+{.name = "calculate",
+ .type = VSH_OT_BOOL,
+ .help = N_("calculate dirty rate only, can be used together with --query,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = "query",
+ .type = VSH_OT_BOOL,
+ .help = N_("query dirty rate only, can be used together with --calculate,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = NULL}
+};
+
+static bool
+cmdGetDirtyRateInfo(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom = NULL;
+virDomainDirtyRateInfo info;
+long long sec = 0;
+const char *status = NULL;
+unsigned int flags = 0;
+int rc;
+bool ret = false;
+bool calc = vshCommandOptBool(cmd, "calculate");
+bool query = vshCommandOptBool(cmd, "query");
+
+if (calc)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC;
+if (query)
+flags |= VIR_DOMAIN_DIRTYRATE_QUERY;
+
+/* if flag option is missing, default to both --calculate and --query */
+if (!calc && !query)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC | VIR_DOMAIN_DIRTYRATE_QUERY;
+
+if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+rc = vshCommandOptLongLong(ctl, cmd, "seconds", );
+if (rc < 0)
+goto done;
+
+/* if --seconds option is missing, default to 1s */
+if (!rc)
+sec = 1;
+
+if (virDomainGetDirtyRateInfo(dom, , sec, flags) < 0) {
+vshError(ctl, "%s", _("Get memory dirty-rate failed."));
+goto done;
+}
+
+if (flags & VIR_DOMAIN_DIRTYRATE_QUERY) {
+switch (info.status) {
+case VIR_DOMAIN_DIRTYRATE_UNSTARTED:
+status = _("unstarted");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURING:
+status = _("measuring");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURED:
+status = _("measured");
+break;
+default:
+status = _("unknown");
+}
+
+vshPrint(ctl, _("status:%s\n"), status);
+vshPrint(ctl, _("startTime: %lld\n"), info.startTime);
+vshPrint(ctl, _("calcTime:  %lld s\n"), info.calcTime);
+
+if (info.status == VIR_DOMAIN_DIRTYRATE_MEASURED)
+vshPrint(ctl, _("dirtyRate: %lld MB/s\n"), info.dirtyRate);
+else
+vshPrint(ctl, _("dirtyRate: the calculation is %s, please 
query results later\n"),
+ status);
+} else {
+vshPrint(ctl, _("Memory dirty rate is calculating, use --query option 
to display results.\n"));
+}
+
+ret = true;
+ done:
+virDomainFree(dom);
+return ret;
+}
+
 const vshCmdDef domManagementCmds[] = {
 {.name = "attach-device",
  .handler = cmdAttachDevice,
@@ -14960,5 +15066,11 @@ const vshCmdDef domManagementCmds[] = {
  .info = info_guestinfo,
  .flags = 0
 },
+{.name = "getdirtyrate",
+ .handler = cmdGetDirtyRateInfo,
+ .opts = opts_getdirtyrate,
+ .info = info_getdirtyrate,
+ .flags = 0
+},
 {.name = NULL}
 };
-- 
2.23.0




[PATCH v2 6/7] migration/dirtyrate: Introduce DomainGetDirtyRateInfo API

2020-10-19 Thread Hao Wang
Introduce DomainGetDirtyRateInfo API for domain's memory dirty rate
calculation and query.

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 13 ++
 src/driver-hypervisor.h  |  7 
 src/libvirt-domain.c | 46 +
 src/libvirt_public.syms  |  5 +++
 src/qemu/qemu_driver.c   | 70 
 src/remote/remote_driver.c   |  1 +
 src/remote/remote_protocol.x | 21 +-
 7 files changed, 162 insertions(+), 1 deletion(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index ca54ebdb2e..f318b0f272 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5063,4 +5063,17 @@ struct _virDomainDirtyRateInfo {
 
 typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
 
+/**
+ * virDomainDirtyRateInfoPtr:
+ *
+ * a virDomainDirtyRateInfoPtr is a pointer to a virDomainDirtyRateInfo 
structure.
+ */
+
+typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
+
+int virDomainGetDirtyRateInfo(virDomainPtr domain,
+  virDomainDirtyRateInfoPtr info,
+  long long sec,
+  int flags);
+
 #endif /* LIBVIRT_DOMAIN_H */
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index bce023017d..dc2aefa910 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1387,6 +1387,12 @@ typedef char *
 (*virDrvDomainBackupGetXMLDesc)(virDomainPtr domain,
 unsigned int flags);
 
+typedef int
+(*virDrvDomainGetDirtyRateInfo)(virDomainPtr domain,
+virDomainDirtyRateInfoPtr info,
+long long sec,
+int flags);
+
 typedef struct _virHypervisorDriver virHypervisorDriver;
 typedef virHypervisorDriver *virHypervisorDriverPtr;
 
@@ -1650,4 +1656,5 @@ struct _virHypervisorDriver {
 virDrvDomainAgentSetResponseTimeout domainAgentSetResponseTimeout;
 virDrvDomainBackupBegin domainBackupBegin;
 virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc;
+virDrvDomainGetDirtyRateInfo domainGetDirtyRateInfo;
 };
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 3c5f55176a..8714c1ca93 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -12758,3 +12758,49 @@ virDomainBackupGetXMLDesc(virDomainPtr domain,
 virDispatchError(conn);
 return NULL;
 }
+
+
+/**
+ * virDomainGetDirtyRateInfo:
+ * @domain: a domain object.
+ * @info: return value of current domain's memory dirty rate info.
+ * @sec: show dirty rate within specified seconds.
+ * @flags: the flags of getdirtyrate action -- calculate and/or query.
+ *
+ * Get the current domain's memory dirty rate (in MB/s).
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainGetDirtyRateInfo(virDomainPtr domain,
+  virDomainDirtyRateInfoPtr info,
+  long long sec,
+  int flags)
+{
+virConnectPtr conn;
+
+VIR_DOMAIN_DEBUG(domain, "info = %p, seconds=%lld", info, sec);
+
+virResetLastError();
+
+virCheckDomainReturn(domain, -1);
+conn = domain->conn;
+
+virCheckNonNullArgGoto(info, error);
+virCheckReadOnlyGoto(conn->flags, error);
+
+if (info)
+memset(info, 0, sizeof(*info));
+
+if (conn->driver->domainGetDirtyRateInfo) {
+if (conn->driver->domainGetDirtyRateInfo(domain, info, sec, flags) < 0)
+goto error;
+VIR_DOMAIN_DEBUG(domain, "info = %p, seconds=%lld", info, sec);
+return 0;
+}
+
+virReportUnsupportedError();
+ error:
+virDispatchError(conn);
+return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 539d2e3943..11864f48b1 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -873,4 +873,9 @@ LIBVIRT_6.0.0 {
 virDomainBackupGetXMLDesc;
 } LIBVIRT_5.10.0;
 
+LIBVIRT_6.9.0 {
+global:
+virDomainGetDirtyRateInfo;
+} LIBVIRT_6.0.0;
+
 #  define new API here using predicted next version number 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 825bdd9119..47292a42be 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20050,6 +20050,75 @@ qemuDomainAgentSetResponseTimeout(virDomainPtr dom,
 }
 
 
+#define MIN_DIRTYRATE_CALCULATION_PERIOD1/* 1s */
+#define MAX_DIRTYRATE_CALCULATION_PERIOD60   /* 60s */
+
+static int
+qemuDomainGetDirtyRateInfo(virDomainPtr dom,
+   virDomainDirtyRateInfoPtr info,
+   long long sec,
+   int flags)
+{
+virDomainObjPtr vm = NULL;
+virQEMUDriverPtr driver = dom->conn->privateData;
+int ret = -1;
+
+if (!(vm = qemuDomainObjFromDomain(dom)))
+return ret;
+

[PATCH v2 3/7] migration/dirtyrate: Implement qemuDomainQueryDirtyRate

2020-10-19 Thread Hao Wang
Implement qemuDomainQueryDirtyRate which query domain's memory dirty rate
using qmp "query-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_migration.c| 31 +++
 src/qemu/qemu_migration.h|  5 +
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 27 +++
 src/qemu/qemu_monitor_json.h |  4 
 6 files changed, 83 insertions(+)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 132545c99f..a2f6b319de 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5826,3 +5826,34 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
 virHashFree(blockinfo);
 return 0;
 }
+
+
+int
+qemuDomainQueryDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return ret;
+}
+
+priv = vm->privateData;
+
+qemuDomainObjEnterMonitor(driver, vm);
+
+ret = qemuMonitorQueryDirtyRate(priv->mon, info);
+if (ret < 0) {
+virReportError(VIR_ERR_OPERATION_FAILED,
+   "%s", _("get vm's dirty rate failed."));
+}
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index fd9eb7cab0..0cd12adb27 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -258,3 +258,8 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
  virDomainObjPtr vm,
  qemuDomainAsyncJob asyncJob,
  qemuDomainJobInfoPtr jobInfo);
+
+int
+qemuDomainQueryDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 834e1c9e8f..009aeb759c 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4656,3 +4656,15 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 return qemuMonitorJSONTransactionBackup(actions, device, jobname, target,
 bitmap, syncmode);
 }
+
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info)
+{
+VIR_DEBUG("info=%p", info);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONQueryDirtyRate(mon, info);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index f2c632a7ac..8813c546f0 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1447,3 +1447,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
  const char *target,
  const char *bitmap,
  qemuMonitorTransactionBackupSyncMode syncmode);
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 37612a9bba..23b0796101 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9462,3 +9462,30 @@ qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
 
 return 0;
 }
+
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+virJSONValuePtr data = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("query-dirty-rate", NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'return' data"));
+return -1;
+}
+
+return qemuMonitorJSONExtractDirtyRateInfo(data, info);
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index e9107eaade..d6dba4731f 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -698,3 +698,7 @@ int qemuMonitorJSONSetDBusVMStateIdList(qemuMonitorPtr mon,
 int
 qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 bool *migratable);
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info);
-- 
2.23.0




[[RESEND] 2/8] migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo

2020-10-15 Thread Hao Wang
Implement qemuMonitorJSONExtractDirtyRateInfo to deal with the return from
qmp "query-dirty-rate", and store them in virDomainDirtyRateInfo.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 16 +++
 src/qemu/qemu_monitor_json.c | 48 
 2 files changed, 64 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index c7e22d4af1..9bf4f8a8cf 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5012,6 +5012,22 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateStatus:
+ *
+ * Details on the cause of a dirtyrate calculation status.
+ */
+
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_UNSTARTED = 0, /* the dirtyrate calculation has not 
been started */
+VIR_DOMAIN_DIRTYRATE_MEASURING = 1, /* the dirtyrate calculation is 
measuring */
+VIR_DOMAIN_DIRTYRATE_MEASURED  = 2, /* the dirtyrate calculation is 
completed */
+
+# ifdef VIR_ENUM_SENTINELS
+VIR_DOMAIN_DIRTYRATE_LAST
+# endif
+} virDomainDirtyRateStatus;
+
 /**
  * virDomainDirtyRateInfo:
  *
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 26ac499fc5..2e920553ae 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9393,3 +9393,51 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 return virJSONValueGetBoolean(virJSONValueObjectGet(reply, "return"),
   migratable);
 }
+
+
+VIR_ENUM_DECL(qemuDomainDirtyRateStatus);
+VIR_ENUM_IMPL(qemuDomainDirtyRateStatus,
+  VIR_DOMAIN_DIRTYRATE_LAST,
+  "unstarted",
+  "measuring",
+  "measured");
+
+static int
+qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
+virDomainDirtyRateInfoPtr info)
+{
+const char *status;
+int statusID;
+
+if (!(status = virJSONValueObjectGetString(data, "status"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'status' data"));
+return -1;
+}
+
+if ((statusID = qemuDomainDirtyRateStatusTypeFromString(status)) < 0) {
+return -1;
+}
+info->status = statusID;
+
+if ((info->status == VIR_DOMAIN_DIRTYRATE_MEASURED) &&
+(virJSONValueObjectGetNumberLong(data, "dirty-rate", 
&(info->dirtyRate)) < 0)) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'dirty-rate' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "start-time", 
&(info->startTime)) < 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'start-time' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "calc-time", &(info->calcTime)) 
< 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'calc-time' 
data"));
+return -1;
+}
+
+return 0;
+}
-- 
2.23.0




[[RESEND] 7/8] migration/dirtyrate: Introduce DomainGetDirtyRateInfo API

2020-10-15 Thread Hao Wang
Introduce DomainGetDirtyRateInfo API for domain's memory dirty rate
calculation and query.

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 13 ++
 src/driver-hypervisor.h  |  7 
 src/libvirt-domain.c | 46 +
 src/libvirt_public.syms  |  5 +++
 src/qemu/qemu_driver.c   | 71 
 src/remote/remote_driver.c   |  1 +
 src/remote/remote_protocol.x | 21 +-
 7 files changed, 163 insertions(+), 1 deletion(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 68a760816a..9e148a238b 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5064,4 +5064,17 @@ struct _virDomainDirtyRateInfo {
 
 typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
 
+/**
+ * virDomainDirtyRateInfoPtr:
+ *
+ * a virDomainDirtyRateInfoPtr is a pointer to a virDomainDirtyRateInfo 
structure.
+ */
+
+typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
+
+int virDomainGetDirtyRateInfo(virDomainPtr domain,
+  virDomainDirtyRateInfoPtr info,
+  long long sec,
+  int flags);
+
 #endif /* LIBVIRT_DOMAIN_H */
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index bce023017d..dc2aefa910 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1387,6 +1387,12 @@ typedef char *
 (*virDrvDomainBackupGetXMLDesc)(virDomainPtr domain,
 unsigned int flags);
 
+typedef int
+(*virDrvDomainGetDirtyRateInfo)(virDomainPtr domain,
+virDomainDirtyRateInfoPtr info,
+long long sec,
+int flags);
+
 typedef struct _virHypervisorDriver virHypervisorDriver;
 typedef virHypervisorDriver *virHypervisorDriverPtr;
 
@@ -1650,4 +1656,5 @@ struct _virHypervisorDriver {
 virDrvDomainAgentSetResponseTimeout domainAgentSetResponseTimeout;
 virDrvDomainBackupBegin domainBackupBegin;
 virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc;
+virDrvDomainGetDirtyRateInfo domainGetDirtyRateInfo;
 };
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 3c5f55176a..8714c1ca93 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -12758,3 +12758,49 @@ virDomainBackupGetXMLDesc(virDomainPtr domain,
 virDispatchError(conn);
 return NULL;
 }
+
+
+/**
+ * virDomainGetDirtyRateInfo:
+ * @domain: a domain object.
+ * @info: return value of current domain's memory dirty rate info.
+ * @sec: show dirty rate within specified seconds.
+ * @flags: the flags of getdirtyrate action -- calculate and/or query.
+ *
+ * Get the current domain's memory dirty rate (in MB/s).
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainGetDirtyRateInfo(virDomainPtr domain,
+  virDomainDirtyRateInfoPtr info,
+  long long sec,
+  int flags)
+{
+virConnectPtr conn;
+
+VIR_DOMAIN_DEBUG(domain, "info = %p, seconds=%lld", info, sec);
+
+virResetLastError();
+
+virCheckDomainReturn(domain, -1);
+conn = domain->conn;
+
+virCheckNonNullArgGoto(info, error);
+virCheckReadOnlyGoto(conn->flags, error);
+
+if (info)
+memset(info, 0, sizeof(*info));
+
+if (conn->driver->domainGetDirtyRateInfo) {
+if (conn->driver->domainGetDirtyRateInfo(domain, info, sec, flags) < 0)
+goto error;
+VIR_DOMAIN_DEBUG(domain, "info = %p, seconds=%lld", info, sec);
+return 0;
+}
+
+virReportUnsupportedError();
+ error:
+virDispatchError(conn);
+return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 539d2e3943..11864f48b1 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -873,4 +873,9 @@ LIBVIRT_6.0.0 {
 virDomainBackupGetXMLDesc;
 } LIBVIRT_5.10.0;
 
+LIBVIRT_6.9.0 {
+global:
+virDomainGetDirtyRateInfo;
+} LIBVIRT_6.0.0;
+
 #  define new API here using predicted next version number 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 8457cbfb4b..3ef8253cb5 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20055,6 +20055,76 @@ qemuDomainAgentSetResponseTimeout(virDomainPtr dom,
 }
 
 
+#define MIN_DIRTYRATE_CALCULATION_PERIOD1/* 1s */
+#define MAX_DIRTYRATE_CALCULATION_PERIOD60   /* 60s */
+
+static int
+qemuDomainGetDirtyRateInfo(virDomainPtr dom,
+   virDomainDirtyRateInfoPtr info,
+   long long sec,
+   int flags)
+{
+virDomainObjPtr vm = NULL;
+virQEMUDriverPtr driver = dom->conn->privateData;
+int ret = -1;
+
+if (!(vm = qemuDomainObjFromDomain(dom)))
+return ret;
+

[[RESEND] 3/8] migration/dirtyrate: Introduce dirty_rate async job

2020-10-15 Thread Hao Wang
Introduce dirty_rate async job for qemuDomainGetDirtyRateInfo.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 1 +
 src/qemu/qemu_domainjob.c| 3 +++
 src/qemu/qemu_domainjob.h| 1 +
 src/qemu/qemu_driver.c   | 5 +
 src/qemu/qemu_migration.c| 2 ++
 src/qemu/qemu_process.c  | 3 +++
 tools/virsh-domain.c | 1 +
 7 files changed, 16 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 9bf4f8a8cf..c7c64b9317 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -3308,6 +3308,7 @@ typedef enum {
 VIR_DOMAIN_JOB_OPERATION_SNAPSHOT_REVERT = 7,
 VIR_DOMAIN_JOB_OPERATION_DUMP = 8,
 VIR_DOMAIN_JOB_OPERATION_BACKUP = 9,
+VIR_DOMAIN_JOB_OPERATION_DIRTYRATE = 10,
 
 # ifdef VIR_ENUM_SENTINELS
 VIR_DOMAIN_JOB_OPERATION_LAST
diff --git a/src/qemu/qemu_domainjob.c b/src/qemu/qemu_domainjob.c
index 3c2c6b9179..d20cc09d49 100644
--- a/src/qemu/qemu_domainjob.c
+++ b/src/qemu/qemu_domainjob.c
@@ -61,6 +61,7 @@ VIR_ENUM_IMPL(qemuDomainAsyncJob,
   "snapshot",
   "start",
   "backup",
+  "dirty rate"
 );
 
 const char *
@@ -78,6 +79,7 @@ qemuDomainAsyncJobPhaseToString(qemuDomainAsyncJob job,
 case QEMU_ASYNC_JOB_START:
 case QEMU_ASYNC_JOB_NONE:
 case QEMU_ASYNC_JOB_BACKUP:
+case QEMU_ASYNC_JOB_DIRTYRATE:
 G_GNUC_FALLTHROUGH;
 case QEMU_ASYNC_JOB_LAST:
 break;
@@ -104,6 +106,7 @@ qemuDomainAsyncJobPhaseFromString(qemuDomainAsyncJob job,
 case QEMU_ASYNC_JOB_START:
 case QEMU_ASYNC_JOB_NONE:
 case QEMU_ASYNC_JOB_BACKUP:
+case QEMU_ASYNC_JOB_DIRTYRATE:
 G_GNUC_FALLTHROUGH;
 case QEMU_ASYNC_JOB_LAST:
 break;
diff --git a/src/qemu/qemu_domainjob.h b/src/qemu/qemu_domainjob.h
index 79f0127252..4f820aaf37 100644
--- a/src/qemu/qemu_domainjob.h
+++ b/src/qemu/qemu_domainjob.h
@@ -74,6 +74,7 @@ typedef enum {
 QEMU_ASYNC_JOB_SNAPSHOT,
 QEMU_ASYNC_JOB_START,
 QEMU_ASYNC_JOB_BACKUP,
+QEMU_ASYNC_JOB_DIRTYRATE,
 
 QEMU_ASYNC_JOB_LAST
 } qemuDomainAsyncJob;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 825bdd9119..8457cbfb4b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -12856,6 +12856,11 @@ static int qemuDomainAbortJob(virDomainPtr dom)
 ret = 0;
 break;
 
+case QEMU_ASYNC_JOB_DIRTYRATE:
+virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+   _("cannot abort get dirty rate"));
+break;
+
 case QEMU_ASYNC_JOB_LAST:
 default:
 virReportEnumRangeError(qemuDomainAsyncJob, priv->job.asyncJob);
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 4e959abebf..3e4ca49df0 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1643,6 +1643,8 @@ qemuMigrationJobName(virDomainObjPtr vm)
 return _("start job");
 case QEMU_ASYNC_JOB_BACKUP:
 return _("backup job");
+case QEMU_ASYNC_JOB_DIRTYRATE:
+return _("dirty rate");
 case QEMU_ASYNC_JOB_LAST:
 default:
 return _("job");
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 5bc76a75e3..74b98cd72b 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3687,6 +3687,9 @@ qemuProcessRecoverJob(virQEMUDriverPtr driver,
 priv->job.current->started = now;
 break;
 
+case QEMU_ASYNC_JOB_DIRTYRATE:
+break;
+
 case QEMU_ASYNC_JOB_NONE:
 case QEMU_ASYNC_JOB_LAST:
 break;
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 8f11393197..909864c940 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -6166,6 +6166,7 @@ VIR_ENUM_IMPL(virshDomainJobOperation,
   N_("Snapshot revert"),
   N_("Dump"),
   N_("Backup"),
+  N_("Dirty Rate"),
 );
 
 static const char *
-- 
2.23.0




[[RESEND] 5/8] migration/dirtyrate: Implement qemuDomainCalculateDirtyRate

2020-10-15 Thread Hao Wang
Implement qemuDomainCalculateDirtyRate which calculates domain's memory
dirty rate using qmp "calc-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_migration.c| 29 +
 src/qemu/qemu_migration.h|  5 +
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 22 ++
 src/qemu/qemu_monitor_json.h |  4 
 6 files changed, 76 insertions(+)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index be89c0d807..a3c2618bd1 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5870,3 +5870,32 @@ qemuDomainQueryDirtyRate(virDomainPtr dom,
 
 return ret;
 }
+
+
+int
+qemuDomainCalculateDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ long long sec)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return ret;
+}
+
+priv = vm->privateData;
+
+VIR_DEBUG("Calculate dirty rate during %lld seconds", sec);
+if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_DIRTYRATE) < 
0)
+return ret;
+
+ret = qemuMonitorCalculateDirtyRate(priv->mon, sec);
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 0cd12adb27..15f707fb57 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -263,3 +263,8 @@ int
 qemuDomainQueryDirtyRate(virDomainPtr dom,
  virDomainObjPtr vm,
  virDomainDirtyRateInfoPtr info);
+
+int
+qemuDomainCalculateDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ long long sec);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 35b0db1c13..017dd69dbf 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4658,3 +4658,15 @@ qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
 
 return qemuMonitorJSONQueryDirtyRate(mon, info);
 }
+
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec)
+{
+VIR_DEBUG("seconds=%lld", sec);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONCalculateDirtyRate(mon, sec);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 15601b7ee8..a51fb9 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1447,3 +1447,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 int
 qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
   virDomainDirtyRateInfoPtr info);
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 1ce9f8576b..d68dc86b7d 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9468,3 +9468,25 @@ qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
 
 return qemuMonitorJSONExtractDirtyRateInfo(data, info);
 }
+
+
+int
+qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("calc-dirty-rate",
+   "I:calc-time", (long)sec,
+   NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+return 0;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index f3f5b78fb9..6c5fb2b091 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -698,3 +698,7 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 int
 qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
   virDomainDirtyRateInfoPtr info);
+
+int
+qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec);
-- 
2.23.0




[[RESEND] 8/8] migration/dirtyrate: Introduce getdirtyrate virsh api

2020-10-15 Thread Hao Wang
Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 tools/virsh-domain.c | 112 +++
 1 file changed, 112 insertions(+)

diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 909864c940..4b2ee3f8e3 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -14334,6 +14334,112 @@ cmdGuestInfo(vshControl *ctl, const vshCmd *cmd)
 return ret;
 }
 
+/*
+ * "querydirtyrate" command
+ */
+static const vshCmdInfo info_getdirtyrate[] = {
+{.name = "help",
+ .data = N_("Get a vm's memory dirty rate")
+},
+{.name = "desc",
+ .data = N_("Get memory dirty rate of a domain in order to decide"
+" whether it's proper to be migrated out or not.")
+},
+{.name = NULL}
+};
+
+static const vshCmdOptDef opts_getdirtyrate[] = {
+VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+{.name = "seconds",
+ .type = VSH_OT_INT,
+ .help = N_("calculate memory dirty rate within specified seconds,"
+" a valid range of values is [1, 60], and would default to 
1s.")
+},
+{.name = "calculate",
+ .type = VSH_OT_BOOL,
+ .help = N_("calculate dirty rate only, can be used together with --query,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = "query",
+ .type = VSH_OT_BOOL,
+ .help = N_("query dirty rate only, can be used together with --calculate,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = NULL}
+};
+
+static bool
+cmdGetDirtyRateInfo(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom = NULL;
+virDomainDirtyRateInfo info;
+long long sec = 0;
+const char *status = NULL;
+unsigned int flags = 0;
+int rc;
+bool ret = false;
+bool calc = vshCommandOptBool(cmd, "calculate");
+bool query = vshCommandOptBool(cmd, "query");
+
+if (calc)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC;
+if (query)
+flags |= VIR_DOMAIN_DIRTYRATE_QUERY;
+
+/* if flag option is missing, default to both --calculate and --query */
+if (!calc && !query)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC | VIR_DOMAIN_DIRTYRATE_QUERY;
+
+if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+rc = vshCommandOptLongLong(ctl, cmd, "seconds", );
+if (rc < 0)
+goto done;
+
+/* if --seconds option is missing, default to 1s */
+if (!rc)
+sec = 1;
+
+if (virDomainGetDirtyRateInfo(dom, , sec, flags) < 0) {
+vshError(ctl, "%s", _("Get memory dirty-rate failed."));
+goto done;
+}
+
+if (flags & VIR_DOMAIN_DIRTYRATE_QUERY) {
+switch (info.status) {
+case VIR_DOMAIN_DIRTYRATE_UNSTARTED:
+status = _("unstarted");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURING:
+status = _("measuring");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURED:
+status = _("measured");
+break;
+default:
+status = _("unknown");
+}
+
+vshPrint(ctl, _("status:%s\n"), status);
+vshPrint(ctl, _("startTime: %lld\n"), info.startTime);
+vshPrint(ctl, _("calcTime:  %lld s\n"), info.calcTime);
+
+if (info.status == VIR_DOMAIN_DIRTYRATE_MEASURED)
+vshPrint(ctl, _("dirtyRate: %lld MB/s\n"), info.dirtyRate);
+else
+vshPrint(ctl, _("dirtyRate: the calculation is %s, please 
query results later\n"),
+ status);
+} else {
+vshPrint(ctl, _("Memory dirty rate is calculating, use --query option 
to display results.\n"));
+}
+
+ret = true;
+ done:
+virDomainFree(dom);
+return ret;
+}
+
 const vshCmdDef domManagementCmds[] = {
 {.name = "attach-device",
  .handler = cmdAttachDevice,
@@ -14961,5 +15067,11 @@ const vshCmdDef domManagementCmds[] = {
  .info = info_guestinfo,
  .flags = 0
 },
+{.name = "getdirtyrate",
+ .handler = cmdGetDirtyRateInfo,
+ .opts = opts_getdirtyrate,
+ .info = info_getdirtyrate,
+ .flags = 0
+},
 {.name = NULL}
 };
-- 
2.23.0




[[RESEND] 1/8] migration/dirtyrate: Introduce virDomainDirtyRateInfo structure

2020-10-15 Thread Hao Wang
Introduce virDomainDirtyRateInfo structure used for domain's memory dirty rate 
query.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 24 
 1 file changed, 24 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 77f9116675..c7e22d4af1 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5012,4 +5012,28 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateInfo:
+ *
+ * a virDomainDirtyRateInfo is a structure filled by virDomainGetDirtyRate() 
and
+ * extracting dirty rate infomation for a given active Domain.
+ */
+
+typedef struct _virDomainDirtyRateInfo virDomainDirtyRateInfo;
+
+struct _virDomainDirtyRateInfo {
+int status; /* the status of dirtyrate calculation */
+long long dirtyRate;/* the dirtyrate in MB/s */
+long long startTime;/* the start time of dirtyrate calculation */
+long long calcTime; /* the period of dirtyrate calculation */
+};
+
+/**
+ * virDomainDirtyRateInfoPtr:
+ *
+ * a virDomainDirtyRateInfoPtr is a pointer to a virDomainDirtyRateInfo 
structure.
+ */
+
+typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
+
 #endif /* LIBVIRT_DOMAIN_H */
-- 
2.23.0




[[RESEND] 0/8] migration/dirtyrate: Introduce APIs for getting domain memory dirty rate

2020-10-15 Thread Hao Wang
Sometimes domain's memory dirty rate is expected by user in order to
decide whether it's proper to be migrated out or not.

We have already completed the QEMU part of the capability:
https://patchew.org/QEMU/1600237327-33618-1-git-send-email-zhengch...@huawei.com/
And this serial of patches introduce the corresponding LIBVIRT part --
DomainGetDirtyRateInfo API and corresponding virsh api -- "getdirtyrate".


instructions:
bash# virsh getdirtyrate --help
  NAME
getdirtyrate - Get a vm's memory dirty rate

  SYNOPSIS
getdirtyrate  [--seconds ] [--calculate] [--query]

  DESCRIPTION
Get memory dirty rate of a domain in order to decide whether it's proper to 
be migrated out or not.

  OPTIONS
[--domain]   domain name, id or uuid
--seconds   calculate memory dirty rate within specified seconds, a 
valid range of values is [1, 60], and would default to 1s.
--calculate  calculate dirty rate only, can be used together with 
--query, either or both is expected, otherwise would default to both.
--query  query dirty rate only, can be used together with 
--calculate, either or both is expected, otherwise would default to both.


example:
bash# virsh getdirtyrate --calculate --query --domain vm0 --seconds 1
status:measured
startTime: 820148
calcTime:  1 s
dirtyRate: 6 MB/s


Hao Wang (8):
  migration/dirtyrate: Introduce virDomainDirtyRateInfo structure
  migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo
  migration/dirtyrate: Introduce dirty_rate async job
  migration/dirtyrate: Implement qemuDomainQueryDirtyRate
  migration/dirtyrate: Implement qemuDomainCalculateDirtyRate
  migration/dirtyrate: Introduce virDomainDirtyRateFlags
  migration/dirtyrate: Introduce DomainGetDirtyRateInfo API
  migration/dirtyrate: Introduce getdirtyrate virsh api

 include/libvirt/libvirt-domain.h |  65 ++
 src/driver-hypervisor.h  |   7 ++
 src/libvirt-domain.c |  46 +
 src/libvirt_public.syms  |   5 ++
 src/qemu/qemu_domainjob.c|   3 +
 src/qemu/qemu_domainjob.h|   1 +
 src/qemu/qemu_driver.c   |  76 +
 src/qemu/qemu_migration.c|  63 +
 src/qemu/qemu_migration.h|  10 +++
 src/qemu/qemu_monitor.c  |  24 +++
 src/qemu/qemu_monitor.h  |   8 +++
 src/qemu/qemu_monitor_json.c |  97 ++
 src/qemu/qemu_monitor_json.h |   8 +++
 src/qemu/qemu_process.c  |   3 +
 src/remote/remote_driver.c   |   1 +
 src/remote/remote_protocol.x |  21 +-
 tools/virsh-domain.c | 113 +++
 17 files changed, 550 insertions(+), 1 deletion(-)

-- 
2.23.0




[[RESEND] 4/8] migration/dirtyrate: Implement qemuDomainQueryDirtyRate

2020-10-15 Thread Hao Wang
Implement qemuDomainQueryDirtyRate which query domain's memory dirty rate
using qmp "query-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_migration.c| 32 
 src/qemu/qemu_migration.h|  5 +
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 27 +++
 src/qemu/qemu_monitor_json.h |  4 
 6 files changed, 84 insertions(+)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 3e4ca49df0..be89c0d807 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5838,3 +5838,35 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
 virHashFree(blockinfo);
 return 0;
 }
+
+
+int
+qemuDomainQueryDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return ret;
+}
+
+priv = vm->privateData;
+
+if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_DIRTYRATE) < 
0)
+return ret;
+
+ret = qemuMonitorQueryDirtyRate(priv->mon, info);
+if (ret < 0) {
+virReportError(VIR_ERR_OPERATION_FAILED,
+   "%s", _("get vm's dirty rate failed."));
+}
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index fd9eb7cab0..0cd12adb27 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -258,3 +258,8 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
  virDomainObjPtr vm,
  qemuDomainAsyncJob asyncJob,
  qemuDomainJobInfoPtr jobInfo);
+
+int
+qemuDomainQueryDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 8c991fefbb..35b0db1c13 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4646,3 +4646,15 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 return qemuMonitorJSONTransactionBackup(actions, device, jobname, target,
 bitmap, syncmode);
 }
+
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info)
+{
+VIR_DEBUG("info=%p", info);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONQueryDirtyRate(mon, info);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index a744c8975b..15601b7ee8 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1443,3 +1443,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
  const char *target,
  const char *bitmap,
  qemuMonitorTransactionBackupSyncMode syncmode);
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 2e920553ae..1ce9f8576b 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9441,3 +9441,30 @@ qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
 
 return 0;
 }
+
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+virJSONValuePtr data = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("query-dirty-rate", NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'return' data"));
+return -1;
+}
+
+return qemuMonitorJSONExtractDirtyRateInfo(data, info);
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 098ab857be..f3f5b78fb9 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -694,3 +694,7 @@ int qemuMonitorJSONSetDBusVMStateIdList(qemuMonitorPtr mon,
 int
 qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 bool *migratable);
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info);
-- 
2.23.0




[[RESEND] 6/8] migration/dirtyrate: Introduce virDomainDirtyRateFlags

2020-10-15 Thread Hao Wang
Introduce virDomainDirtyRateFlags for DomainGetDirtyRateInfo API.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index c7c64b9317..68a760816a 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5013,6 +5013,17 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateFlags:
+ *
+ * Details on the flags used by getdirtyrate api.
+ */
+
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_CALC = 1 << 0,  /* calculate domain's dirtyrate */
+VIR_DOMAIN_DIRTYRATE_QUERY = 1 << 1, /* query domain's dirtyrate */
+} virDomainDirtyRateFlags;
+
 /**
  * virDomainDirtyRateStatus:
  *
-- 
2.23.0




[PATCH v1 6/8] migration/dirtyrate: Introduce virDomainDirtyRateFlags

2020-10-15 Thread Hao Wang
Introduce virDomainDirtyRateFlags for DomainGetDirtyRateInfo API.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 5ed0ecd..d95020a 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5000,6 +5000,17 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateFlags:
+ *
+ * Details on the flags used by getdirtyrate api.
+ */
+
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_CALC = 1 << 0,  /* calculate domain's dirtyrate */
+VIR_DOMAIN_DIRTYRATE_QUERY = 1 << 1, /* query domain's dirtyrate */
+} virDomainDirtyRateFlags;
+
 /**
  * virDomainDirtyRateStatus:
  *
-- 
2.23.0




[PATCH v1 3/8] migration/dirtyrate: Introduce dirty_rate async job

2020-10-15 Thread Hao Wang
Introduce dirty_rate async job for qemuDomainGetDirtyRateInfo.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 1 +
 src/qemu/qemu_domainjob.c| 3 +++
 src/qemu/qemu_domainjob.h| 1 +
 src/qemu/qemu_driver.c   | 5 +
 src/qemu/qemu_migration.c| 2 ++
 src/qemu/qemu_process.c  | 3 +++
 tools/virsh-domain.c | 1 +
 7 files changed, 16 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index a4b5fcc..5ed0ecd 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -3295,6 +3295,7 @@ typedef enum {
 VIR_DOMAIN_JOB_OPERATION_SNAPSHOT_REVERT = 7,
 VIR_DOMAIN_JOB_OPERATION_DUMP = 8,
 VIR_DOMAIN_JOB_OPERATION_BACKUP = 9,
+VIR_DOMAIN_JOB_OPERATION_DIRTYRATE = 10,
 
 # ifdef VIR_ENUM_SENTINELS
 VIR_DOMAIN_JOB_OPERATION_LAST
diff --git a/src/qemu/qemu_domainjob.c b/src/qemu/qemu_domainjob.c
index 6393cc0..5f802d4 100644
--- a/src/qemu/qemu_domainjob.c
+++ b/src/qemu/qemu_domainjob.c
@@ -61,6 +61,7 @@ VIR_ENUM_IMPL(qemuDomainAsyncJob,
   "snapshot",
   "start",
   "backup",
+  "dirty rate"
 );
 
 const char *
@@ -78,6 +79,7 @@ qemuDomainAsyncJobPhaseToString(qemuDomainAsyncJob job,
 case QEMU_ASYNC_JOB_START:
 case QEMU_ASYNC_JOB_NONE:
 case QEMU_ASYNC_JOB_BACKUP:
+case QEMU_ASYNC_JOB_DIRTYRATE:
 G_GNUC_FALLTHROUGH;
 case QEMU_ASYNC_JOB_LAST:
 break;
@@ -104,6 +106,7 @@ qemuDomainAsyncJobPhaseFromString(qemuDomainAsyncJob job,
 case QEMU_ASYNC_JOB_START:
 case QEMU_ASYNC_JOB_NONE:
 case QEMU_ASYNC_JOB_BACKUP:
+case QEMU_ASYNC_JOB_DIRTYRATE:
 G_GNUC_FALLTHROUGH;
 case QEMU_ASYNC_JOB_LAST:
 break;
diff --git a/src/qemu/qemu_domainjob.h b/src/qemu/qemu_domainjob.h
index c83e055..63496ef 100644
--- a/src/qemu/qemu_domainjob.h
+++ b/src/qemu/qemu_domainjob.h
@@ -74,6 +74,7 @@ typedef enum {
 QEMU_ASYNC_JOB_SNAPSHOT,
 QEMU_ASYNC_JOB_START,
 QEMU_ASYNC_JOB_BACKUP,
+QEMU_ASYNC_JOB_DIRTYRATE,
 
 QEMU_ASYNC_JOB_LAST
 } qemuDomainAsyncJob;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0ad6359..268e457 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -13808,6 +13808,11 @@ static int qemuDomainAbortJob(virDomainPtr dom)
 ret = 0;
 break;
 
+case QEMU_ASYNC_JOB_DIRTYRATE:
+virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+   _("cannot abort get dirty rate"));
+break;
+
 case QEMU_ASYNC_JOB_LAST:
 default:
 virReportEnumRangeError(qemuDomainAsyncJob, priv->job.asyncJob);
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 2c7bf34..25b06ca 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1525,6 +1525,8 @@ qemuMigrationJobName(virDomainObjPtr vm)
 return _("start job");
 case QEMU_ASYNC_JOB_BACKUP:
 return _("backup job");
+case QEMU_ASYNC_JOB_DIRTYRATE:
+return _("dirty rate");
 case QEMU_ASYNC_JOB_LAST:
 default:
 return _("job");
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index ec6ca14..b4db76f 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3657,6 +3657,9 @@ qemuProcessRecoverJob(virQEMUDriverPtr driver,
 priv->job.current->started = now;
 break;
 
+case QEMU_ASYNC_JOB_DIRTYRATE:
+break;
+
 case QEMU_ASYNC_JOB_NONE:
 case QEMU_ASYNC_JOB_LAST:
 break;
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index aaf3b9a..2eabc95 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -6165,6 +6165,7 @@ VIR_ENUM_IMPL(virshDomainJobOperation,
   N_("Snapshot revert"),
   N_("Dump"),
   N_("Backup"),
+  N_("Dirty Rate"),
 );
 
 static const char *
-- 
2.23.0




[PATCH v1 1/8] migration/dirtyrate: Introduce virDomainDirtyRateInfo structure

2020-10-15 Thread Hao Wang
Introduce virDomainDirtyRateInfo structure used for domain's memory dirty rate 
query.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 24 
 1 file changed, 24 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 8b9d9c1..2d3847b 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -4999,4 +4999,28 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateInfo:
+ *
+ * a virDomainDirtyRateInfo is a structure filled by virDomainGetDirtyRate() 
and
+ * extracting dirty rate infomation for a given active Domain.
+ */
+
+typedef struct _virDomainDirtyRateInfo virDomainDirtyRateInfo;
+
+struct _virDomainDirtyRateInfo {
+int status; /* the status of dirtyrate calculation */
+long long dirtyRate;/* the dirtyrate in MB/s */
+long long startTime;/* the start time of dirtyrate calculation */
+long long calcTime; /* the period of dirtyrate calculation */
+};
+
+/**
+ * virDomainDirtyRateInfoPtr:
+ *
+ * a virDomainDirtyRateInfoPtr is a pointer to a virDomainDirtyRateInfo 
structure.
+ */
+
+typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
+
 #endif /* LIBVIRT_DOMAIN_H */
-- 
2.23.0




[PATCH v1 7/8] migration/dirtyrate: Introduce DomainGetDirtyRateInfo API

2020-10-15 Thread Hao Wang
Introduce DomainGetDirtyRateInfo API for domain's memory dirty rate
calculation and query.

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 13 ++
 src/driver-hypervisor.h  |  7 
 src/libvirt-domain.c | 46 +
 src/libvirt_public.syms  |  5 +++
 src/qemu/qemu_driver.c   | 71 
 src/remote/remote_driver.c   |  1 +
 src/remote/remote_protocol.x | 21 +-
 7 files changed, 163 insertions(+), 1 deletion(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index d95020a..e9cc0d1 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5051,4 +5051,17 @@ struct _virDomainDirtyRateInfo {
 
 typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
 
+/**
+ * virDomainDirtyRateInfoPtr:
+ *
+ * a virDomainDirtyRateInfoPtr is a pointer to a virDomainDirtyRateInfo 
structure.
+ */
+
+typedef virDomainDirtyRateInfo *virDomainDirtyRateInfoPtr;
+
+int virDomainGetDirtyRateInfo(virDomainPtr domain,
+  virDomainDirtyRateInfoPtr info,
+  long long sec,
+  int flags);
+
 #endif /* LIBVIRT_DOMAIN_H */
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index bce0230..dc2aefa 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1387,6 +1387,12 @@ typedef char *
 (*virDrvDomainBackupGetXMLDesc)(virDomainPtr domain,
 unsigned int flags);
 
+typedef int
+(*virDrvDomainGetDirtyRateInfo)(virDomainPtr domain,
+virDomainDirtyRateInfoPtr info,
+long long sec,
+int flags);
+
 typedef struct _virHypervisorDriver virHypervisorDriver;
 typedef virHypervisorDriver *virHypervisorDriverPtr;
 
@@ -1650,4 +1656,5 @@ struct _virHypervisorDriver {
 virDrvDomainAgentSetResponseTimeout domainAgentSetResponseTimeout;
 virDrvDomainBackupBegin domainBackupBegin;
 virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc;
+virDrvDomainGetDirtyRateInfo domainGetDirtyRateInfo;
 };
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index ad60a92..c859296 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -12755,3 +12755,49 @@ virDomainBackupGetXMLDesc(virDomainPtr domain,
 virDispatchError(conn);
 return NULL;
 }
+
+
+/**
+ * virDomainGetDirtyRateInfo:
+ * @domain: a domain object.
+ * @info: return value of current domain's memory dirty rate info.
+ * @sec: show dirty rate within specified seconds.
+ * @flags: the flags of getdirtyrate action -- calculate and/or query.
+ *
+ * Get the current domain's memory dirty rate (in MB/s).
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainGetDirtyRateInfo(virDomainPtr domain,
+  virDomainDirtyRateInfoPtr info,
+  long long sec,
+  int flags)
+{
+virConnectPtr conn;
+
+VIR_DOMAIN_DEBUG(domain, "info = %p, seconds=%lld", info, sec);
+
+virResetLastError();
+
+virCheckDomainReturn(domain, -1);
+conn = domain->conn;
+
+virCheckNonNullArgGoto(info, error);
+virCheckReadOnlyGoto(conn->flags, error);
+
+if (info)
+memset(info, 0, sizeof(*info));
+
+if (conn->driver->domainGetDirtyRateInfo) {
+if (conn->driver->domainGetDirtyRateInfo(domain, info, sec, flags) < 0)
+goto error;
+VIR_DOMAIN_DEBUG(domain, "info = %p, seconds=%lld", info, sec);
+return 0;
+}
+
+virReportUnsupportedError();
+ error:
+virDispatchError(conn);
+return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 539d2e3..6c47894 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -873,4 +873,9 @@ LIBVIRT_6.0.0 {
 virDomainBackupGetXMLDesc;
 } LIBVIRT_5.10.0;
 
+LIBVIRT_6.9.0 {
+global:
+virDomainGetDirtyRateInfo;
+} LIBVIRT_6.0.0;
+
 #  define new API here using predicted next version number 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 268e457..40f1f0e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -23157,6 +23157,76 @@ qemuDomainAgentSetResponseTimeout(virDomainPtr dom,
 }
 
 
+#define MIN_DIRTYRATE_CALCULATION_PERIOD1/* 1s */
+#define MAX_DIRTYRATE_CALCULATION_PERIOD60   /* 60s */
+
+static int
+qemuDomainGetDirtyRateInfo(virDomainPtr dom,
+   virDomainDirtyRateInfoPtr info,
+   long long sec,
+   int flags)
+{
+virDomainObjPtr vm = NULL;
+virQEMUDriverPtr driver = dom->conn->privateData;
+int ret = -1;
+
+if (!(vm = qemuDomainObjFromDomain(dom)))
+return ret;
+
+if (virDomainGe

[PATCH v1 4/8] migration/dirtyrate: Implement qemuDomainQueryDirtyRate

2020-10-15 Thread Hao Wang
Implement qemuDomainQueryDirtyRate which query domain's memory dirty rate
using qmp "query-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_migration.c| 32 
 src/qemu/qemu_migration.h|  5 +
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 27 +++
 src/qemu/qemu_monitor_json.h |  4 
 6 files changed, 84 insertions(+)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 25b06ca..b2100d7 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5644,3 +5644,35 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
 virHashFree(blockinfo);
 return 0;
 }
+
+
+int
+qemuDomainQueryDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return ret;
+}
+
+priv = vm->privateData;
+
+if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_DIRTYRATE) < 
0)
+return ret;
+
+ret = qemuMonitorQueryDirtyRate(priv->mon, info);
+if (ret < 0) {
+virReportError(VIR_ERR_OPERATION_FAILED,
+   "%s", _("get vm's dirty rate failed."));
+}
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index b6f88d3..a80497d 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -255,3 +255,8 @@ qemuMigrationSrcFetchMirrorStats(virQEMUDriverPtr driver,
  virDomainObjPtr vm,
  qemuDomainAsyncJob asyncJob,
  qemuDomainJobInfoPtr jobInfo);
+
+int
+qemuDomainQueryDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 637361d..acbe4a6 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4635,3 +4635,15 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 return qemuMonitorJSONTransactionBackup(actions, device, jobname, target,
 bitmap, syncmode);
 }
+
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info)
+{
+VIR_DEBUG("info=%p", info);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONQueryDirtyRate(mon, info);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 1c1b0c9..cfb425a 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1435,3 +1435,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
  const char *target,
  const char *bitmap,
  qemuMonitorTransactionBackupSyncMode syncmode);
+
+int
+qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index d6beb44..6b5753d 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9463,3 +9463,30 @@ qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
 
 return 0;
 }
+
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+virJSONValuePtr data = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("query-dirty-rate", NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'return' data"));
+return -1;
+}
+
+return qemuMonitorJSONExtractDirtyRateInfo(data, info);
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 84fea25..5800e83 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -694,3 +694,7 @@ int qemuMonitorJSONSetDBusVMStateIdList(qemuMonitorPtr mon,
 int
 qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 bool *migratable);
+
+int
+qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
+  virDomainDirtyRateInfoPtr info);
-- 
2.23.0




[PATCH v1 2/8] migration/dirtyrate: Implement qemuMonitorJSONExtractDirtyRateInfo

2020-10-15 Thread Hao Wang
Implement qemuMonitorJSONExtractDirtyRateInfo to deal with the return from
qmp "query-dirty-rate", and store them in virDomainDirtyRateInfo.

Signed-off-by: Hao Wang 
Reviewed-by: Chuan Zheng 
---
 include/libvirt/libvirt-domain.h | 16 +++
 src/qemu/qemu_monitor_json.c | 48 
 2 files changed, 64 insertions(+)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 2d3847b..a4b5fcc 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -4999,6 +4999,22 @@ int virDomainBackupBegin(virDomainPtr domain,
 char *virDomainBackupGetXMLDesc(virDomainPtr domain,
 unsigned int flags);
 
+/**
+ * virDomainDirtyRateStatus:
+ *
+ * Details on the cause of a dirtyrate calculation status.
+ */
+
+typedef enum {
+VIR_DOMAIN_DIRTYRATE_UNSTARTED = 0, /* the dirtyrate calculation has not 
been started */
+VIR_DOMAIN_DIRTYRATE_MEASURING = 1, /* the dirtyrate calculation is 
measuring */
+VIR_DOMAIN_DIRTYRATE_MEASURED  = 2, /* the dirtyrate calculation is 
completed */
+
+# ifdef VIR_ENUM_SENTINELS
+VIR_DOMAIN_DIRTYRATE_LAST
+# endif
+} virDomainDirtyRateStatus;
+
 /**
  * virDomainDirtyRateInfo:
  *
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 83f169e..d6beb44 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9415,3 +9415,51 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 return virJSONValueGetBoolean(virJSONValueObjectGet(reply, "return"),
   migratable);
 }
+
+
+VIR_ENUM_DECL(qemuDomainDirtyRateStatus);
+VIR_ENUM_IMPL(qemuDomainDirtyRateStatus,
+  VIR_DOMAIN_DIRTYRATE_LAST,
+  "unstarted",
+  "measuring",
+  "measured");
+
+static int
+qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data,
+virDomainDirtyRateInfoPtr info)
+{
+const char *status;
+int statusID;
+
+if (!(status = virJSONValueObjectGetString(data, "status"))) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'status' data"));
+return -1;
+}
+
+if ((statusID = qemuDomainDirtyRateStatusTypeFromString(status)) < 0) {
+return -1;
+}
+info->status = statusID;
+
+if ((info->status == VIR_DOMAIN_DIRTYRATE_MEASURED) &&
+(virJSONValueObjectGetNumberLong(data, "dirty-rate", 
&(info->dirtyRate)) < 0)) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'dirty-rate' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "start-time", 
&(info->startTime)) < 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'start-time' 
data"));
+return -1;
+}
+
+if (virJSONValueObjectGetNumberLong(data, "calc-time", &(info->calcTime)) 
< 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("query-dirty-rate reply was missing 'calc-time' 
data"));
+return -1;
+}
+
+return 0;
+}
-- 
2.23.0




[PATCH v1 8/8] migration/dirtyrate: Introduce getdirtyrate virsh api

2020-10-15 Thread Hao Wang
Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 tools/virsh-domain.c | 112 +++
 1 file changed, 112 insertions(+)

diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 2eabc95..599222e 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -14312,6 +14312,112 @@ cmdGuestInfo(vshControl *ctl, const vshCmd *cmd)
 return ret;
 }
 
+/*
+ * "querydirtyrate" command
+ */
+static const vshCmdInfo info_getdirtyrate[] = {
+{.name = "help",
+ .data = N_("Get a vm's memory dirty rate")
+},
+{.name = "desc",
+ .data = N_("Get memory dirty rate of a domain in order to decide"
+" whether it's proper to be migrated out or not.")
+},
+{.name = NULL}
+};
+
+static const vshCmdOptDef opts_getdirtyrate[] = {
+VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+{.name = "seconds",
+ .type = VSH_OT_INT,
+ .help = N_("calculate memory dirty rate within specified seconds,"
+" a valid range of values is [1, 60], and would default to 
1s.")
+},
+{.name = "calculate",
+ .type = VSH_OT_BOOL,
+ .help = N_("calculate dirty rate only, can be used together with --query,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = "query",
+ .type = VSH_OT_BOOL,
+ .help = N_("query dirty rate only, can be used together with --calculate,"
+" either or both is expected, otherwise would default to 
both.")
+},
+{.name = NULL}
+};
+
+static bool
+cmdGetDirtyRateInfo(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom = NULL;
+virDomainDirtyRateInfo info;
+long long sec = 0;
+const char *status = NULL;
+unsigned int flags = 0;
+int rc;
+bool ret = false;
+bool calc = vshCommandOptBool(cmd, "calculate");
+bool query = vshCommandOptBool(cmd, "query");
+
+if (calc)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC;
+if (query)
+flags |= VIR_DOMAIN_DIRTYRATE_QUERY;
+
+/* if flag option is missing, default to both --calculate and --query */
+if (!calc && !query)
+flags |= VIR_DOMAIN_DIRTYRATE_CALC | VIR_DOMAIN_DIRTYRATE_QUERY;
+
+if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+rc = vshCommandOptLongLong(ctl, cmd, "seconds", );
+if (rc < 0)
+goto done;
+
+/* if --seconds option is missing, default to 1s */
+if (!rc)
+sec = 1;
+
+if (virDomainGetDirtyRateInfo(dom, , sec, flags) < 0) {
+vshError(ctl, "%s", _("Get memory dirty-rate failed."));
+goto done;
+}
+
+if (flags & VIR_DOMAIN_DIRTYRATE_QUERY) {
+switch (info.status) {
+case VIR_DOMAIN_DIRTYRATE_UNSTARTED:
+status = _("unstarted");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURING:
+status = _("measuring");
+break;
+case VIR_DOMAIN_DIRTYRATE_MEASURED:
+status = _("measured");
+break;
+default:
+status = _("unknown");
+}
+
+vshPrint(ctl, _("status:%s\n"), status);
+vshPrint(ctl, _("startTime: %lld\n"), info.startTime);
+vshPrint(ctl, _("calcTime:  %lld s\n"), info.calcTime);
+
+if (info.status == VIR_DOMAIN_DIRTYRATE_MEASURED)
+vshPrint(ctl, _("dirtyRate: %lld MB/s\n"), info.dirtyRate);
+else
+vshPrint(ctl, _("dirtyRate: the calculation is %s, please 
query results later\n"),
+ status);
+} else {
+vshPrint(ctl, _("Memory dirty rate is calculating, use --query option 
to display results.\n"));
+}
+
+ret = true;
+ done:
+virDomainFree(dom);
+return ret;
+}
+
 const vshCmdDef domManagementCmds[] = {
 {.name = "attach-device",
  .handler = cmdAttachDevice,
@@ -14939,5 +15045,11 @@ const vshCmdDef domManagementCmds[] = {
  .info = info_guestinfo,
  .flags = 0
 },
+{.name = "getdirtyrate",
+ .handler = cmdGetDirtyRateInfo,
+ .opts = opts_getdirtyrate,
+ .info = info_getdirtyrate,
+ .flags = 0
+},
 {.name = NULL}
 };
-- 
2.23.0




[PATCH v1 5/8] migration/dirtyrate: Implement qemuDomainCalculateDirtyRate

2020-10-15 Thread Hao Wang
Implement qemuDomainCalculateDirtyRate which calculates domain's memory
dirty rate using qmp "calc-dirty-rate".

Signed-off-by: Hao Wang 
Signed-off-by: Zhou Yimin 
Reviewed-by: Chuan Zheng 
---
 src/qemu/qemu_migration.c| 29 +
 src/qemu/qemu_migration.h|  5 +
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 22 ++
 src/qemu/qemu_monitor_json.h |  4 
 6 files changed, 76 insertions(+)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index b2100d7..aadf150 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5676,3 +5676,32 @@ qemuDomainQueryDirtyRate(virDomainPtr dom,
 
 return ret;
 }
+
+
+int
+qemuDomainCalculateDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ long long sec)
+{
+virQEMUDriverPtr driver = dom->conn->privateData;
+qemuDomainObjPrivatePtr priv;
+int ret = -1;
+
+if (!virDomainObjIsActive(vm)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   "%s", _("domain is not running"));
+return ret;
+}
+
+priv = vm->privateData;
+
+VIR_DEBUG("Calculate dirty rate during %lld seconds", sec);
+if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_DIRTYRATE) < 
0)
+return ret;
+
+ret = qemuMonitorCalculateDirtyRate(priv->mon, sec);
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ret = -1;
+
+return ret;
+}
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index a80497d..a7af869 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -260,3 +260,8 @@ int
 qemuDomainQueryDirtyRate(virDomainPtr dom,
  virDomainObjPtr vm,
  virDomainDirtyRateInfoPtr info);
+
+int
+qemuDomainCalculateDirtyRate(virDomainPtr dom,
+ virDomainObjPtr vm,
+ long long sec);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index acbe4a6..19f52e1 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4647,3 +4647,15 @@ qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
 
 return qemuMonitorJSONQueryDirtyRate(mon, info);
 }
+
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec)
+{
+VIR_DEBUG("seconds=%lld", sec);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONCalculateDirtyRate(mon, sec);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index cfb425a..b525448 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1439,3 +1439,7 @@ qemuMonitorTransactionBackup(virJSONValuePtr actions,
 int
 qemuMonitorQueryDirtyRate(qemuMonitorPtr mon,
   virDomainDirtyRateInfoPtr info);
+
+int
+qemuMonitorCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 6b5753d..e7a14bf 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -9490,3 +9490,25 @@ qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
 
 return qemuMonitorJSONExtractDirtyRateInfo(data, info);
 }
+
+
+int
+qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec)
+{
+g_autoptr(virJSONValue) cmd = NULL;
+g_autoptr(virJSONValue) reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("calc-dirty-rate",
+   "I:calc-time", (long)sec,
+   NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, ) < 0)
+return -1;
+
+if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+return -1;
+
+return 0;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 5800e83..d2118ee 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -698,3 +698,7 @@ qemuMonitorJSONGetCPUMigratable(qemuMonitorPtr mon,
 int
 qemuMonitorJSONQueryDirtyRate(qemuMonitorPtr mon,
   virDomainDirtyRateInfoPtr info);
+
+int
+qemuMonitorJSONCalculateDirtyRate(qemuMonitorPtr mon,
+  long long sec);
-- 
2.23.0




[PATCH] NVRAM: check NVRAM file size and recover from template

2020-08-08 Thread Hao Wang
From: Hao Wang 
Subject: [PATCH] NVRAM: check NVRAM file size and recover from template

A corrupted nvram file (e.g. caused by last unsuccessful creation due to
insufficient memory) can lead to boot or migration failure.
Check the size of the existed nvram file when qemuPrepareNVRAM, and re-create
if the existed one is unhealthy.

Signed-off-by: Hao Wang 
---
 src/qemu/qemu_process.c | 54 -
 1 file changed, 53 insertions(+), 1 deletion(-)

diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 126fabf5ef..42060bb36c 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4376,6 +4376,48 @@ qemuProcessUpdateCPU(virQEMUDriverPtr driver,
 }


+static bool
+qemuIsNvramFileHealthy(virQEMUDriverConfigPtr cfg,
+   virDomainLoaderDefPtr loader)
+{
+const char *masterNvramPath;
+off_t nvramSize;
+off_t masterSize;
+
+masterNvramPath = loader->templt;
+if (!loader->templt) {
+size_t i;
+for (i = 0; i < cfg->nfirmwares; i++) {
+if (STREQ(cfg->firmwares[i]->name, loader->path)) {
+masterNvramPath = cfg->firmwares[i]->nvram;
+break;
+}
+}
+}
+
+if (!masterNvramPath) {
+VIR_WARN("no nvram template is found; assume the nvram file is 
healthy");
+return true;
+}
+
+if ((nvramSize = virFileLength(loader->nvram, -1)) < 0 ||
+(masterSize = virFileLength(masterNvramPath, -1)) < 0) {
+virReportSystemError(errno,
+ _("unable to get the size of '%s' or '%s'"),
+ loader->nvram, masterNvramPath);
+return false;
+}
+
+if (nvramSize != masterSize) {
+VIR_WARN("the size(%zd) of the nvram file is not equal to that of the 
template %s",
+ nvramSize, masterNvramPath);
+return false;
+}
+
+return true;
+}
+
+
 static int
 qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg,
  virDomainObjPtr vm)
@@ -4388,9 +4430,19 @@ qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg,
 const char *master_nvram_path;
 ssize_t r;

-if (!loader || !loader->nvram || virFileExists(loader->nvram))
+if (!loader || !loader->nvram)
 return 0;

+if (virFileExists(loader->nvram)) {
+if (qemuIsNvramFileHealthy(cfg, loader))
+return 0;
+
+ignore_value(virFileRemove(loader->nvram, -1, -1));
+VIR_WARN("the nvram file %s exists but may be corrupted! "
+ "Remove it and try to copy a new one from template.",
+ loader->nvram);
+}
+
 master_nvram_path = loader->templt;
 if (!loader->templt) {
 size_t i;
--
2.23.0



[PATCH] doCoreDump: fix return value not expect as result

2020-08-08 Thread Hao Wang
From: Hao Wang 
Subject: [PATCH] doCoreDump: fix return value not expect as result

In a case that qemuDumpToFd() return zero while VIR_CLOSE(fd) fails,
codes will go to "cleanup" with "ret=0", resulting in unexpected return
value. Fix that.

Signed-off-by: Hao Wang 
---
 src/qemu/qemu_driver.c | 11 ++-
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0f98243fe4..8dfb9a38bf 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3796,6 +3796,7 @@ doCoreDump(virQEMUDriverPtr driver,
 {
 int fd = -1;
 int ret = -1;
+int rc = -1;
 virFileWrapperFdPtr wrapperFd = NULL;
 int directFlag = 0;
 unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
@@ -3843,8 +3844,8 @@ doCoreDump(virQEMUDriverPtr driver,
 if (STREQ(memory_dump_format, "elf"))
 memory_dump_format = NULL;

-ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP,
-   memory_dump_format);
+rc = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP,
+  memory_dump_format);
 } else {
 if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) {
 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
@@ -3856,11 +3857,11 @@ doCoreDump(virQEMUDriverPtr driver,
 if (!qemuMigrationSrcIsAllowed(driver, vm, false, 0))
 goto cleanup;

-ret = qemuMigrationSrcToFile(driver, vm, fd, compressor,
- QEMU_ASYNC_JOB_DUMP);
+rc = qemuMigrationSrcToFile(driver, vm, fd, compressor,
+QEMU_ASYNC_JOB_DUMP);
 }

-if (ret < 0)
+if (rc < 0)
 goto cleanup;

 if (VIR_CLOSE(fd) < 0) {
--
2.23.0



[PATCH] virNodeDevPCICapSRIOVVirtualParseXML: fix memleak of addr

2020-07-30 Thread Hao Wang
From: Hao Wang 
Subject: [PATCH] virNodeDevPCICapSRIOVVirtualParseXML: fix memleak of addr

virPCIDeviceAddressPtr 'addr' is forgotten to be freed in the branch
'VIR_APPEND_ELEMENT() < 0'. Use g_autoptr instead.

Signed-off-by: Hao Wang 
---
 src/conf/node_device_conf.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index c54015336a..2f63772917 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -1489,15 +1489,13 @@ virNodeDevPCICapSRIOVVirtualParseXML(xmlXPathContextPtr 
ctxt,
 goto cleanup;

 for (i = 0; i < naddresses; i++) {
-virPCIDeviceAddressPtr addr = NULL;
+g_autoptr(virPCIDeviceAddress) addr = NULL;

 if (VIR_ALLOC(addr) < 0)
 goto cleanup;

-if (virPCIDeviceAddressParseXML(addresses[i], addr) < 0) {
-VIR_FREE(addr);
+if (virPCIDeviceAddressParseXML(addresses[i], addr) < 0)
 goto cleanup;
-}

 if (VIR_APPEND_ELEMENT(pci_dev->virtual_functions,
pci_dev->num_virtual_functions,
--
2.23.0



[PATCH] client: fix memory leak in client msg

2020-07-23 Thread Hao Wang
>From 3ad3fae4f2562a11bef8dcdd25b6a7e0b00d4e2c Mon Sep 17 00:00:00 2001
From: Hao Wang 
Date: Sat, 18 Jul 2020 15:43:30 +0800
Subject: [PATCH] client: fix memory leak in client msg

When closing client->waitDispatch in virNetClientIOEventLoopRemoveAll
or virNetClientIOEventLoopRemoveDone, VIR_FREE() is called to free
call->msg directly, resulting in leak of the memory call->msg->buffer
points to.
Use virNetMessageFree(call->msg) instead of VIR_FREE(call->msg).

Signed-off-by: Hao Wang 
---
 src/rpc/virnetclient.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 441f1502a6..f899493b64 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -1519,7 +1519,7 @@ static bool 
virNetClientIOEventLoopRemoveDone(virNetClientCallPtr call,
 if (call->expectReply)
 VIR_WARN("Got a call expecting a reply but without a waiting 
thread");
 virCondDestroy(>cond);
-VIR_FREE(call->msg);
+virNetMessageFree(call->msg);
 VIR_FREE(call);
 }

@@ -1546,7 +1546,7 @@ virNetClientIOEventLoopRemoveAll(virNetClientCallPtr call,

 VIR_DEBUG("Removing call %p", call);
 virCondDestroy(>cond);
-VIR_FREE(call->msg);
+virNetMessageFree(call->msg);
 VIR_FREE(call);
 return true;
 }
--
2.23.0