On Tue, Aug 02, 2022 at 10:13:40PM +0800, ~hyman wrote: > From: Hyman Huang(黄勇) <yong.huang@xxxxxxxxxx> > > Introduce virDomainSetVcpuDirtyLimit API to set or cancel the > dirty page rate upper limit. > > The API will throttle the virtual CPU as needed to keep their dirty > page rate within the limit. Since it just throttles the virtual CPU, > which dirties memory, read processes in the guest OS aren't penalized. > > The feature therefor could, in some scenes, be used to provide > quality-of-service in the aspect of the memory workload for virtual > CPUs. > > Signed-off-by: Hyman Huang(黄勇) <yong.huang@xxxxxxxxxx> > --- > include/libvirt/libvirt-domain.h | 4 +++ > src/driver-hypervisor.h | 7 ++++ > src/libvirt-domain.c | 59 ++++++++++++++++++++++++++++++++ > src/libvirt_public.syms | 1 + > src/remote/remote_driver.c | 1 + > src/remote/remote_protocol.x | 18 +++++++++- > src/remote_protocol-structs | 7 ++++ > 7 files changed, 96 insertions(+), 1 deletion(-) > > diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h > index a1902546bb..3d3c7cdcba 100644 > --- a/include/libvirt/libvirt-domain.h > +++ b/include/libvirt/libvirt-domain.h > @@ -6506,4 +6506,8 @@ int virDomainFDAssociate(virDomainPtr domain, > int *fds, > unsigned int flags); > > +int virDomainSetVcpuDirtyLimit(virDomainPtr domain, > + int vcpu, > + unsigned long long rate, > + unsigned int flags); We've generally tried to avoid adding single purpose APIs for tunable parameters, instead using APIs with virTypedParameter arrays to allow bulk updates. I note that we don't appear to have any mechanism currently to set the VCPU scheduler tunables either Perhaps we should have a more general virDomainSetVCPUTuneParameters(virDomainPtr domain, int vcpu, virTypedParameterPtr params, unsigned int params, unsigned int flags); > #endif /* LIBVIRT_DOMAIN_H */ > diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h > index 5219344b72..e61b9efca5 100644 > --- a/src/driver-hypervisor.h > +++ b/src/driver-hypervisor.h > @@ -1448,6 +1448,12 @@ typedef int > int *fds, > unsigned int flags); > > +typedef int > +(*virDrvDomainSetVcpuDirtyLimit)(virDomainPtr domain, > + int vcpu, > + unsigned long long rate, > + unsigned int flags); > + > typedef struct _virHypervisorDriver virHypervisorDriver; > > /** > @@ -1720,4 +1726,5 @@ struct _virHypervisorDriver { > virDrvDomainGetMessages domainGetMessages; > virDrvDomainStartDirtyRateCalc domainStartDirtyRateCalc; > virDrvDomainFDAssociate domainFDAssociate; > + virDrvDomainSetVcpuDirtyLimit domainSetVcpuDirtyLimit; > }; > diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c > index 6616294fc1..5b505cc519 100644 > --- a/src/libvirt-domain.c > +++ b/src/libvirt-domain.c > @@ -14041,3 +14041,62 @@ virDomainFDAssociate(virDomainPtr domain, > virDispatchError(conn); > return -1; > } > + > +/** > + * virDomainSetVcpuDirtyLimit: > + * @domain: pointer to domain object > + * @vcpu: index of the limited virtual CPU > + * @rate: upper limit of dirty page rate (mebibyte/s) for virtual CPUs > + * @flags: bitwise-OR of virDomainModificationImpact > + * > + * Dynamically set the dirty page rate upper limit for the virtual CPUs. > + * > + * @vcpu may be a positive value, zero, or equal to -1. If -1 is set, > + * the change affects all virtual CPUs of VM; it affects the specified > + * virtual CPU otherwise. > + * @rate may be 0 to cancel the limit or a positive value to enable. The > + * hypervisors are free to round it down to the nearest mebibyte/s. > + * > + * The API will throttle the virtual CPU as needed to keep their dirty > + * page rate within the limit set by @rate. Since it just throttles the > + * virtual CPU, which dirties memory, read processes in the guest OS > + * aren't penalized. This could, in some scenes, be used to provide > + * quality-of-service in the aspect of the memory workload for virtual > + * CPUs. > + * > + * Returns 0 in case of success, -1 in case of failure. > + * > + * Since: 9.7.0 > + */ > +int > +virDomainSetVcpuDirtyLimit(virDomainPtr domain, > + int vcpu, > + unsigned long long rate, > + unsigned int flags) > +{ > + virConnectPtr conn; > + > + VIR_DOMAIN_DEBUG(domain, "vcpu=%d, rate=%llu, flags=0x%x", > + vcpu, rate, flags); > + > + virResetLastError(); > + > + virCheckDomainReturn(domain, -1); > + conn = domain->conn; > + > + virCheckReadOnlyGoto(conn->flags, error); > + > + if (conn->driver->domainSetVcpuDirtyLimit) { > + int ret; > + ret = conn->driver->domainSetVcpuDirtyLimit(domain, vcpu, rate, flags); > + if (ret < 0) > + goto error; > + return ret; > + } > + > + virReportUnsupportedError(); > + > + error: > + virDispatchError(domain->conn); > + return -1; > +} > diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms > index bd1e916d2a..602494935d 100644 > --- a/src/libvirt_public.syms > +++ b/src/libvirt_public.syms > @@ -934,6 +934,7 @@ LIBVIRT_9.0.0 { > > LIBVIRT_9.7.0 { > global: > + virDomainSetVcpuDirtyLimit; > virNetworkGetMetadata; > virNetworkSetMetadata; > } LIBVIRT_9.0.0; > diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c > index 0b925f8edc..15d023154b 100644 > --- a/src/remote/remote_driver.c > +++ b/src/remote/remote_driver.c > @@ -8110,6 +8110,7 @@ static virHypervisorDriver hypervisor_driver = { > .domainStartDirtyRateCalc = remoteDomainStartDirtyRateCalc, /* 7.2.0 */ > .domainSetLaunchSecurityState = remoteDomainSetLaunchSecurityState, /* 8.0.0 */ > .domainFDAssociate = remoteDomainFDAssociate, /* 9.0.0 */ > + .domainSetVcpuDirtyLimit = remoteDomainSetVcpuDirtyLimit, /* 9.7.0 */ > }; > > static virNetworkDriver network_driver = { > diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x > index 7ff059e393..72b2684912 100644 > --- a/src/remote/remote_protocol.x > +++ b/src/remote/remote_protocol.x > @@ -3955,6 +3955,14 @@ struct remote_domain_fd_associate_args { > remote_nonnull_string name; > unsigned int flags; > }; > + > +struct remote_domain_set_vcpu_dirty_limit_args { > + remote_nonnull_domain dom; > + int vcpu; > + unsigned hyper rate; > + unsigned int flags; > +}; > + > /*----- Protocol. -----*/ > > /* Define the program number, protocol version and procedure numbers here. */ > @@ -7008,5 +7016,13 @@ enum remote_procedure { > * @generate: both > * @acl: network:read > */ > - REMOTE_PROC_NETWORK_GET_METADATA = 445 > + REMOTE_PROC_NETWORK_GET_METADATA = 445, > + > + /** > + * @generate: both > + * @acl: domain:write > + * @acl: domain:save:!VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE > + * @acl: domain:save:VIR_DOMAIN_AFFECT_CONFIG > + */ > + REMOTE_PROC_DOMAIN_SET_VCPU_DIRTY_LIMIT = 446 > }; > diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs > index c07e0af1e6..715a121f36 100644 > --- a/src/remote_protocol-structs > +++ b/src/remote_protocol-structs > @@ -3290,6 +3290,12 @@ struct remote_domain_fd_associate_args { > remote_nonnull_string name; > u_int flags; > }; > +struct remote_domain_set_vcpu_dirty_limit_args { > + remote_nonnull_domain dom; > + int vcpu; > + uint64_t rate; > + u_int flags; > +}; > enum remote_procedure { > REMOTE_PROC_CONNECT_OPEN = 1, > REMOTE_PROC_CONNECT_CLOSE = 2, > @@ -3736,4 +3742,5 @@ enum remote_procedure { > REMOTE_PROC_DOMAIN_FD_ASSOCIATE = 443, > REMOTE_PROC_NETWORK_SET_METADATA = 444, > REMOTE_PROC_NETWORK_GET_METADATA = 445, > + REMOTE_PROC_DOMAIN_SET_VCPU_DIRTY_LIMIT = 446, > }; > -- > 2.38.5 > With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|