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

Introduce virDomainDirtyRateInfo structure used for domain's memory dirty rate query. Signed-off-by: Hao Wang <wanghao232@huawei.com> Reviewed-by: Chuan Zheng <zhengchuan@huawei.com> --- 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

Implement qemuMonitorJSONExtractDirtyRateInfo to deal with the return from qmp "query-dirty-rate", and store them in virDomainDirtyRateInfo. Signed-off-by: Hao Wang <wanghao232@huawei.com> Reviewed-by: Chuan Zheng <zhengchuan@huawei.com> --- 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

Introduce dirty_rate async job for qemuDomainGetDirtyRateInfo. Signed-off-by: Hao Wang <wanghao232@huawei.com> Reviewed-by: Chuan Zheng <zhengchuan@huawei.com> --- 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

On Thu, Oct 15, 2020 at 15:23:28 +0800, Hao Wang wrote:
Introduce dirty_rate async job for qemuDomainGetDirtyRateInfo.
Signed-off-by: Hao Wang <wanghao232@huawei.com> Reviewed-by: Chuan Zheng <zhengchuan@huawei.com> --- 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,
IMO making this a domain job will limit usefullnes of the API. domain jobs are mutually exclusive, so you can't really use them together with migration, where this would make the most sense to query. Could you elaborate why you've decided to use a domain job for this? If the only reason is that there's a domain job stats gathering API IMO it should not be used as the main reason.

On 2020/10/15 18:22, Peter Krempa wrote:
On Thu, Oct 15, 2020 at 15:23:28 +0800, Hao Wang wrote:
Introduce dirty_rate async job for qemuDomainGetDirtyRateInfo.
Signed-off-by: Hao Wang <wanghao232@huawei.com> Reviewed-by: Chuan Zheng <zhengchuan@huawei.com> --- 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,
IMO making this a domain job will limit usefullnes of the API. domain jobs are mutually exclusive, so you can't really use them together with migration, where this would make the most sense to query.
Could you elaborate why you've decided to use a domain job for this? If the only reason is that there's a domain job stats gathering API IMO it should not be used as the main reason.
Hi, Peter. Yes, I agree with you. The reason why we use a domain job is that it is really mutually exclusive with migration because we simulate log-sync like migration does in our first qemu edition. Now there should be no restrict for that anymore:)
.
-- Regards. Chuan

Implement qemuDomainQueryDirtyRate which query domain's memory dirty rate using qmp "query-dirty-rate". Signed-off-by: Hao Wang <wanghao232@huawei.com> Signed-off-by: Zhou Yimin <zhouyimin@huawei.com> Reviewed-by: Chuan Zheng <zhengchuan@huawei.com> --- 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, &reply) < 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

Implement qemuDomainCalculateDirtyRate which calculates domain's memory dirty rate using qmp "calc-dirty-rate". Signed-off-by: Hao Wang <wanghao232@huawei.com> Signed-off-by: Zhou Yimin <zhouyimin@huawei.com> Reviewed-by: Chuan Zheng <zhengchuan@huawei.com> --- 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, &reply) < 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

Introduce virDomainDirtyRateFlags for DomainGetDirtyRateInfo API. Signed-off-by: Hao Wang <wanghao232@huawei.com> Reviewed-by: Chuan Zheng <zhengchuan@huawei.com> --- 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

Introduce DomainGetDirtyRateInfo API for domain's memory dirty rate calculation and query. Signed-off-by: Hao Wang <wanghao232@huawei.com> Signed-off-by: Zhou Yimin <zhouyimin@huawei.com> Reviewed-by: Chuan Zheng <zhengchuan@huawei.com> --- 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_PERIOD 1 /* 1s */ +#define MAX_DIRTYRATE_CALCULATION_PERIOD 60 /* 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 (virDomainGetDirtyRateInfoEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (qemuDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_DIRTYRATE, + VIR_DOMAIN_JOB_OPERATION_DIRTYRATE, 0) < 0) + goto cleanup; + + qemuDomainObjSetAsyncJobMask(vm, (QEMU_JOB_DEFAULT_MASK | + JOB_MASK(QEMU_JOB_SUSPEND))); + + 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(&ts, 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: + qemuDomainObjEndAsyncJob(driver, vm); + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + + static virHypervisorDriver qemuHypervisorDriver = { .name = QEMU_DRIVER_NAME, .connectURIProbe = qemuConnectURIProbe, @@ -23396,6 +23466,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainAgentSetResponseTimeout = qemuDomainAgentSetResponseTimeout, /* 5.10.0 */ .domainBackupBegin = qemuDomainBackupBegin, /* 6.0.0 */ .domainBackupGetXMLDesc = qemuDomainBackupGetXMLDesc, /* 6.0.0 */ + .domainGetDirtyRateInfo = qemuDomainGetDirtyRateInfo, /* 6.9.0 */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 653c684..9bfa127 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8684,6 +8684,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 d439368..506b79b 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3771,6 +3771,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 sec; + int flags; +}; + +struct remote_domain_get_dirty_rate_info_ret { /* insert@1 */ + int status; + hyper dirtyRate; + hyper startTime; + hyper calcTime; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -6664,5 +6677,11 @@ enum remote_procedure { * @priority: high * @acl: domain:read */ - REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC = 422 + REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC = 422, + + /** + * @generate: both + * @acl: domain:read + */ + REMOTE_PROC_DOMAIN_GET_DIRTY_RATE_INFO = 423 }; -- 2.23.0

Signed-off-by: Hao Wang <wanghao232@huawei.com> Signed-off-by: Zhou Yimin <zhouyimin@huawei.com> Reviewed-by: Chuan Zheng <zhengchuan@huawei.com> --- 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", &sec); + if (rc < 0) + goto done; + + /* if --seconds option is missing, default to 1s */ + if (!rc) + sec = 1; + + if (virDomainGetDirtyRateInfo(dom, &info, 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
participants (3)
-
Hao Wang
-
Peter Krempa
-
Zheng Chuan