[libvirt] [PATCH 0/6 v2] New APIs to get/set node memory parameters

v1: https://www.redhat.com/archives/libvir-list/2012-September/msg00517.html v1 - v2: * Rename virNode{Get,Set}SharedMemoryParameters to virNode{Get,Set}MemoryParameters, in case of we could add more node memory tunables in future. As a result of RFC: https://www.redhat.com/archives/libvir-list/2012-August/msg01998.html, this adds two new APIs (virNode{Get,Set}MemoryParameters) to get and set the host shared memory tunables (ksm under linux). Osier Yang (6): node_memory: Define the APIs to get/set shared memory parameters node_memory: Wire up the RPC protocol node_memory: Implement the internal APIs node_memory: Support get/set memory parameters for drivers node_memory: Expose the APIs to virsh node_memory: Expose the APIs to Python bindings daemon/remote.c | 59 +++++++ include/libvirt/libvirt.h.in | 63 ++++++++ python/generator.py | 2 + python/libvirt-override-api.xml | 13 ++ python/libvirt-override.c | 125 +++++++++++++++ src/driver.h | 14 ++ src/libvirt.c | 121 ++++++++++++++ src/libvirt_private.syms | 2 + src/libvirt_public.syms | 2 + src/lxc/lxc_driver.c | 2 + src/nodeinfo.c | 332 +++++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 10 ++ src/qemu/qemu_driver.c | 2 + src/remote/remote_driver.c | 50 ++++++ src/remote/remote_protocol.x | 24 +++- src/remote_protocol-structs | 20 +++ src/rpc/gendispatch.pl | 3 + src/uml/uml_driver.c | 2 + src/xen/xen_driver.c | 3 + tools/virsh-host.c | 116 ++++++++++++++ tools/virsh.pod | 8 + 21 files changed, 972 insertions(+), 1 deletions(-) -- 1.7.7.3

* include/libvirt/libvirt.h.in: (Add macros for the param fields, declare the APIs). * src/driver.h: (New methods for the driver struct) * src/libvirt.c: (Implement the public APIs) * src/libvirt_public.syms: (Export the public symbols) --- include/libvirt/libvirt.h.in | 63 ++++++++++++++++++++++ python/generator.py | 2 + src/driver.h | 14 +++++ src/libvirt.c | 121 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 2 + 5 files changed, 202 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index ca04f6c..5a26474 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4305,6 +4305,69 @@ typedef struct _virTypedParameter virMemoryParameter; */ typedef virMemoryParameter *virMemoryParameterPtr; +/* + * VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN: + * + * Macro for typed parameter that represents how many present pages + * to scan before the shared memory service goes to sleep. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN "pages_to_scan" + +/* + * VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS: + * + * Macro for typed parameter that represents how many milliseconds + * the shared memory service should sleep before next scan. + */ +# define VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS "sleep_millisecs" + +/* + * VIR_NODE_MEMORY_SHARED_PAGES_SHARED: + * + * Macro for typed parameter that represents how many the shared + * mmeory pages are being used. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_SHARED "pages_shared" + +/* + * VIR_NODE_MEMORY_SHARED_PAGES_SHARING: + * + * Macro for typed parameter that represents how many sites are + * sharing the pages i.e. how much saved. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_SHARING "pages_sharing" + +/* VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED: + * + * Macro for typed parameter that represents how many pages unique + * but repeatedly checked for merging. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED "pages_unshared" + +/* VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE: + * + * Macro for typed parameter that represents how many pages changing + * too fast to be placed in a tree. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE "pages_volatile" + +/* VIR_NODE_MEMORY_SHARED_FULL_SCAN: + * + * Macro for typed parameter that represents how many times all + * mergeable areas have been scanned. + */ +# define VIR_NODE_MEMORY_SHARED_FULL_SCANS "full_scans" + +int virNodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +int virNodeSetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/python/generator.py b/python/generator.py index 8f6e455..8a73a9f 100755 --- a/python/generator.py +++ b/python/generator.py @@ -427,6 +427,8 @@ skip_impl = ( 'virDomainGetDiskErrors', 'virConnectUnregisterCloseCallback', 'virConnectRegisterCloseCallback', + 'virNodeGetMemoryParameters', + 'virNodeSetMemoryParameters', ) qemu_skip_impl = ( diff --git a/src/driver.h b/src/driver.h index 518e9d4..0eae601 100644 --- a/src/driver.h +++ b/src/driver.h @@ -882,6 +882,18 @@ typedef char * const char *uri, unsigned int flags); +typedef int + (*virDrvNodeGetMemoryParameters)(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +typedef int + (*virDrvNodeSetMemoryParameters)(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + /** * _virDriver: * @@ -1068,6 +1080,8 @@ struct _virDriver { virDrvDomainGetDiskErrors domainGetDiskErrors; virDrvDomainSetMetadata domainSetMetadata; virDrvDomainGetMetadata domainGetMetadata; + virDrvNodeGetMemoryParameters nodeGetMemoryParameters; + virDrvNodeSetMemoryParameters nodeSetMemoryParameters; }; typedef int diff --git a/src/libvirt.c b/src/libvirt.c index 6e25baf..d451ec8 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -6720,6 +6720,127 @@ error: return -1; } +/* + * virNodeGetMemoryParameters: + * @conn: pointer to the hypervisor connection + * @params: pointer to memory parameter object + * (return value, allocated by the caller) + * @nparams: pointer to number of memory parameters; input and output + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Get all node memory parameters. On input, @nparams gives the size + * of the @params array; on output, @nparams gives how many slots were + * filled with parameter information, which might be less but will + * not exceed the input value. + * + * As a special case, calling with @params as NULL and @nparams as 0 on + * input will cause @nparams on output to contain the number of parameters + * supported by the hypervisor. The caller should then allocate @params + * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API + * again. See virDomainGetMemoryParameters() for an equivalent usage + * example. + * + * Returns 0 in case of success, and -1 in case of failure. + */ +int +virNodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, params=%p, nparams=%p, flags=%x", + conn, params, nparams, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + virCheckNonNullArgGoto(nparams, error); + virCheckNonNegativeArgGoto(*nparams, error); + if (*nparams != 0) + virCheckNonNullArgGoto(params, error); + + if (VIR_DRV_SUPPORTS_FEATURE(conn->driver, conn, + VIR_DRV_FEATURE_TYPED_PARAM_STRING)) + flags |= VIR_TYPED_PARAM_STRING_OKAY; + + if (conn->driver->nodeGetMemoryParameters) { + int ret; + ret = conn->driver->nodeGetMemoryParameters(conn, params, + nparams, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/* + * virNodeSetMemoryParameters: + * @conn: pointer to the hypervisor connection + * @params: pointer to scheduler parameter objects + * @nparams: number of scheduler parameter objects + * (this value can be the same or less than the returned + * value nparams of virDomainGetSchedulerType) + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Change all or a subset of the node memory tunables. + * This function may require privileged access to the hypervisor. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virNodeSetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, params=%p, nparams=%d, flags=%x", + conn, params, nparams, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + virCheckNonNullArgGoto(params, error); + virCheckNonNegativeArgGoto(nparams, error); + + if (virTypedParameterValidateSet(conn, params, nparams) < 0) + goto error; + + if (conn->driver->nodeSetMemoryParameters) { + int ret; + ret = conn->driver->nodeSetMemoryParameters(conn, params, + nparams, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} /** * virDomainGetSchedulerType: diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 8dda48b..7ec1177 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -559,6 +559,8 @@ LIBVIRT_0.10.2 { virConnectListAllInterfaces; virConnectListAllNetworks; virConnectListAllStoragePools; + virNodeGetMemoryParameters; + virNodeSetMemoryParameters; virStoragePoolListAllVolumes; } LIBVIRT_0.10.0; -- 1.7.7.3

