diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a4e8ca9212532c9e594b20de450dd6361aced71b..149055892f53c354ede68d2915c67fe60131f2ab 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4490,6 +4490,18 @@ typedef virMemoryParameter *virMemoryParameterPtr; */ # define VIR_NODE_MEMORY_SHARED_FULL_SCANS "shm_full_scans" +/* VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES: + * + * Macro for typed parameter that represents whether pages from + * different NUMA nodes can be merged. The parameter has type int, + * when its value is 0, only pages which physically reside in the + * memory area of same NUMA node are merged; When its value is 1, + * pages from all nodes can be merged. Other values are reserved + * for future use. + */ +# define VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES "shm_merge_across_nodes" + + int virNodeGetMemoryParameters(virConnectPtr conn, virTypedParameterPtr params, int *nparams, diff --git a/src/nodeinfo.c b/src/nodeinfo.c index c0e60d8099ef5bf89fcf4b5c48dc4916fbf829ab..8f96b8b2f664274c10f7266d5d6c8cbe138e5cbb 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -1005,6 +1005,8 @@ nodeSetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, VIR_TYPED_PARAM_UINT, VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, VIR_TYPED_PARAM_UINT, + VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES, + VIR_TYPED_PARAM_UINT, NULL) < 0) return -1; @@ -1022,6 +1024,13 @@ nodeSetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS)) { ret = nodeSetMemoryParameterValue("sleep_millisecs", param); + /* Out of memory */ + if (ret == -2) + return -1; + } else if (STREQ(param->field, + VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES)) { + ret = nodeSetMemoryParameterValue("merge_across_nodes", param); + /* Out of memory */ if (ret == -2) return -1; @@ -1060,8 +1069,9 @@ nodeGetMemoryParameterValue(const char *field, if ((tmp = strchr(buf, '\n'))) *tmp = '\0'; - if (STREQ(field, "pages_to_scan") || - STREQ(field, "sleep_millisecs")) + if (STREQ(field, "pages_to_scan") || + STREQ(field, "sleep_millisecs") || + STREQ(field, "merge_across_nodes")) rc = virStrToLong_ui(buf, NULL, 10, (unsigned int *)value); else if (STREQ(field, "pages_shared") || STREQ(field, "pages_sharing") || @@ -1084,7 +1094,7 @@ cleanup: } #endif -#define NODE_MEMORY_PARAMETERS_NUM 7 +#define NODE_MEMORY_PARAMETERS_NUM 8 int nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, virTypedParameterPtr params ATTRIBUTE_UNUSED, @@ -1096,6 +1106,7 @@ nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, #ifdef __linux__ unsigned int pages_to_scan; unsigned int sleep_millisecs; + unsigned int merge_across_nodes; unsigned long long pages_shared; unsigned long long pages_sharing; unsigned long long pages_unshared; @@ -1189,6 +1200,17 @@ nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, break; + case 7: + if (nodeGetMemoryParameterValue("merge_across_nodes", + &merge_across_nodes) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES, + VIR_TYPED_PARAM_UINT, merge_across_nodes) < 0) + return -1; + + break; + default: break; } diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 5cf192de65b90dadc48bd2275055fa4c5441f8e1..106f5e9e0d3d6ab6bd668aa02ec9787dc62ac756 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -920,6 +920,8 @@ static const vshCmdOptDef opts_node_memory_tune[] = { {"shm-sleep-millisecs", VSH_OT_INT, VSH_OFLAG_NONE, N_("number of millisecs the shared memory service should " "sleep before next scan")}, + {"shm-merge-across-nodes", VSH_OT_INT, VSH_OFLAG_NONE, + N_("Specifies if pages from different numa nodes can be merged")}, {NULL, 0, 0, NULL} }; @@ -931,6 +933,7 @@ cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd) unsigned int flags = 0; unsigned int shm_pages_to_scan = 0; unsigned int shm_sleep_millisecs = 0; + unsigned int shm_merge_across_nodes = 0; bool ret = false; int i = 0; @@ -946,12 +949,21 @@ cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd) return false; } + if (vshCommandOptUInt(cmd, "shm-merge-across-nodes", + &shm_merge_across_nodes) < 0) { + vshError(ctl, "%s", _("invalid shm-merge-across-nodes number")); + return false; + } + if (shm_pages_to_scan) nparams++; if (shm_sleep_millisecs) nparams++; + if (shm_merge_across_nodes) + nparams++; + if (nparams == 0) { /* Get the number of memory parameters */ if (virNodeGetMemoryParameters(ctl->conn, NULL, &nparams, flags) != 0) { @@ -1003,6 +1015,14 @@ cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd) goto error; } + if (i < nparams && shm_merge_across_nodes) { + if (virTypedParameterAssign(¶ms[i++], + VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES, + VIR_TYPED_PARAM_UINT, + shm_merge_across_nodes) < 0) + goto error; + } + if (virNodeSetMemoryParameters(ctl->conn, params, nparams, flags) != 0) goto error; else diff --git a/tools/virsh.pod b/tools/virsh.pod index 2d90b7bdecad8dd6ed6ac445cbb03197c88fb013..0481e1fb54899e5ed827c33d3c82f7cffae65ec2 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -303,7 +303,10 @@ Allows you to display or set the node memory parameters. I can be used to set the number of pages to scan before the shared memory service goes to sleep; I can be used to set the number of millisecs the shared memory service should -sleep before next scan. +sleep before next scan; I specifies if pages from +different numa nodes can be merged. When set to 0, only pages which physically +reside in the memory area of same NUMA node can be merged. When set to 1, +pages from all nodes can be merged. Default to 1. =item B