On Fri, Sep 14, 2012 at 02:42:15PM +0800, Osier Yang wrote:
* include/libvirt/libvirt.h.in: (Add macros for the param fields, declare the APIs). * src/driver.h: (New methods for the driver struct) * src/libvirt.c: (Implement the public APIs) * src/libvirt_public.syms: (Export the public symbols) --- include/libvirt/libvirt.h.in | 63 ++++++++++++++++++++++ python/generator.py | 2 + src/driver.h | 14 +++++ src/libvirt.c | 121 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 2 + 5 files changed, 202 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index ca04f6c..5a26474 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4305,6 +4305,69 @@ typedef struct _virTypedParameter virMemoryParameter; */ typedef virMemoryParameter *virMemoryParameterPtr;
+/* + * VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN: + * + * Macro for typed parameter that represents how many present pages + * to scan before the shared memory service goes to sleep. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN "pages_to_scan"
Hum, now that the API is generic and not just for shared memory maybe the string need to be made more specific, for example "pages_shared" as a general node memory information would not be the data about the memory tuning of KSM, it would be expected to be something else. I suggest to prefix all those propertes with "shm" for shared memory: "shm_pages_to_scan"
+/* + * VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS: + * + * Macro for typed parameter that represents how many milliseconds + * the shared memory service should sleep before next scan. + */ +# define VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS "sleep_millisecs"
"shm_sleep_millisecs"
+/* + * VIR_NODE_MEMORY_SHARED_PAGES_SHARED: + * + * Macro for typed parameter that represents how many the shared + * mmeory pages are being used. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_SHARED "pages_shared"
"shm_pages_shared"
+/* + * VIR_NODE_MEMORY_SHARED_PAGES_SHARING: + * + * Macro for typed parameter that represents how many sites are + * sharing the pages i.e. how much saved. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_SHARING "pages_sharing"
"shm_pages_sharing"
+/* VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED: + * + * Macro for typed parameter that represents how many pages unique + * but repeatedly checked for merging. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED "pages_unshared"
idem
+/* VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE: + * + * Macro for typed parameter that represents how many pages changing + * too fast to be placed in a tree. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE "pages_volatile"
idem
+/* VIR_NODE_MEMORY_SHARED_FULL_SCAN: + * + * Macro for typed parameter that represents how many times all + * mergeable areas have been scanned. + */ +# define VIR_NODE_MEMORY_SHARED_FULL_SCANS "full_scans"
idem
+int virNodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +int virNodeSetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/python/generator.py b/python/generator.py index 8f6e455..8a73a9f 100755 --- a/python/generator.py +++ b/python/generator.py @@ -427,6 +427,8 @@ skip_impl = ( 'virDomainGetDiskErrors', 'virConnectUnregisterCloseCallback', 'virConnectRegisterCloseCallback', + 'virNodeGetMemoryParameters', + 'virNodeSetMemoryParameters', )
qemu_skip_impl = ( diff --git a/src/driver.h b/src/driver.h index 518e9d4..0eae601 100644 --- a/src/driver.h +++ b/src/driver.h @@ -882,6 +882,18 @@ typedef char * const char *uri, unsigned int flags);
+typedef int + (*virDrvNodeGetMemoryParameters)(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +typedef int + (*virDrvNodeSetMemoryParameters)(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + /** * _virDriver: * @@ -1068,6 +1080,8 @@ struct _virDriver { virDrvDomainGetDiskErrors domainGetDiskErrors; virDrvDomainSetMetadata domainSetMetadata; virDrvDomainGetMetadata domainGetMetadata; + virDrvNodeGetMemoryParameters nodeGetMemoryParameters; + virDrvNodeSetMemoryParameters nodeSetMemoryParameters; };
typedef int diff --git a/src/libvirt.c b/src/libvirt.c index 6e25baf..d451ec8 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -6720,6 +6720,127 @@ error: return -1; }
+/* + * virNodeGetMemoryParameters: + * @conn: pointer to the hypervisor connection + * @params: pointer to memory parameter object + * (return value, allocated by the caller) + * @nparams: pointer to number of memory parameters; input and output + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Get all node memory parameters. On input, @nparams gives the size + * of the @params array; on output, @nparams gives how many slots were + * filled with parameter information, which might be less but will + * not exceed the input value. + * + * As a special case, calling with @params as NULL and @nparams as 0 on + * input will cause @nparams on output to contain the number of parameters + * supported by the hypervisor. The caller should then allocate @params + * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API + * again. See virDomainGetMemoryParameters() for an equivalent usage + * example. + * + * Returns 0 in case of success, and -1 in case of failure. + */ +int +virNodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, params=%p, nparams=%p, flags=%x", + conn, params, nparams, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + virCheckNonNullArgGoto(nparams, error); + virCheckNonNegativeArgGoto(*nparams, error); + if (*nparams != 0) + virCheckNonNullArgGoto(params, error); + + if (VIR_DRV_SUPPORTS_FEATURE(conn->driver, conn, + VIR_DRV_FEATURE_TYPED_PARAM_STRING)) + flags |= VIR_TYPED_PARAM_STRING_OKAY; + + if (conn->driver->nodeGetMemoryParameters) { + int ret; + ret = conn->driver->nodeGetMemoryParameters(conn, params, + nparams, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/* + * virNodeSetMemoryParameters: + * @conn: pointer to the hypervisor connection + * @params: pointer to scheduler parameter objects + * @nparams: number of scheduler parameter objects + * (this value can be the same or less than the returned + * value nparams of virDomainGetSchedulerType) + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Change all or a subset of the node memory tunables. + * This function may require privileged access to the hypervisor. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virNodeSetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, params=%p, nparams=%d, flags=%x", + conn, params, nparams, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + virCheckNonNullArgGoto(params, error); + virCheckNonNegativeArgGoto(nparams, error); + + if (virTypedParameterValidateSet(conn, params, nparams) < 0) + goto error; + + if (conn->driver->nodeSetMemoryParameters) { + int ret; + ret = conn->driver->nodeSetMemoryParameters(conn, params, + nparams, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +}
/** * virDomainGetSchedulerType: diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 8dda48b..7ec1177 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -559,6 +559,8 @@ LIBVIRT_0.10.2 { virConnectListAllInterfaces; virConnectListAllNetworks; virConnectListAllStoragePools; + virNodeGetMemoryParameters; + virNodeSetMemoryParameters; virStoragePoolListAllVolumes; } LIBVIRT_0.10.0;
Otherwise looks fine to me, ACK with the parameter name change as suggested. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On 2012年09月14日 15:20, Daniel Veillard wrote:
On Fri, Sep 14, 2012 at 02:42:15PM +0800, Osier Yang wrote:
* include/libvirt/libvirt.h.in: (Add macros for the param fields, declare the APIs). * src/driver.h: (New methods for the driver struct) * src/libvirt.c: (Implement the public APIs) * src/libvirt_public.syms: (Export the public symbols) --- include/libvirt/libvirt.h.in | 63 ++++++++++++++++++++++ python/generator.py | 2 + src/driver.h | 14 +++++ src/libvirt.c | 121 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 2 + 5 files changed, 202 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index ca04f6c..5a26474 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4305,6 +4305,69 @@ typedef struct _virTypedParameter virMemoryParameter; */ typedef virMemoryParameter *virMemoryParameterPtr;
+/* + * VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN: + * + * Macro for typed parameter that represents how many present pages + * to scan before the shared memory service goes to sleep. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN "pages_to_scan"
Hum, now that the API is generic and not just for shared memory maybe the string need to be made more specific, for example "pages_shared" as a general node memory information would not be the data about the memory tuning of KSM, it would be expected to be something else. I suggest to prefix all those propertes with "shm" for shared memory:
"shm_pages_to_scan"
Okay, that's more sepcific, agreed. I will updated 3/6 soon. Thanks! Osier

* src/rpc/gendispatch.pl: (virNodeSetMemoryParameters is the the special one which needs a connection object as the first argument, improve the generator to support it). * daemon/remote.c: (Implement the server side handler for virDomainGetMemoryParameters) * src/remote/remote_driver.c: (Implement the client side handler for virDomainGetMemoryParameters) * src/remote/remote_protocol.x: (New RPC procedures for the two new APIs and structs to represent the args and ret for it) * src/remote_protocol-structs: Likewise --- daemon/remote.c | 59 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 50 +++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 24 ++++++++++++++++- src/remote_protocol-structs | 20 ++++++++++++++ src/rpc/gendispatch.pl | 3 ++ 5 files changed, 155 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 12cd25c..337acd8 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4321,6 +4321,65 @@ cleanup: return rv; } +static int +remoteDispatchNodeGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_node_get_memory_parameters_args *args, + remote_node_get_memory_parameters_ret *ret) +{ + virTypedParameterPtr params = NULL; + int nparams = args->nparams; + unsigned int flags; + int rv = -1; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + flags = args->flags; + + if (nparams > REMOTE_NODE_MEMORY_PARAMETERS_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large")); + goto cleanup; + } + if (nparams && VIR_ALLOC_N(params, nparams) < 0) { + virReportOOMError(); + goto cleanup; + } + + + if (virNodeGetMemoryParameters(priv->conn, params, &nparams, flags) < 0) + goto cleanup; + + /* In this case, we need to send back the number of parameters + * supported + */ + if (args->nparams == 0) { + ret->nparams = nparams; + goto success; + } + + if (remoteSerializeTypedParameters(params, nparams, + &ret->params.params_val, + &ret->params.params_len, + args->flags) < 0) + goto cleanup; + +success: + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + virTypedParameterArrayClear(params, nparams); + VIR_FREE(params); + return rv; +} /*----- Helpers. -----*/ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index f47b06c..c16fc4a 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -5510,6 +5510,54 @@ done: return rv; } +static int +remoteNodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + int rv = -1; + remote_node_get_memory_parameters_args args; + remote_node_get_memory_parameters_ret ret; + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + args.nparams = *nparams; + args.flags = flags; + + memset (&ret, 0, sizeof(ret)); + if (call (conn, priv, 0, REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS, + (xdrproc_t) xdr_remote_node_get_memory_parameters_args, (char *) &args, + (xdrproc_t) xdr_remote_node_get_memory_parameters_ret, (char *) &ret) == -1) + goto done; + + /* Handle the case when the caller does not know the number of parameters + * and is asking for the number of parameters supported + */ + if (*nparams == 0) { + *nparams = ret.nparams; + rv = 0; + goto cleanup; + } + + if (remoteDeserializeTypedParameters(ret.params.params_val, + ret.params.params_len, + REMOTE_NODE_MEMORY_PARAMETERS_MAX, + params, + nparams) < 0) + goto cleanup; + + rv = 0; + +cleanup: + xdr_free ((xdrproc_t) xdr_remote_node_get_memory_parameters_ret, + (char *) &ret); +done: + remoteDriverUnlock(priv); + return rv; +} + static void remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event) { @@ -5821,6 +5869,8 @@ static virDriver remote_driver = { .domainSetMetadata = remoteDomainSetMetadata, /* 0.9.10 */ .domainGetMetadata = remoteDomainGetMetadata, /* 0.9.10 */ .domainGetHostname = remoteDomainGetHostname, /* 0.10.0 */ + .nodeSetMemoryParameters = remoteNodeSetMemoryParameters, /* 0.10.2 */ + .nodeGetMemoryParameters = remoteNodeGetMemoryParameters, /* 0.10.2 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 54054af..c640f2f 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -229,6 +229,11 @@ const REMOTE_DOMAIN_GET_CPU_STATS_MAX = 2048; */ const REMOTE_DOMAIN_DISK_ERRORS_MAX = 256; +/* + * Upper limit on number of memory parameters + */ +const REMOTE_NODE_MEMORY_PARAMETERS_MAX = 16; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -2599,6 +2604,21 @@ struct remote_connect_list_all_interfaces_ret { unsigned int ret; }; +struct remote_node_set_memory_parameters_args { + remote_typed_param params<REMOTE_NODE_MEMORY_PARAMETERS_MAX>; + unsigned int flags; +}; + +struct remote_node_get_memory_parameters_args { + int nparams; + unsigned int flags; +}; + +struct remote_node_get_memory_parameters_ret { + remote_typed_param params<REMOTE_NODE_MEMORY_PARAMETERS_MAX>; + int nparams; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -2933,7 +2953,9 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 281, /* skipgen skipgen priority:high */ REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 282, /* skipgen skipgen priority:high */ REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 283, /* skipgen skipgen priority:high */ - REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 284 /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 284, /* skipgen skipgen priority:high */ + REMOTE_PROC_NODE_SET_MEMORY_PARAMETERS = 285, /* autogen autogen */ + REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS = 286 /* skipgen skipgen */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 2a33039..7fc3e25 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2056,6 +2056,24 @@ struct remote_connect_list_all_interfaces_ret { } ifaces; u_int ret; }; +struct remote_node_set_memory_parameters_args { + struct { + u_int params_len; + remote_typed_param * params_val; + } params; + u_int flags; +}; +struct remote_node_get_memory_parameters_args { + int nparams; + u_int flags; +}; +struct remote_node_get_memory_parameters_ret { + struct { + u_int params_len; + remote_typed_param * params_val; + } params; + int nparams; +}; enum remote_procedure { REMOTE_PROC_OPEN = 1, REMOTE_PROC_CLOSE = 2, @@ -2341,4 +2359,6 @@ enum remote_procedure { REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 282, REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 283, REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 284, + REMOTE_PROC_NODE_SET_MEMORY_PARAMETERS = 285, + REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS = 286, }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 12023e9..774977d 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -478,6 +478,9 @@ elsif ($opt_b) { } elsif ($args_member =~ m/^remote_typed_param (\S+)<(\S+)>;/) { push(@vars_list, "virTypedParameterPtr $1 = NULL"); push(@vars_list, "int n$1"); + if ($call->{ProcName} eq "NodeSetMemoryParameters") { + push(@args_list, "priv->conn"); + } push(@args_list, "$1"); push(@args_list, "n$1"); push(@getters_list, " if (($1 = remoteDeserializeTypedParameters(args->$1.$1_val,\n" . -- 1.7.7.3

On Fri, Sep 14, 2012 at 02:42:16PM +0800, Osier Yang wrote:
* src/rpc/gendispatch.pl: (virNodeSetMemoryParameters is the the special one which needs a connection object as the first argument, improve the generator to support it). * daemon/remote.c: (Implement the server side handler for virDomainGetMemoryParameters) * src/remote/remote_driver.c: (Implement the client side handler for virDomainGetMemoryParameters) * src/remote/remote_protocol.x: (New RPC procedures for the two new APIs and structs to represent the args and ret for it) * src/remote_protocol-structs: Likewise --- daemon/remote.c | 59 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 50 +++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 24 ++++++++++++++++- src/remote_protocol-structs | 20 ++++++++++++++ src/rpc/gendispatch.pl | 3 ++ 5 files changed, 155 insertions(+), 1 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c index 12cd25c..337acd8 100644 [...] --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -229,6 +229,11 @@ const REMOTE_DOMAIN_GET_CPU_STATS_MAX = 2048; */ const REMOTE_DOMAIN_DISK_ERRORS_MAX = 256;
+/* + * Upper limit on number of memory parameters + */ +const REMOTE_NODE_MEMORY_PARAMETERS_MAX = 16; +
Hum, it doesn't cost much to increase that a bit, on the other hand if we hit the limit raising it becomes a deployment problem. I would raise that arbitrarilly a bit higher (32 or 64) to avoid the issue in the long term.
/* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN];
Looks fine otehrwise, ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Only implemented for linux platform. * src/nodeinfo.h: (Declare node{Get,Set}MemoryParameters) * src/nodeinfo.c: (Implement node{Get,Set}MemoryParameters) * src/libvirt_private.syms: (Export those two new internal APIs to private symbols) --- src/libvirt_private.syms | 2 + src/nodeinfo.c | 332 ++++++++++++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 10 ++ 3 files changed, 344 insertions(+), 0 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8dfb4ce..23ea9fe 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -879,7 +879,9 @@ nodeGetCPUStats; nodeGetCellsFreeMemory; nodeGetFreeMemory; nodeGetInfo; +nodeGetMemoryParameters; nodeGetMemoryStats; +nodeSetMemoryParameters; # nwfilter_conf.h diff --git a/src/nodeinfo.c b/src/nodeinfo.c index e3d4a24..d50705e 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -48,6 +48,7 @@ #include "count-one-bits.h" #include "intprops.h" #include "virfile.h" +#include "virtypedparam.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -57,6 +58,7 @@ # define SYSFS_SYSTEM_PATH "/sys/devices/system" # define PROCSTAT_PATH "/proc/stat" # define MEMINFO_PATH "/proc/meminfo" +# define SYSFS_MEMORY_SHARED_PATH "/sys/kernel/mm/ksm" # define LINUX_NB_CPU_STATS 4 # define LINUX_NB_MEMORY_STATS_ALL 4 @@ -933,6 +935,336 @@ nodeGetCPUmap(virConnectPtr conn ATTRIBUTE_UNUSED, #endif } +int +nodeSetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virCheckFlags(0, -1); + +#ifdef __linux__ + { + int ret = 0; + int rc; + int i; + + if (virTypedParameterArrayValidate(params, nparams, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, + NULL) < 0) + return -1; + + for (i = 0; i < nparams; i++) { + virTypedParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN)) { + char *pages_to_scan = NULL; + char *strval = NULL; + + if (virAsprintf(&pages_to_scan, "%s/%s", + SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN) < 0) { + virReportOOMError(); + return -1; + } + + if (virAsprintf(&strval, "%u", param->value.ui) == -1) { + virReportOOMError(); + VIR_FREE(pages_to_scan); + return -1; + } + + if ((rc = virFileWriteStr(pages_to_scan, strval, 0)) < 0) { + virReportSystemError(-rc, "%s", + _("failed to set pages_to_scan")); + ret = -1; + } + VIR_FREE(pages_to_scan); + VIR_FREE(strval); + } else if (STREQ(param->field, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS)) { + char *sleep_millisecs = NULL; + char *strval = NULL; + + if (virAsprintf(&sleep_millisecs, "%s/%s", + SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS) < 0) { + virReportOOMError(); + return -1; + } + + if (virAsprintf(&strval, "%u", param->value.ui) == -1) { + virReportOOMError(); + VIR_FREE(sleep_millisecs); + return -1; + } + + if ((rc = virFileWriteStr(sleep_millisecs, strval, 0)) < 0) { + virReportSystemError(-rc, "%s", + _("failed to set pages_to_scan")); + ret = -1; + } + VIR_FREE(sleep_millisecs); + VIR_FREE(strval); + } + } + + return ret; + } +#else + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("node set memory parameters not implemented" + " on this platform")); + return -1; +#endif +} + +#define NODE_MEMORY_PARAMETERS_NUM 7 +int +nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + +#ifdef __linux__ + { + char *path = NULL; + char *buf = NULL; + unsigned int pages_to_scan; + unsigned int sleep_millisecs; + unsigned long long pages_shared; + unsigned long long pages_sharing; + unsigned long long pages_unshared; + unsigned long long pages_volatile; + unsigned long long full_scans = 0; + int ret = -1; + int i; + + if ((*nparams) == 0) { + *nparams = NODE_MEMORY_PARAMETERS_NUM; + return 0; + } + + for (i = 0; i < *nparams && i < NODE_MEMORY_PARAMETERS_NUM; i++) { + virTypedParameterPtr param = ¶ms[i]; + char *tmp = NULL; + + switch(i) { + case 0: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ui(buf, NULL, 10, &pages_to_scan) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_to_scan")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, pages_to_scan) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 1: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ui(buf, NULL, 10, &sleep_millisecs) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse sleep_millisecs")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, sleep_millisecs) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 2: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_SHARED) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_shared) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_shared")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARED, + VIR_TYPED_PARAM_ULLONG, pages_shared) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 3: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_SHARING) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_sharing) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_sharing")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARING, + VIR_TYPED_PARAM_ULLONG, pages_sharing) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 4: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_unshared) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_unshared")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED, + VIR_TYPED_PARAM_ULLONG, pages_unshared) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 5: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_volatile) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_volatile")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE, + VIR_TYPED_PARAM_ULLONG, pages_volatile) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 6: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_FULL_SCANS) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &full_scans) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse full_scans")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_FULL_SCANS, + VIR_TYPED_PARAM_ULLONG, full_scans) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + default: + break; + } + } + + ret = 0; + + cleanup: + VIR_FREE(path); + VIR_FREE(buf); + return ret; + } +#else + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("node get memory parameters not implemented" + " on this platform")); + return -1; +#endif +} + #if HAVE_NUMACTL # if LIBNUMA_API_VERSION <= 1 # define NUMA_MAX_N_CPUS 4096 diff --git a/src/nodeinfo.h b/src/nodeinfo.h index 12090e2..25ad0dd 100644 --- a/src/nodeinfo.h +++ b/src/nodeinfo.h @@ -49,4 +49,14 @@ unsigned long long nodeGetFreeMemory(virConnectPtr conn); char *nodeGetCPUmap(virConnectPtr conn, int *max_id, const char *mapname); + +int nodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +int nodeSetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); #endif /* __VIR_NODEINFO_H__*/ -- 1.7.7.3

On Fri, Sep 14, 2012 at 02:42:17PM +0800, Osier Yang wrote:
Only implemented for linux platform.
* src/nodeinfo.h: (Declare node{Get,Set}MemoryParameters) * src/nodeinfo.c: (Implement node{Get,Set}MemoryParameters) * src/libvirt_private.syms: (Export those two new internal APIs to private symbols) --- src/libvirt_private.syms | 2 + src/nodeinfo.c | 332 ++++++++++++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 10 ++ 3 files changed, 344 insertions(+), 0 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8dfb4ce..23ea9fe 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -879,7 +879,9 @@ nodeGetCPUStats; nodeGetCellsFreeMemory; nodeGetFreeMemory; nodeGetInfo; +nodeGetMemoryParameters; nodeGetMemoryStats; +nodeSetMemoryParameters;
# nwfilter_conf.h diff --git a/src/nodeinfo.c b/src/nodeinfo.c index e3d4a24..d50705e 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -48,6 +48,7 @@ #include "count-one-bits.h" #include "intprops.h" #include "virfile.h" +#include "virtypedparam.h"
#define VIR_FROM_THIS VIR_FROM_NONE @@ -57,6 +58,7 @@ # define SYSFS_SYSTEM_PATH "/sys/devices/system" # define PROCSTAT_PATH "/proc/stat" # define MEMINFO_PATH "/proc/meminfo" +# define SYSFS_MEMORY_SHARED_PATH "/sys/kernel/mm/ksm"
# define LINUX_NB_CPU_STATS 4 # define LINUX_NB_MEMORY_STATS_ALL 4 @@ -933,6 +935,336 @@ nodeGetCPUmap(virConnectPtr conn ATTRIBUTE_UNUSED, #endif }
+int +nodeSetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virCheckFlags(0, -1); + +#ifdef __linux__ + { + int ret = 0; + int rc; + int i; +
Hum, i'm not sure i like the extra indentation level just for the sake of making it easier to define local variables, especially as this function is already takink liberties with the 80 character wide formatting rule.
+ if (virTypedParameterArrayValidate(params, nparams, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, + NULL) < 0) + return -1; + + for (i = 0; i < nparams; i++) { + virTypedParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN)) { + char *pages_to_scan = NULL; + char *strval = NULL; + + if (virAsprintf(&pages_to_scan, "%s/%s", + SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN) < 0) {
Won't work here, you will have to use the strings directly since prefixed by "shm_', that will make for more compact code ! Maybe a couple of helper static functions instead of duplicating the code for each case would be nicer, and lead to code fitting in 80 columns.
+ virReportOOMError(); + return -1; + } + + if (virAsprintf(&strval, "%u", param->value.ui) == -1) { + virReportOOMError(); + VIR_FREE(pages_to_scan); + return -1; + } + + if ((rc = virFileWriteStr(pages_to_scan, strval, 0)) < 0) { + virReportSystemError(-rc, "%s", + _("failed to set pages_to_scan")); + ret = -1; + } + VIR_FREE(pages_to_scan); + VIR_FREE(strval); + } else if (STREQ(param->field, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS)) { + char *sleep_millisecs = NULL; + char *strval = NULL; + + if (virAsprintf(&sleep_millisecs, "%s/%s", + SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS) < 0) { + virReportOOMError(); + return -1; + } + + if (virAsprintf(&strval, "%u", param->value.ui) == -1) { + virReportOOMError(); + VIR_FREE(sleep_millisecs); + return -1; + } + + if ((rc = virFileWriteStr(sleep_millisecs, strval, 0)) < 0) { + virReportSystemError(-rc, "%s", + _("failed to set pages_to_scan")); + ret = -1; + } + VIR_FREE(sleep_millisecs); + VIR_FREE(strval); + } + } + + return ret; + } +#else + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("node set memory parameters not implemented" + " on this platform")); + return -1; +#endif +} + +#define NODE_MEMORY_PARAMETERS_NUM 7 +int +nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + +#ifdef __linux__ + { + char *path = NULL; + char *buf = NULL; + unsigned int pages_to_scan; + unsigned int sleep_millisecs; + unsigned long long pages_shared; + unsigned long long pages_sharing; + unsigned long long pages_unshared; + unsigned long long pages_volatile; + unsigned long long full_scans = 0; + int ret = -1; + int i; + + if ((*nparams) == 0) { + *nparams = NODE_MEMORY_PARAMETERS_NUM; + return 0; + } + + for (i = 0; i < *nparams && i < NODE_MEMORY_PARAMETERS_NUM; i++) { + virTypedParameterPtr param = ¶ms[i]; + char *tmp = NULL; + + switch(i) { + case 0: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ui(buf, NULL, 10, &pages_to_scan) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_to_scan")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, pages_to_scan) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 1: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ui(buf, NULL, 10, &sleep_millisecs) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse sleep_millisecs")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, sleep_millisecs) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 2: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_SHARED) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_shared) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_shared")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARED, + VIR_TYPED_PARAM_ULLONG, pages_shared) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 3: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_SHARING) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_sharing) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_sharing")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARING, + VIR_TYPED_PARAM_ULLONG, pages_sharing) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 4: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_unshared) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_unshared")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED, + VIR_TYPED_PARAM_ULLONG, pages_unshared) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 5: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_volatile) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_volatile")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE, + VIR_TYPED_PARAM_ULLONG, pages_volatile) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 6: + if (virAsprintf(&path, "%s/%s", SYSFS_MEMORY_SHARED_PATH, + VIR_NODE_MEMORY_SHARED_FULL_SCANS) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &full_scans) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse full_scans")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_FULL_SCANS, + VIR_TYPED_PARAM_ULLONG, full_scans) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + default: + break; + } + } + + ret = 0; + + cleanup: + VIR_FREE(path); + VIR_FREE(buf); + return ret; + } +#else + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("node get memory parameters not implemented" + " on this platform")); + return -1; +#endif +} + #if HAVE_NUMACTL # if LIBNUMA_API_VERSION <= 1 # define NUMA_MAX_N_CPUS 4096 diff --git a/src/nodeinfo.h b/src/nodeinfo.h index 12090e2..25ad0dd 100644 --- a/src/nodeinfo.h +++ b/src/nodeinfo.h @@ -49,4 +49,14 @@ unsigned long long nodeGetFreeMemory(virConnectPtr conn); char *nodeGetCPUmap(virConnectPtr conn, int *max_id, const char *mapname); + +int nodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +int nodeSetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); #endif /* __VIR_NODEINFO_H__*/
No fundamental disagreement, but this needs a bit of rework IMHO Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Including QEMU, LXC, UML, XEN drivers. --- src/lxc/lxc_driver.c | 2 ++ src/qemu/qemu_driver.c | 2 ++ src/uml/uml_driver.c | 2 ++ src/xen/xen_driver.c | 3 +++ 4 files changed, 9 insertions(+), 0 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index ff11c2c..62c36e6 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2748,6 +2748,8 @@ static virDriver lxcDriver = { .domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */ .isAlive = lxcIsAlive, /* 0.9.8 */ .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ }; static virStateDriver lxcStateDriver = { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d952c9c..8313612 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -14112,6 +14112,8 @@ static virDriver qemuDriver = { .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */ .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */ .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ }; diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 26877eb..72d1b0e 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2623,6 +2623,8 @@ static virDriver umlDriver = { .domainOpenConsole = umlDomainOpenConsole, /* 0.8.6 */ .isAlive = umlIsAlive, /* 0.9.8 */ .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ }; static virStateDriver umlStateDriver = { diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index d33737e..3a14d12 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -64,6 +64,7 @@ #include "viruri.h" #include "command.h" #include "virnodesuspend.h" +#include "nodeinfo.h" #define VIR_FROM_THIS VIR_FROM_XEN @@ -2269,6 +2270,8 @@ static virDriver xenUnifiedDriver = { .domainOpenConsole = xenUnifiedDomainOpenConsole, /* 0.8.6 */ .isAlive = xenUnifiedIsAlive, /* 0.9.8 */ .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ }; /** -- 1.7.7.3

On Fri, Sep 14, 2012 at 02:42:18PM +0800, Osier Yang wrote:
Including QEMU, LXC, UML, XEN drivers. --- src/lxc/lxc_driver.c | 2 ++ src/qemu/qemu_driver.c | 2 ++ src/uml/uml_driver.c | 2 ++ src/xen/xen_driver.c | 3 +++ 4 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index ff11c2c..62c36e6 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2748,6 +2748,8 @@ static virDriver lxcDriver = { .domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */ .isAlive = lxcIsAlive, /* 0.9.8 */ .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ };
static virStateDriver lxcStateDriver = { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d952c9c..8313612 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -14112,6 +14112,8 @@ static virDriver qemuDriver = { .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */ .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */ .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ };
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 26877eb..72d1b0e 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2623,6 +2623,8 @@ static virDriver umlDriver = { .domainOpenConsole = umlDomainOpenConsole, /* 0.8.6 */ .isAlive = umlIsAlive, /* 0.9.8 */ .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ };
static virStateDriver umlStateDriver = { diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index d33737e..3a14d12 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -64,6 +64,7 @@ #include "viruri.h" #include "command.h" #include "virnodesuspend.h" +#include "nodeinfo.h"
#define VIR_FROM_THIS VIR_FROM_XEN
@@ -2269,6 +2270,8 @@ static virDriver xenUnifiedDriver = { .domainOpenConsole = xenUnifiedDomainOpenConsole, /* 0.8.6 */ .isAlive = xenUnifiedIsAlive, /* 0.9.8 */ .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ };
ACK, once patch 3 is okay :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

New command node-memory-tune to get/set the node memory parameters, only two parameters are allowed to set (pages_to_scan, and sleep_millisecs, see documents in this patch for more details). Example of node-memory-tune's output: Shared memory: pages_to_scan 100 sleep_millisecs 20 pages_shared 0 pages_sharing 0 pages_unshared 0 pages_volatile 0 full_scans 0 --- tools/virsh-host.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 8 ++++ 2 files changed, 124 insertions(+), 0 deletions(-) diff --git a/tools/virsh-host.c b/tools/virsh-host.c index c46288b..22292c8 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -37,6 +37,7 @@ #include "util.h" #include "virsh-domain.h" #include "xml.h" +#include "virtypedparam.h" /* * "capabilities" command @@ -884,12 +885,127 @@ cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; } +static const vshCmdInfo info_node_memory_tune[] = { + {"help", N_("Get or set node memory parameters")}, + {"desc", N_("Get or set node memory parameters" + " To get the memory parameters, use following command: \n\n" + " virsh # node-memory-tune")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_memory_tune[] = { + {"shared-pages-to-scan", VSH_OT_INT, VSH_OFLAG_NONE, + N_("number of pages to scan before the shared memory service " + "goes to sleep")}, + {"shared-sleep-millisecs", VSH_OT_INT, VSH_OFLAG_NONE, + N_("number of millisecs the shared memory service should " + "sleep before next scan")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd) +{ + virTypedParameterPtr params = NULL; + int nparams = 0; + unsigned int flags = 0; + unsigned int shared_pages_to_scan = 0; + unsigned int shared_sleep_millisecs = 0; + bool ret = false; + int i = 0; + + if (vshCommandOptUInt(cmd, "shared-pages-to-scan", + &shared_pages_to_scan) < 0) { + vshError(ctl, "%s", _("invalid shared-pages-to-scan number")); + return false; + } + + if (vshCommandOptUInt(cmd, "shared-sleep-millisecs", + &shared_sleep_millisecs) < 0) { + vshError(ctl, "%s", _("invalid shared-sleep-millisecs number")); + return false; + } + + if (shared_pages_to_scan) + nparams++; + + if (shared_sleep_millisecs) + nparams++; + + if (nparams == 0) { + /* Get the number of memory parameters */ + if (virNodeGetMemoryParameters(ctl->conn, NULL, &nparams, flags) != 0) { + vshError(ctl, "%s", + _("Unable to get number of memory parameters")); + goto cleanup; + } + + if (nparams == 0) { + ret = true; + goto cleanup; + } + + /* Now go get all the memory parameters */ + params = vshCalloc(ctl, nparams, sizeof(*params)); + if (virNodeGetMemoryParameters(ctl->conn, params, &nparams, flags) != 0) { + vshError(ctl, "%s", _("Unable to get memory parameters")); + goto cleanup; + } + + /* XXX: Need to sort the returned params once new parameter + * fields not of shared memory are added. + */ + vshPrint(ctl, _("Shared memory:\n")); + for (i = 0; i < nparams; i++) { + char *str = vshGetTypedParamValue(ctl, ¶ms[i]); + vshPrint(ctl, "\t%-15s %s\n", params[i].field, str); + VIR_FREE(str); + } + + ret = true; + } else { + /* Set the memory parameters */ + params = vshCalloc(ctl, nparams, sizeof(*params)); + + if (i < nparams && shared_pages_to_scan) { + if (virTypedParameterAssign(¶ms[i++], + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, + shared_pages_to_scan) < 0) + goto error; + } + + if (i < nparams && shared_sleep_millisecs) { + if (virTypedParameterAssign(¶ms[i++], + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, + shared_sleep_millisecs) < 0) + goto error; + } + + if (virNodeSetMemoryParameters(ctl->conn, params, nparams, flags) != 0) + goto error; + else + ret = true; + } + +cleanup: + VIR_FREE(params); + return ret; + +error: + vshError(ctl, "%s", _("Unable to change memory parameters")); + goto cleanup; +} + const vshCmdDef hostAndHypervisorCmds[] = { {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, {"connect", cmdConnect, opts_connect, info_connect, VSH_CMD_FLAG_NOCONNECT}, {"freecell", cmdFreecell, opts_freecell, info_freecell, 0}, {"hostname", cmdHostname, NULL, info_hostname, 0}, + {"node-memory-tune", cmdNodeMemoryTune, + opts_node_memory_tune, info_node_memory_tune, 0}, {"nodecpustats", cmdNodeCpuStats, opts_node_cpustats, info_nodecpustats, 0}, {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo, 0}, {"nodememstats", cmdNodeMemStats, opts_node_memstats, info_nodememstats, 0}, diff --git a/tools/virsh.pod b/tools/virsh.pod index 559e64d..7795822 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -293,6 +293,14 @@ Real-Time-Clock interrupt to fire (to wake up the node) after a time delay specified by the 'duration' parameter. The duration time should be at least 60 seconds. +=item B<node-memory-tune> [I<shared-pages-to-scan>] [I<shared-sleep-millisecs>] + +Allows you to display or set the node memory parameters. +I<shared-pages-to-scan> can be used to set the number of pages to scan +before the shared memory service goes to sleep; I<shared-sleep-millisecs> +can be used to set the number of millisecs the shared memory service should +sleep before next scan. + =item B<capabilities> Print an XML document describing the capabilities of the hypervisor -- 1.7.7.3

On Fri, Sep 14, 2012 at 02:42:19PM +0800, Osier Yang wrote:
New command node-memory-tune to get/set the node memory parameters, only two parameters are allowed to set (pages_to_scan, and sleep_millisecs, see documents in this patch for more details).
Example of node-memory-tune's output:
Shared memory: pages_to_scan 100 sleep_millisecs 20 pages_shared 0 pages_sharing 0 pages_unshared 0 pages_volatile 0 full_scans 0 --- tools/virsh-host.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 8 ++++ 2 files changed, 124 insertions(+), 0 deletions(-)
diff --git a/tools/virsh-host.c b/tools/virsh-host.c index c46288b..22292c8 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -37,6 +37,7 @@ #include "util.h" #include "virsh-domain.h" #include "xml.h" +#include "virtypedparam.h"
/* * "capabilities" command @@ -884,12 +885,127 @@ cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; }
+static const vshCmdInfo info_node_memory_tune[] = { + {"help", N_("Get or set node memory parameters")}, + {"desc", N_("Get or set node memory parameters" + " To get the memory parameters, use following command: \n\n" + " virsh # node-memory-tune")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_memory_tune[] = { + {"shared-pages-to-scan", VSH_OT_INT, VSH_OFLAG_NONE, + N_("number of pages to scan before the shared memory service " + "goes to sleep")}, + {"shared-sleep-millisecs", VSH_OT_INT, VSH_OFLAG_NONE, + N_("number of millisecs the shared memory service should " + "sleep before next scan")},
I would add "shm_" prefix again for the paremeters
+ {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd) +{ + virTypedParameterPtr params = NULL; + int nparams = 0; + unsigned int flags = 0; + unsigned int shared_pages_to_scan = 0; + unsigned int shared_sleep_millisecs = 0; + bool ret = false; + int i = 0; + + if (vshCommandOptUInt(cmd, "shared-pages-to-scan", + &shared_pages_to_scan) < 0) { + vshError(ctl, "%s", _("invalid shared-pages-to-scan number")); + return false; + } + + if (vshCommandOptUInt(cmd, "shared-sleep-millisecs", + &shared_sleep_millisecs) < 0) { + vshError(ctl, "%s", _("invalid shared-sleep-millisecs number")); + return false; + } +
same
+ if (shared_pages_to_scan) + nparams++; + + if (shared_sleep_millisecs) + nparams++; + + if (nparams == 0) { + /* Get the number of memory parameters */ + if (virNodeGetMemoryParameters(ctl->conn, NULL, &nparams, flags) != 0) { + vshError(ctl, "%s", + _("Unable to get number of memory parameters")); + goto cleanup; + } + + if (nparams == 0) { + ret = true; + goto cleanup; + } + + /* Now go get all the memory parameters */ + params = vshCalloc(ctl, nparams, sizeof(*params)); + if (virNodeGetMemoryParameters(ctl->conn, params, &nparams, flags) != 0) { + vshError(ctl, "%s", _("Unable to get memory parameters")); + goto cleanup; + } + + /* XXX: Need to sort the returned params once new parameter + * fields not of shared memory are added. + */ + vshPrint(ctl, _("Shared memory:\n")); + for (i = 0; i < nparams; i++) { + char *str = vshGetTypedParamValue(ctl, ¶ms[i]); + vshPrint(ctl, "\t%-15s %s\n", params[i].field, str); + VIR_FREE(str); + } + + ret = true; + } else { + /* Set the memory parameters */ + params = vshCalloc(ctl, nparams, sizeof(*params)); + + if (i < nparams && shared_pages_to_scan) { + if (virTypedParameterAssign(¶ms[i++], + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, + shared_pages_to_scan) < 0) + goto error; + } + + if (i < nparams && shared_sleep_millisecs) { + if (virTypedParameterAssign(¶ms[i++], + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, + shared_sleep_millisecs) < 0) + goto error; + } + + if (virNodeSetMemoryParameters(ctl->conn, params, nparams, flags) != 0) + goto error; + else + ret = true; + } + +cleanup: + VIR_FREE(params); + return ret; + +error: + vshError(ctl, "%s", _("Unable to change memory parameters")); + goto cleanup; +} + const vshCmdDef hostAndHypervisorCmds[] = { {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, {"connect", cmdConnect, opts_connect, info_connect, VSH_CMD_FLAG_NOCONNECT}, {"freecell", cmdFreecell, opts_freecell, info_freecell, 0}, {"hostname", cmdHostname, NULL, info_hostname, 0}, + {"node-memory-tune", cmdNodeMemoryTune, + opts_node_memory_tune, info_node_memory_tune, 0}, {"nodecpustats", cmdNodeCpuStats, opts_node_cpustats, info_nodecpustats, 0}, {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo, 0}, {"nodememstats", cmdNodeMemStats, opts_node_memstats, info_nodememstats, 0}, diff --git a/tools/virsh.pod b/tools/virsh.pod index 559e64d..7795822 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -293,6 +293,14 @@ Real-Time-Clock interrupt to fire (to wake up the node) after a time delay specified by the 'duration' parameter. The duration time should be at least 60 seconds.
+=item B<node-memory-tune> [I<shared-pages-to-scan>] [I<shared-sleep-millisecs>] + +Allows you to display or set the node memory parameters. +I<shared-pages-to-scan> can be used to set the number of pages to scan +before the shared memory service goes to sleep; I<shared-sleep-millisecs>
idem
+can be used to set the number of millisecs the shared memory service should +sleep before next scan. + =item B<capabilities>
Print an XML document describing the capabilities of the hypervisor
Otherwise, looks fine, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

* python/libvirt-override-api.xml: (Add document to describe the APIs). * python/libvirt-override.c: (Implement the API wrappers manually) --- python/libvirt-override-api.xml | 13 ++++ python/libvirt-override.c | 125 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 0 deletions(-) diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index ab6f407..abc0b81 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -511,5 +511,18 @@ <arg name='domain' type='virDomainPtr' info='a domain object'/> <arg name='flags' type='unsigned int' info='unused, always pass 0'/> </function> + <function name='virNodeSetMemoryParameters' file='python'> + <info>Change the node memory tunables</info> + <return type='int' info='-1 in case of error, 0 in case of success.'/> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='params' type='virTypedParameterPtr' info='pointer to the memory tunable objects'/> + <arg name='flags' type='int' info='unused, always pass 0'/> + </function> + <function name='virNodeGetMemoryParameters' file='python'> + <info>Get the node memory parameters</info> + <return type='str *' info='None in case of error, returns a dictionary of params'/> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='flags' type='int' info='unused, always pass 0'/> + </function> </symbols> </api> diff --git a/python/libvirt-override.c b/python/libvirt-override.c index d07e7cb..ca32f80 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -6005,6 +6005,129 @@ cleanup: return py_retval; } +static PyObject * +libvirt_virNodeSetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + virConnectPtr conn; + PyObject *pyobj_conn, *info; + PyObject *ret = NULL; + int i_retval; + int nparams = 0; + Py_ssize_t size = 0; + unsigned int flags; + virTypedParameterPtr params, new_params; + + if (!PyArg_ParseTuple(args, + (char *)"OOi:virNodeSetMemoryParameters", + &pyobj_conn, &info, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + if ((size = PyDict_Size(info)) < 0) + return NULL; + + if (size == 0) { + PyErr_Format(PyExc_LookupError, + "Need non-empty dictionary to set attributes"); + return NULL; + } + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, NULL, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) + return VIR_PY_INT_FAIL; + + if (nparams == 0) { + PyErr_Format(PyExc_LookupError, + "no settable attributes"); + return NULL; + } + + if (VIR_ALLOC_N(params, nparams) < 0) + return PyErr_NoMemory(); + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, params, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) { + ret = VIR_PY_INT_FAIL; + goto cleanup; + } + + new_params = setPyVirTypedParameter(info, params, nparams); + if (!new_params) + goto cleanup; + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeSetMemoryParameters(conn, new_params, size, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) { + ret = VIR_PY_INT_FAIL; + goto cleanup; + } + + ret = VIR_PY_INT_SUCCESS; + +cleanup: + virTypedParameterArrayClear(params, nparams); + VIR_FREE(params); + VIR_FREE(new_params); + return ret; +} + +static PyObject * +libvirt_virNodeGetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + virConnectPtr conn; + PyObject *pyobj_conn; + PyObject *ret = NULL; + int i_retval; + int nparams = 0; + unsigned int flags; + virTypedParameterPtr params; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virNodeGetMemoryParameters", + &pyobj_conn, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, NULL, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) + return VIR_PY_NONE; + + if (!nparams) + return PyDict_New(); + + if (VIR_ALLOC_N(params, nparams) < 0) + return PyErr_NoMemory(); + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, params, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) { + ret = VIR_PY_NONE; + goto cleanup; + } + + ret = getPyVirTypedParameter(params, nparams); + +cleanup: + virTypedParameterArrayClear(params, nparams); + VIR_FREE(params); + return ret; +} + + /************************************************************************ * * * The registration stuff * @@ -6116,6 +6239,8 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virDomainBlockPeek", libvirt_virDomainBlockPeek, METH_VARARGS, NULL}, {(char *) "virDomainMemoryPeek", libvirt_virDomainMemoryPeek, METH_VARARGS, NULL}, {(char *) "virDomainGetDiskErrors", libvirt_virDomainGetDiskErrors, METH_VARARGS, NULL}, + {(char *) "virNodeGetMemoryParameters", libvirt_virNodeGetMemoryParameters, METH_VARARGS, NULL}, + {(char *) "virNodeSetMemoryParameters", libvirt_virNodeSetMemoryParameters, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; -- 1.7.7.3

On Fri, Sep 14, 2012 at 02:42:20PM +0800, Osier Yang wrote:
* python/libvirt-override-api.xml: (Add document to describe the APIs). * python/libvirt-override.c: (Implement the API wrappers manually) --- python/libvirt-override-api.xml | 13 ++++ python/libvirt-override.c | 125 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 0 deletions(-)
diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index ab6f407..abc0b81 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -511,5 +511,18 @@ <arg name='domain' type='virDomainPtr' info='a domain object'/> <arg name='flags' type='unsigned int' info='unused, always pass 0'/> </function> + <function name='virNodeSetMemoryParameters' file='python'> + <info>Change the node memory tunables</info> + <return type='int' info='-1 in case of error, 0 in case of success.'/> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='params' type='virTypedParameterPtr' info='pointer to the memory tunable objects'/> + <arg name='flags' type='int' info='unused, always pass 0'/> + </function> + <function name='virNodeGetMemoryParameters' file='python'> + <info>Get the node memory parameters</info> + <return type='str *' info='None in case of error, returns a dictionary of params'/> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='flags' type='int' info='unused, always pass 0'/> + </function> </symbols> </api> diff --git a/python/libvirt-override.c b/python/libvirt-override.c index d07e7cb..ca32f80 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -6005,6 +6005,129 @@ cleanup: return py_retval; }
+static PyObject * +libvirt_virNodeSetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + virConnectPtr conn; + PyObject *pyobj_conn, *info; + PyObject *ret = NULL; + int i_retval; + int nparams = 0; + Py_ssize_t size = 0; + unsigned int flags; + virTypedParameterPtr params, new_params; + + if (!PyArg_ParseTuple(args, + (char *)"OOi:virNodeSetMemoryParameters", + &pyobj_conn, &info, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + if ((size = PyDict_Size(info)) < 0) + return NULL; + + if (size == 0) { + PyErr_Format(PyExc_LookupError, + "Need non-empty dictionary to set attributes"); + return NULL; + } + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, NULL, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) + return VIR_PY_INT_FAIL; + + if (nparams == 0) { + PyErr_Format(PyExc_LookupError, + "no settable attributes"); + return NULL; + } + + if (VIR_ALLOC_N(params, nparams) < 0) + return PyErr_NoMemory(); + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, params, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) { + ret = VIR_PY_INT_FAIL; + goto cleanup; + } + + new_params = setPyVirTypedParameter(info, params, nparams); + if (!new_params) + goto cleanup; + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeSetMemoryParameters(conn, new_params, size, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) { + ret = VIR_PY_INT_FAIL; + goto cleanup; + } + + ret = VIR_PY_INT_SUCCESS; + +cleanup: + virTypedParameterArrayClear(params, nparams); + VIR_FREE(params); + VIR_FREE(new_params); + return ret; +} + +static PyObject * +libvirt_virNodeGetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + virConnectPtr conn; + PyObject *pyobj_conn; + PyObject *ret = NULL; + int i_retval; + int nparams = 0; + unsigned int flags; + virTypedParameterPtr params; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virNodeGetMemoryParameters", + &pyobj_conn, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, NULL, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) + return VIR_PY_NONE; + + if (!nparams) + return PyDict_New(); + + if (VIR_ALLOC_N(params, nparams) < 0) + return PyErr_NoMemory(); + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, params, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) { + ret = VIR_PY_NONE; + goto cleanup; + } + + ret = getPyVirTypedParameter(params, nparams); + +cleanup: + virTypedParameterArrayClear(params, nparams); + VIR_FREE(params); + return ret; +} + + /************************************************************************ * * * The registration stuff * @@ -6116,6 +6239,8 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virDomainBlockPeek", libvirt_virDomainBlockPeek, METH_VARARGS, NULL}, {(char *) "virDomainMemoryPeek", libvirt_virDomainMemoryPeek, METH_VARARGS, NULL}, {(char *) "virDomainGetDiskErrors", libvirt_virDomainGetDiskErrors, METH_VARARGS, NULL}, + {(char *) "virNodeGetMemoryParameters", libvirt_virNodeGetMemoryParameters, METH_VARARGS, NULL}, + {(char *) "virNodeSetMemoryParameters", libvirt_virNodeSetMemoryParameters, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} };
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Fri, Sep 14, 2012 at 02:42:14PM +0800, Osier Yang wrote:
v1:
https://www.redhat.com/archives/libvir-list/2012-September/msg00517.html
v1 - v2: * Rename virNode{Get,Set}SharedMemoryParameters to virNode{Get,Set}MemoryParameters, in case of we could add more node memory tunables in future.
Agreed, even if right now we think of using those generic parameter based function just for shared memory, there is potentially other use cases, allowing/forbidding memory overcommit could be such a node related memeory tuning.
As a result of RFC: https://www.redhat.com/archives/libvir-list/2012-August/msg01998.html, this adds two new APIs (virNode{Get,Set}MemoryParameters) to get and set the host shared memory tunables (ksm under linux).
Osier Yang (6): node_memory: Define the APIs to get/set shared memory parameters node_memory: Wire up the RPC protocol node_memory: Implement the internal APIs node_memory: Support get/set memory parameters for drivers node_memory: Expose the APIs to virsh node_memory: Expose the APIs to Python bindings
daemon/remote.c | 59 +++++++ include/libvirt/libvirt.h.in | 63 ++++++++ python/generator.py | 2 + python/libvirt-override-api.xml | 13 ++ python/libvirt-override.c | 125 +++++++++++++++ src/driver.h | 14 ++ src/libvirt.c | 121 ++++++++++++++ src/libvirt_private.syms | 2 + src/libvirt_public.syms | 2 + src/lxc/lxc_driver.c | 2 + src/nodeinfo.c | 332 +++++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 10 ++ src/qemu/qemu_driver.c | 2 + src/remote/remote_driver.c | 50 ++++++ src/remote/remote_protocol.x | 24 +++- src/remote_protocol-structs | 20 +++ src/rpc/gendispatch.pl | 3 + src/uml/uml_driver.c | 2 + src/xen/xen_driver.c | 3 + tools/virsh-host.c | 116 ++++++++++++++ tools/virsh.pod | 8 + 21 files changed, 972 insertions(+), 1 deletions(-)
-- 1.7.7.3
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/
participants (2)
-
Daniel Veillard
-
Osier Yang