libvirt/src/conf/numa_conf.c

1968 lines
57 KiB
C
Raw Normal View History

/*
* numa_conf.c
*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "numa_conf.h"
#include "domain_conf.h"
#include "viralloc.h"
#include "virnuma.h"
#include "virstring.h"
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
/*
* Distance definitions defined Conform ACPI 2.0 SLIT.
* See include/linux/topology.h
*/
#define LOCAL_DISTANCE 10
#define REMOTE_DISTANCE 20
/* SLIT entry value is a one-byte unsigned integer. */
#define UNREACHABLE 255
#define VIR_FROM_THIS VIR_FROM_DOMAIN
VIR_ENUM_IMPL(virDomainNumatuneMemMode,
VIR_DOMAIN_NUMATUNE_MEM_LAST,
"strict",
"preferred",
"interleave",
);
VIR_ENUM_IMPL(virDomainNumatunePlacement,
VIR_DOMAIN_NUMATUNE_PLACEMENT_LAST,
"default",
"static",
"auto",
);
VIR_ENUM_IMPL(virDomainMemoryAccess,
VIR_DOMAIN_MEMORY_ACCESS_LAST,
"default",
"shared",
"private",
);
VIR_ENUM_IMPL(virDomainCacheAssociativity,
VIR_DOMAIN_CACHE_ASSOCIATIVITY_LAST,
"none",
"direct",
"full",
);
VIR_ENUM_IMPL(virDomainCachePolicy,
VIR_DOMAIN_CACHE_POLICY_LAST,
"none",
"writeback",
"writethrough",
);
VIR_ENUM_IMPL(virDomainMemoryLatency,
VIR_DOMAIN_MEMORY_LATENCY_LAST,
"none",
"access",
"read",
"write"
);
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
typedef struct _virDomainNumaDistance virDomainNumaDistance;
typedef virDomainNumaDistance *virDomainNumaDistancePtr;
typedef struct _virDomainNumaCache virDomainNumaCache;
typedef virDomainNumaCache *virDomainNumaCachePtr;
typedef struct _virDomainNumaInterconnect virDomainNumaInterconnect;
typedef virDomainNumaInterconnect *virDomainNumaInterconnectPtr;
typedef struct _virDomainNumaNode virDomainNumaNode;
typedef virDomainNumaNode *virDomainNumaNodePtr;
struct _virDomainNuma {
struct {
bool specified;
virBitmapPtr nodeset;
virDomainNumatuneMemMode mode;
virDomainNumatunePlacement placement;
} memory; /* pinning for all the memory */
struct _virDomainNumaNode {
unsigned long long mem; /* memory size in KiB */
virBitmapPtr cpumask; /* bitmap of vCPUs corresponding to the node */
virBitmapPtr nodeset; /* host memory nodes where this guest node resides */
virDomainNumatuneMemMode mode; /* memory mode selection */
virDomainMemoryAccess memAccess; /* shared memory access configuration */
virTristateBool discard; /* discard-data for memory-backend-file */
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
struct _virDomainNumaDistance {
unsigned int value; /* locality value for node i->j or j->i */
unsigned int cellid;
} *distances; /* remote node distances */
size_t ndistances;
struct _virDomainNumaCache {
unsigned int level; /* cache level */
unsigned int size; /* cache size */
unsigned int line; /* line size, !!! in bytes !!! */
virDomainCacheAssociativity associativity; /* cache associativity */
virDomainCachePolicy policy; /* cache policy */
} *caches;
size_t ncaches;
} *mem_nodes; /* guest node configuration */
size_t nmem_nodes;
struct _virDomainNumaInterconnect {
virDomainNumaInterconnectType type; /* whether structure describes latency
or bandwidth */
unsigned int initiator; /* the initiator NUMA node */
unsigned int target; /* the target NUMA node */
unsigned int cache; /* the target cache on @target; if 0 then the
memory on @target */
virDomainMemoryLatency accessType; /* what type of access is defined */
unsigned long value; /* value itself */
} *interconnects;
size_t ninterconnects;
/* Future NUMA tuning related stuff should go here. */
};
bool
virDomainNumatuneNodeSpecified(virDomainNumaPtr numatune,
int cellid)
{
if (numatune &&
cellid >= 0 &&
cellid < numatune->nmem_nodes)
return numatune->mem_nodes[cellid].nodeset;
return false;
}
static int
virDomainNumatuneNodeParseXML(virDomainNumaPtr numa,
xmlXPathContextPtr ctxt)
{
char *tmp = NULL;
int n = 0;
int ret = -1;
size_t i = 0;
xmlNodePtr *nodes = NULL;
if ((n = virXPathNodeSet("./numatune/memnode", ctxt, &nodes)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot extract memnode nodes"));
goto cleanup;
}
if (!n)
return 0;
if (numa->memory.specified &&
numa->memory.placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Per-node binding is not compatible with "
"automatic NUMA placement."));
goto cleanup;
}
if (!numa->nmem_nodes) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Element 'memnode' is invalid without "
"any guest NUMA cells"));
goto cleanup;
}
for (i = 0; i < n; i++) {
int mode = 0;
unsigned int cellid = 0;
virDomainNumaNodePtr mem_node = NULL;
xmlNodePtr cur_node = nodes[i];
tmp = virXMLPropString(cur_node, "cellid");
if (!tmp) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing required cellid attribute "
"in memnode element"));
goto cleanup;
}
if (virStrToLong_uip(tmp, NULL, 10, &cellid) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid cellid attribute in memnode element: %s"),
tmp);
goto cleanup;
}
VIR_FREE(tmp);
if (cellid >= numa->nmem_nodes) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Argument 'cellid' in memnode element must "
"correspond to existing guest's NUMA cell"));
goto cleanup;
}
mem_node = &numa->mem_nodes[cellid];
if (mem_node->nodeset) {
virReportError(VIR_ERR_XML_ERROR,
_("Multiple memnode elements with cellid %u"),
cellid);
goto cleanup;
}
tmp = virXMLPropString(cur_node, "mode");
if (!tmp) {
mem_node->mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
} else {
if ((mode = virDomainNumatuneMemModeTypeFromString(tmp)) < 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Invalid mode attribute in memnode element"));
goto cleanup;
}
VIR_FREE(tmp);
mem_node->mode = mode;
}
tmp = virXMLPropString(cur_node, "nodeset");
if (!tmp) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing required nodeset attribute "
"in memnode element"));
goto cleanup;
}
if (virBitmapParse(tmp, &mem_node->nodeset, VIR_DOMAIN_CPUMASK_LEN) < 0)
goto cleanup;
if (virBitmapIsAllClear(mem_node->nodeset)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Invalid value of 'nodeset': %s"), tmp);
goto cleanup;
}
VIR_FREE(tmp);
}
ret = 0;
cleanup:
VIR_FREE(nodes);
VIR_FREE(tmp);
return ret;
}
int
virDomainNumatuneParseXML(virDomainNumaPtr numa,
bool placement_static,
xmlXPathContextPtr ctxt)
{
char *tmp = NULL;
int mode = -1;
int n = 0;
int placement = -1;
int ret = -1;
virBitmapPtr nodeset = NULL;
xmlNodePtr node = NULL;
if (virXPathInt("count(./numatune)", ctxt, &n) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot extract numatune nodes"));
goto cleanup;
} else if (n > 1) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("only one numatune is supported"));
goto cleanup;
}
node = virXPathNode("./numatune/memory[1]", ctxt);
if (!placement_static && !node)
placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO;
if (node) {
if ((tmp = virXMLPropString(node, "mode")) &&
(mode = virDomainNumatuneMemModeTypeFromString(tmp)) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported NUMA memory tuning mode '%s'"), tmp);
goto cleanup;
}
VIR_FREE(tmp);
if ((tmp = virXMLPropString(node, "placement")) &&
(placement = virDomainNumatunePlacementTypeFromString(tmp)) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported NUMA memory placement mode '%s'"), tmp);
goto cleanup;
}
VIR_FREE(tmp);
tmp = virXMLPropString(node, "nodeset");
if (tmp) {
if (virBitmapParse(tmp, &nodeset, VIR_DOMAIN_CPUMASK_LEN) < 0)
goto cleanup;
if (virBitmapIsAllClear(nodeset)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Invalid value of 'nodeset': %s"), tmp);
goto cleanup;
}
VIR_FREE(tmp);
}
}
if (virDomainNumatuneSet(numa,
placement_static,
placement,
mode,
nodeset) < 0)
goto cleanup;
if (virDomainNumatuneNodeParseXML(numa, ctxt) < 0)
goto cleanup;
ret = 0;
cleanup:
virBitmapFree(nodeset);
VIR_FREE(tmp);
return ret;
}
int
virDomainNumatuneFormatXML(virBufferPtr buf,
virDomainNumaPtr numatune)
{
const char *tmp = NULL;
char *nodeset = NULL;
bool nodesetSpecified = false;
size_t i = 0;
if (!numatune)
return 0;
for (i = 0; i < numatune->nmem_nodes; i++) {
if (numatune->mem_nodes[i].nodeset) {
nodesetSpecified = true;
break;
}
}
if (!nodesetSpecified && !numatune->memory.specified)
return 0;
virBufferAddLit(buf, "<numatune>\n");
virBufferAdjustIndent(buf, 2);
if (numatune->memory.specified) {
tmp = virDomainNumatuneMemModeTypeToString(numatune->memory.mode);
virBufferAsprintf(buf, "<memory mode='%s' ", tmp);
if (numatune->memory.placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC) {
if (!(nodeset = virBitmapFormat(numatune->memory.nodeset)))
return -1;
virBufferAsprintf(buf, "nodeset='%s'/>\n", nodeset);
VIR_FREE(nodeset);
} else if (numatune->memory.placement) {
tmp = virDomainNumatunePlacementTypeToString(numatune->memory.placement);
virBufferAsprintf(buf, "placement='%s'/>\n", tmp);
}
}
for (i = 0; i < numatune->nmem_nodes; i++) {
virDomainNumaNodePtr mem_node = &numatune->mem_nodes[i];
if (!mem_node->nodeset)
continue;
if (!(nodeset = virBitmapFormat(mem_node->nodeset)))
return -1;
virBufferAsprintf(buf,
"<memnode cellid='%zu' mode='%s' nodeset='%s'/>\n",
i,
virDomainNumatuneMemModeTypeToString(mem_node->mode),
nodeset);
VIR_FREE(nodeset);
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</numatune>\n");
return 0;
}
void
virDomainNumaFree(virDomainNumaPtr numa)
{
size_t i = 0;
if (!numa)
return;
virBitmapFree(numa->memory.nodeset);
for (i = 0; i < numa->nmem_nodes; i++) {
virBitmapFree(numa->mem_nodes[i].cpumask);
virBitmapFree(numa->mem_nodes[i].nodeset);
if (numa->mem_nodes[i].ndistances > 0)
g_free(numa->mem_nodes[i].distances);
g_free(numa->mem_nodes[i].caches);
}
g_free(numa->mem_nodes);
g_free(numa->interconnects);
g_free(numa);
}
/**
* virDomainNumatuneGetMode:
* @numatune: pointer to numatune definition
* @cellid: cell selector
* @mode: where to store the result
*
* Get the defined mode for domain's memory. It's safe to pass
* NULL to @mode if the return value is the only info needed.
*
* Returns: 0 on success (with @mode updated)
* -1 if no mode was defined in XML
*/
int virDomainNumatuneGetMode(virDomainNumaPtr numatune,
int cellid,
virDomainNumatuneMemMode *mode)
{
virDomainNumatuneMemMode tmp_mode;
if (!numatune)
return -1;
if (virDomainNumatuneNodeSpecified(numatune, cellid))
tmp_mode = numatune->mem_nodes[cellid].mode;
else if (numatune->memory.specified)
tmp_mode = numatune->memory.mode;
else
return -1;
if (mode)
*mode = tmp_mode;
return 0;
}
virBitmapPtr
virDomainNumatuneGetNodeset(virDomainNumaPtr numatune,
virBitmapPtr auto_nodeset,
int cellid)
{
if (!numatune)
return NULL;
if (numatune->memory.specified &&
numatune->memory.placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO)
return auto_nodeset;
if (virDomainNumatuneNodeSpecified(numatune, cellid))
return numatune->mem_nodes[cellid].nodeset;
if (!numatune->memory.specified)
return NULL;
return numatune->memory.nodeset;
}
char *
virDomainNumatuneFormatNodeset(virDomainNumaPtr numatune,
virBitmapPtr auto_nodeset,
int cellid)
{
return virBitmapFormat(virDomainNumatuneGetNodeset(numatune,
auto_nodeset,
cellid));
}
int
virDomainNumatuneMaybeGetNodeset(virDomainNumaPtr numatune,
virBitmapPtr auto_nodeset,
virBitmapPtr *retNodeset,
int cellid)
{
*retNodeset = NULL;
if (!numatune)
return 0;
if (!virDomainNumatuneNodeSpecified(numatune, cellid) &&
!numatune->memory.specified)
return 0;
if (numatune->memory.specified &&
numatune->memory.placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO &&
!auto_nodeset) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Advice from numad is needed in case of "
"automatic numa placement"));
return -1;
}
*retNodeset = virDomainNumatuneGetNodeset(numatune, auto_nodeset, cellid);
return 0;
}
int
virDomainNumatuneMaybeFormatNodeset(virDomainNumaPtr numatune,
virBitmapPtr auto_nodeset,
char **mask,
int cellid)
{
virBitmapPtr nodeset;
if (virDomainNumatuneMaybeGetNodeset(numatune, auto_nodeset, &nodeset,
cellid) < 0)
return -1;
if (nodeset &&
!(*mask = virBitmapFormat(nodeset)))
return -1;
return 0;
}
int
virDomainNumatuneSet(virDomainNumaPtr numa,
bool placement_static,
int placement,
int mode,
virBitmapPtr nodeset)
{
/* No need to do anything in this case */
if (mode == -1 && placement == -1 && !nodeset)
return 0;
if (!numa->memory.specified) {
if (mode == -1)
mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
if (placement == -1)
placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_DEFAULT;
}
/* Range checks */
if (mode != -1 &&
(mode < 0 || mode >= VIR_DOMAIN_NUMATUNE_MEM_LAST)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported numatune mode '%d'"),
mode);
return -1;
}
if (placement != -1 &&
(placement < 0 || placement >= VIR_DOMAIN_NUMATUNE_PLACEMENT_LAST)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported numatune placement '%d'"),
mode);
return -1;
}
if (mode != -1)
numa->memory.mode = mode;
if (nodeset) {
virBitmapFree(numa->memory.nodeset);
numa->memory.nodeset = virBitmapNewCopy(nodeset);
if (placement == -1)
placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC;
}
if (placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_DEFAULT) {
if (numa->memory.nodeset || placement_static)
placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC;
else
placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO;
}
if (placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC &&
!numa->memory.nodeset) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("nodeset for NUMA memory tuning must be set "
"if 'placement' is 'static'"));
return -1;
}
/* setting nodeset when placement auto is invalid */
if (placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO &&
numa->memory.nodeset) {
virBitmapFree(numa->memory.nodeset);
numa->memory.nodeset = NULL;
}
if (placement != -1)
numa->memory.placement = placement;
numa->memory.specified = true;
return 0;
}
static bool
virDomainNumaNodesEqual(virDomainNumaPtr n1,
virDomainNumaPtr n2)
{
size_t i = 0;
if (n1->nmem_nodes != n2->nmem_nodes)
return false;
for (i = 0; i < n1->nmem_nodes; i++) {
virDomainNumaNodePtr nd1 = &n1->mem_nodes[i];
virDomainNumaNodePtr nd2 = &n2->mem_nodes[i];
if (!nd1->nodeset && !nd2->nodeset)
continue;
if (nd1->mode != nd2->mode)
return false;
if (!virBitmapEqual(nd1->nodeset, nd2->nodeset))
return false;
}
return true;
}
bool
virDomainNumaEquals(virDomainNumaPtr n1,
virDomainNumaPtr n2)
{
if (!n1 && !n2)
return true;
if (!n1 || !n2)
return false;
if (!n1->memory.specified && !n2->memory.specified)
return virDomainNumaNodesEqual(n1, n2);
if (!n1->memory.specified || !n2->memory.specified)
return false;
if (n1->memory.mode != n2->memory.mode)
return false;
if (n1->memory.placement != n2->memory.placement)
return false;
if (!virBitmapEqual(n1->memory.nodeset, n2->memory.nodeset))
return false;
return virDomainNumaNodesEqual(n1, n2);
}
bool
virDomainNumatuneHasPlacementAuto(virDomainNumaPtr numatune)
{
if (!numatune)
return false;
if (!numatune->memory.specified)
return false;
if (numatune->memory.placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO)
return true;
return false;
}
bool
virDomainNumatuneHasPerNodeBinding(virDomainNumaPtr numatune)
{
size_t i = 0;
if (!numatune)
return false;
for (i = 0; i < numatune->nmem_nodes; i++) {
if (numatune->mem_nodes[i].nodeset)
return true;
}
return false;
}
int
virDomainNumatuneSpecifiedMaxNode(virDomainNumaPtr numatune)
{
int ret = -1;
virBitmapPtr nodemask = NULL;
size_t i;
int bit;
if (!numatune)
return ret;
nodemask = virDomainNumatuneGetNodeset(numatune, NULL, -1);
if (nodemask)
ret = virBitmapLastSetBit(nodemask);
for (i = 0; i < numatune->nmem_nodes; i++) {
nodemask = numatune->mem_nodes[i].nodeset;
if (!nodemask)
continue;
bit = virBitmapLastSetBit(nodemask);
if (bit > ret)
ret = bit;
}
return ret;
}
bool
virDomainNumatuneNodesetIsAvailable(virDomainNumaPtr numatune,
virBitmapPtr auto_nodeset)
{
size_t i = 0;
virBitmapPtr b = NULL;
if (!numatune)
return true;
b = virDomainNumatuneGetNodeset(numatune, auto_nodeset, -1);
if (!virNumaNodesetIsAvailable(b))
return false;
for (i = 0; i < numatune->nmem_nodes; i++) {
b = virDomainNumatuneGetNodeset(numatune, auto_nodeset, i);
if (!virNumaNodesetIsAvailable(b))
return false;
}
return true;
}
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
static int
virDomainNumaDefNodeDistanceParseXML(virDomainNumaPtr def,
xmlXPathContextPtr ctxt,
unsigned int cur_cell)
{
int ret = -1;
int sibling;
char *tmp = NULL;
xmlNodePtr *nodes = NULL;
size_t i, ndistances = def->nmem_nodes;
if (ndistances == 0)
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
return 0;
/* check if NUMA distances definition is present */
if (!virXPathNode("./distances[1]", ctxt))
return 0;
if ((sibling = virXPathNodeSet("./distances[1]/sibling", ctxt, &nodes)) <= 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("NUMA distances defined without siblings"));
goto cleanup;
}
for (i = 0; i < sibling; i++) {
virDomainNumaDistancePtr ldist;
virDomainNumaDistancePtr rdist;
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
unsigned int sibling_id, sibling_value;
/* siblings are in order of parsing or explicitly numbered */
if (!(tmp = virXMLPropString(nodes[i], "id"))) {
virReportError(VIR_ERR_XML_ERROR,
_("Missing 'id' attribute in NUMA "
"distances under 'cell id %d'"),
cur_cell);
goto cleanup;
}
/* The "id" needs to be applicable */
if (virStrToLong_uip(tmp, NULL, 10, &sibling_id) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid 'id' attribute in NUMA "
"distances for sibling: '%s'"),
tmp);
goto cleanup;
}
VIR_FREE(tmp);
/* The "id" needs to be within numa/cell range */
if (sibling_id >= ndistances) {
virReportError(VIR_ERR_XML_ERROR,
_("'sibling_id %d' does not refer to a "
"valid cell within NUMA 'cell id %d'"),
sibling_id, cur_cell);
goto cleanup;
}
/* We need a locality value. Check and correct
* distance to local and distance to remote node.
*/
if (!(tmp = virXMLPropString(nodes[i], "value"))) {
virReportError(VIR_ERR_XML_ERROR,
_("Missing 'value' attribute in NUMA distances "
"under 'cell id %d' for 'sibling id %d'"),
cur_cell, sibling_id);
goto cleanup;
}
/* The "value" needs to be applicable */
if (virStrToLong_uip(tmp, NULL, 10, &sibling_value) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("'value %s' is invalid for "
"'sibling id %d' under NUMA 'cell id %d'"),
tmp, sibling_id, cur_cell);
goto cleanup;
}
VIR_FREE(tmp);
/* Assure LOCAL_DISTANCE <= "value" <= UNREACHABLE
* and correct LOCAL_DISTANCE setting if such applies.
*/
if ((sibling_value < LOCAL_DISTANCE ||
sibling_value > UNREACHABLE) ||
(sibling_id == cur_cell &&
sibling_value != LOCAL_DISTANCE) ||
(sibling_id != cur_cell &&
sibling_value == LOCAL_DISTANCE)) {
virReportError(VIR_ERR_XML_ERROR,
_("'value %d' is invalid for "
"'sibling id %d' under NUMA 'cell id %d'"),
sibling_value, sibling_id, cur_cell);
goto cleanup;
}
/* Apply the local / remote distance */
ldist = def->mem_nodes[cur_cell].distances;
if (!ldist) {
ldist = g_new0(virDomainNumaDistance, ndistances);
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
ldist[cur_cell].value = LOCAL_DISTANCE;
ldist[cur_cell].cellid = cur_cell;
def->mem_nodes[cur_cell].ndistances = ndistances;
def->mem_nodes[cur_cell].distances = ldist;
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
}
ldist[sibling_id].cellid = sibling_id;
ldist[sibling_id].value = sibling_value;
/* Apply symmetry if none given */
rdist = def->mem_nodes[sibling_id].distances;
if (!rdist) {
rdist = g_new0(virDomainNumaDistance, ndistances);
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
rdist[sibling_id].value = LOCAL_DISTANCE;
rdist[sibling_id].cellid = sibling_id;
def->mem_nodes[sibling_id].ndistances = ndistances;
def->mem_nodes[sibling_id].distances = rdist;
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
}
rdist[cur_cell].cellid = cur_cell;
if (!rdist[cur_cell].value)
rdist[cur_cell].value = sibling_value;
}
ret = 0;
cleanup:
if (ret < 0) {
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
for (i = 0; i < ndistances; i++)
VIR_FREE(def->mem_nodes[i].distances);
def->mem_nodes[i].ndistances = 0;
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
}
VIR_FREE(nodes);
VIR_FREE(tmp);
return ret;
}
static int
virDomainNumaDefNodeCacheParseXML(virDomainNumaPtr def,
xmlXPathContextPtr ctxt,
unsigned int cur_cell)
{
g_autofree xmlNodePtr *nodes = NULL;
int n;
size_t i;
if ((n = virXPathNodeSet("./cache", ctxt, &nodes)) < 0)
return -1;
def->mem_nodes[cur_cell].caches = g_new0(virDomainNumaCache, n);
for (i = 0; i < n; i++) {
VIR_XPATH_NODE_AUTORESTORE(ctxt)
virDomainNumaCachePtr cache = &def->mem_nodes[cur_cell].caches[i];
g_autofree char *tmp = NULL;
unsigned int level;
int associativity;
int policy;
unsigned long long size;
unsigned long long line;
if (!(tmp = virXMLPropString(nodes[i], "level"))) {
virReportError(VIR_ERR_XML_ERROR,
_("Missing 'level' attribute in cache "
"element for NUMA node %d"),
cur_cell);
return -1;
}
if (virStrToLong_uip(tmp, NULL, 10, &level) < 0 ||
level == 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid 'level' attribute in cache "
"element for NUMA node %d"),
cur_cell);
return -1;
}
VIR_FREE(tmp);
if (!(tmp = virXMLPropString(nodes[i], "associativity"))) {
virReportError(VIR_ERR_XML_ERROR,
_("Missing 'associativity' attribute in cache "
"element for NUMA node %d"),
cur_cell);
return -1;
}
if ((associativity = virDomainCacheAssociativityTypeFromString(tmp)) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid cache associativity '%s'"),
tmp);
return -1;
}
VIR_FREE(tmp);
if (!(tmp = virXMLPropString(nodes[i], "policy"))) {
virReportError(VIR_ERR_XML_ERROR,
_("Missing 'policy' attribute in cache "
"element for NUMA node %d"),
cur_cell);
}
if ((policy = virDomainCachePolicyTypeFromString(tmp)) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid cache policy '%s'"),
tmp);
return -1;
}
VIR_FREE(tmp);
ctxt->node = nodes[i];
if (virDomainParseMemory("./size/@value", "./size/unit",
ctxt, &size, true, false) < 0)
return -1;
if (virParseScaledValue("./line/@value", "./line/unit",
ctxt, &line, 1, ULLONG_MAX, true) < 0)
return -1;
*cache = (virDomainNumaCache){level, size, line, associativity, policy};
def->mem_nodes[cur_cell].ncaches++;
}
return 0;
}
int
virDomainNumaDefParseXML(virDomainNumaPtr def,
xmlXPathContextPtr ctxt)
{
xmlNodePtr *nodes = NULL;
char *tmp = NULL;
int n;
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
size_t i, j;
int ret = -1;
/* check if NUMA definition is present */
if (!virXPathNode("./cpu/numa[1]", ctxt))
return 0;
if ((n = virXPathNodeSet("./cpu/numa[1]/cell", ctxt, &nodes)) <= 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("NUMA topology defined without NUMA cells"));
goto cleanup;
}
def->mem_nodes = g_new0(struct _virDomainNumaNode, n);
def->nmem_nodes = n;
for (i = 0; i < n; i++) {
VIR_XPATH_NODE_AUTORESTORE(ctxt)
int rc;
unsigned int cur_cell = i;
/* cells are in order of parsing or explicitly numbered */
if ((tmp = virXMLPropString(nodes[i], "id"))) {
if (virStrToLong_uip(tmp, NULL, 10, &cur_cell) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid 'id' attribute in NUMA cell: '%s'"),
tmp);
goto cleanup;
}
if (cur_cell >= n) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Exactly one 'cell' element per guest "
"NUMA cell allowed, non-contiguous ranges or "
"ranges not starting from 0 are not allowed"));
goto cleanup;
}
}
VIR_FREE(tmp);
if (def->mem_nodes[cur_cell].mem) {
virReportError(VIR_ERR_XML_ERROR,
_("Duplicate NUMA cell info for cell id '%u'"),
cur_cell);
goto cleanup;
}
if ((tmp = virXMLPropString(nodes[i], "cpus"))) {
g_autoptr(virBitmap) cpumask = NULL;
if (virBitmapParse(tmp, &cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0)
goto cleanup;
if (!virBitmapIsAllClear(cpumask))
def->mem_nodes[cur_cell].cpumask = g_steal_pointer(&cpumask);
VIR_FREE(tmp);
}
for (j = 0; j < n; j++) {
if (j == cur_cell ||
!def->mem_nodes[j].cpumask ||
!def->mem_nodes[cur_cell].cpumask)
continue;
if (virBitmapOverlaps(def->mem_nodes[j].cpumask,
def->mem_nodes[cur_cell].cpumask)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("NUMA cells %u and %zu have overlapping vCPU ids"),
cur_cell, j);
goto cleanup;
}
}
ctxt->node = nodes[i];
if (virDomainParseMemory("./@memory", "./@unit", ctxt,
&def->mem_nodes[cur_cell].mem, true, false) < 0)
goto cleanup;
if ((tmp = virXMLPropString(nodes[i], "memAccess"))) {
if ((rc = virDomainMemoryAccessTypeFromString(tmp)) <= 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Invalid 'memAccess' attribute value '%s'"),
tmp);
goto cleanup;
}
def->mem_nodes[cur_cell].memAccess = rc;
VIR_FREE(tmp);
}
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
if ((tmp = virXMLPropString(nodes[i], "discard"))) {
if ((rc = virTristateBoolTypeFromString(tmp)) <= 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Invalid 'discard' attribute value '%s'"),
tmp);
goto cleanup;
}
def->mem_nodes[cur_cell].discard = rc;
VIR_FREE(tmp);
}
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
/* Parse NUMA distances info */
if (virDomainNumaDefNodeDistanceParseXML(def, ctxt, cur_cell) < 0)
goto cleanup;
/* Parse cache info */
if (virDomainNumaDefNodeCacheParseXML(def, ctxt, cur_cell) < 0)
goto cleanup;
}
VIR_FREE(nodes);
if ((n = virXPathNodeSet("./cpu/numa[1]/interconnects[1]/latency|"
"./cpu/numa[1]/interconnects[1]/bandwidth", ctxt, &nodes)) < 0)
goto cleanup;
def->interconnects = g_new0(virDomainNumaInterconnect, n);
for (i = 0; i < n; i++) {
virDomainNumaInterconnectType type;
unsigned int initiator;
unsigned int target;
unsigned int cache = 0;
int accessType;
unsigned long long value;
if (virXMLNodeNameEqual(nodes[i], "latency")) {
type = VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_LATENCY;
if (!(tmp = virXMLPropString(nodes[i], "value"))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing 'value' attribute in NUMA interconnects"));
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
goto cleanup;
}
if (virStrToLong_ullp(tmp, NULL, 10, &value) < 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Invalid 'value' attribute in NUMA interconnects"));
goto cleanup;
}
VIR_FREE(tmp);
} else if (virXMLNodeNameEqual(nodes[i], "bandwidth")) {
VIR_XPATH_NODE_AUTORESTORE(ctxt)
type = VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_BANDWIDTH;
ctxt->node = nodes[i];
if (virDomainParseMemory("./@value", "./@unit", ctxt, &value, true, false) < 0)
goto cleanup;
} else {
/* Ignore yet unknown child elements. */
continue;
}
if (!(tmp = virXMLPropString(nodes[i], "initiator"))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing 'initiator' attribute in NUMA interconnects"));
goto cleanup;
}
if (virStrToLong_uip(tmp, NULL, 10, &initiator) < 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Invalid 'initiator' attribute in NUMA interconnects"));
goto cleanup;
}
VIR_FREE(tmp);
if (!(tmp = virXMLPropString(nodes[i], "target"))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing 'target' attribute in NUMA interconnects"));
goto cleanup;
}
if (virStrToLong_uip(tmp, NULL, 10, &target) < 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Invalid 'target' attribute in NUMA interconnects"));
goto cleanup;
}
VIR_FREE(tmp);
/* cache attribute is optional */
if ((tmp = virXMLPropString(nodes[i], "cache"))) {
if (virStrToLong_uip(tmp, NULL, 10, &cache) < 0 ||
cache == 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Invalid 'cache' attribute in NUMA interconnects"));
goto cleanup;
}
}
VIR_FREE(tmp);
if (!(tmp = virXMLPropString(nodes[i], "type"))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing 'type' attribute in NUMA interconnects"));
goto cleanup;
}
if ((accessType = virDomainMemoryLatencyTypeFromString(tmp)) <= 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Invalid 'type' attribute in NUMA interconnects"));
goto cleanup;
}
VIR_FREE(tmp);
def->interconnects[i] = (virDomainNumaInterconnect) {type, initiator, target,
cache, accessType, value};
def->ninterconnects++;
}
ret = 0;
cleanup:
VIR_FREE(nodes);
VIR_FREE(tmp);
return ret;
}
int
virDomainNumaDefFormatXML(virBufferPtr buf,
virDomainNumaPtr def)
{
virDomainMemoryAccess memAccess;
virTristateBool discard;
size_t ncells = virDomainNumaGetNodeCount(def);
size_t i;
if (ncells == 0)
return 0;
virBufferAddLit(buf, "<numa>\n");
virBufferAdjustIndent(buf, 2);
for (i = 0; i < ncells; i++) {
virBitmapPtr cpumask = virDomainNumaGetNodeCpumask(def, i);
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
int ndistances;
size_t ncaches;
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
memAccess = virDomainNumaGetNodeMemoryAccessMode(def, i);
discard = virDomainNumaGetNodeDiscard(def, i);
virBufferAddLit(buf, "<cell");
virBufferAsprintf(buf, " id='%zu'", i);
if (cpumask) {
g_autofree char *cpustr = virBitmapFormat(cpumask);
if (!cpustr)
return -1;
virBufferAsprintf(buf, " cpus='%s'", cpustr);
}
virBufferAsprintf(buf, " memory='%llu'",
virDomainNumaGetNodeMemorySize(def, i));
virBufferAddLit(buf, " unit='KiB'");
if (memAccess)
virBufferAsprintf(buf, " memAccess='%s'",
virDomainMemoryAccessTypeToString(memAccess));
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
if (discard)
virBufferAsprintf(buf, " discard='%s'",
virTristateBoolTypeToString(discard));
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
ndistances = def->mem_nodes[i].ndistances;
ncaches = def->mem_nodes[i].ncaches;
if (ndistances == 0 && ncaches == 0) {
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
virBufferAddLit(buf, "/>\n");
} else {
size_t j;
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);
if (ndistances) {
virDomainNumaDistancePtr distances = def->mem_nodes[i].distances;
virBufferAddLit(buf, "<distances>\n");
virBufferAdjustIndent(buf, 2);
for (j = 0; j < ndistances; j++) {
if (distances[j].value) {
virBufferAddLit(buf, "<sibling");
virBufferAsprintf(buf, " id='%d'", distances[j].cellid);
virBufferAsprintf(buf, " value='%d'", distances[j].value);
virBufferAddLit(buf, "/>\n");
}
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</distances>\n");
}
for (j = 0; j < ncaches; j++) {
virDomainNumaCachePtr cache = &def->mem_nodes[i].caches[j];
virBufferAsprintf(buf, "<cache level='%u'", cache->level);
if (cache->associativity) {
virBufferAsprintf(buf, " associativity='%s'",
virDomainCacheAssociativityTypeToString(cache->associativity));
}
if (cache->policy) {
virBufferAsprintf(buf, " policy='%s'",
virDomainCachePolicyTypeToString(cache->policy));
}
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);
virBufferAsprintf(buf,
"<size value='%u' unit='KiB'/>\n",
cache->size);
if (cache->line) {
virBufferAsprintf(buf,
"<line value='%u' unit='B'/>\n",
cache->line);
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</cache>\n");
numa: describe siblings distances within cells Add support for describing NUMA distances in a domain's <numa> <cell> XML description. Below is an example of a 4 node setup: <cpu> <numa> <cell id='0' cpus='0-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='4-7' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='8-11' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> <cell id='3' cpus='12-15' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> A <cell> defines a NUMA node. <distances> describes the NUMA distance from the <cell> to the other NUMA nodes (the <sibling>s). For example, in above XML description, the distance between NUMA node0 <cell id='0' ...> and NUMA node2 <sibling id='2' ...> is 31. Valid distance values are '10 <= value <= 255'. A distance value of 10 represents the distance to the node itself. A distance value of 20 represents the default value for remote nodes but other values are possible depending on the physical topology of the system. When distances are not fully described, any missing sibling distance values will default to 10 for local nodes and 20 for remote nodes. If distance is given for A -> B, then we default B -> A to the same value instead of 20. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:20 +00:00
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</cell>\n");
}
}
if (def->ninterconnects) {
virBufferAddLit(buf, "<interconnects>\n");
virBufferAdjustIndent(buf, 2);
}
for (i = 0; i < def->ninterconnects; i++) {
virDomainNumaInterconnectPtr l = &def->interconnects[i];
switch (l->type) {
case VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_LATENCY:
virBufferAddLit(buf, "<latency");
break;
case VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_BANDWIDTH:
virBufferAddLit(buf, "<bandwidth");
}
virBufferAsprintf(buf,
" initiator='%u' target='%u'",
l->initiator, l->target);
if (l->cache > 0) {
virBufferAsprintf(buf,
" cache='%u'",
l->cache);
}
virBufferAsprintf(buf,
" type='%s' value='%lu'",
virDomainMemoryLatencyTypeToString(l->accessType),
l->value);
if (l->type == VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_BANDWIDTH)
virBufferAddLit(buf, " unit='KiB'");
virBufferAddLit(buf, "/>\n");
}
if (def->ninterconnects) {
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</interconnects>\n");
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</numa>\n");
return 0;
}
int
virDomainNumaDefValidate(const virDomainNuma *def)
{
size_t i;
size_t j;
if (!def)
return 0;
for (i = 0; i < def->nmem_nodes; i++) {
const virDomainNumaNode *node = &def->mem_nodes[i];
g_autoptr(virBitmap) levelsSeen = virBitmapNew(0);
for (j = 0; j < node->ncaches; j++) {
const virDomainNumaCache *cache = &node->caches[j];
/* Relax this if there's ever fourth layer of cache */
if (cache->level > 3) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Ain't nobody heard of that much cache level"));
return -1;
}
if (virBitmapIsBitSet(levelsSeen, cache->level)) {
virReportError(VIR_ERR_XML_ERROR,
_("Cache level '%u' already defined"),
cache->level);
return -1;
}
if (virBitmapSetBitExpand(levelsSeen, cache->level))
return -1;
}
}
for (i = 0; i < def->ninterconnects; i++) {
const virDomainNumaInterconnect *l = &def->interconnects[i];
if (l->initiator >= def->nmem_nodes) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("'initiator' refers to a non-existent NUMA node"));
return -1;
}
if (l->target >= def->nmem_nodes) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("'target' refers to a non-existent NUMA node"));
return -1;
}
if (!def->mem_nodes[l->initiator].cpumask) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("NUMA nodes without CPUs can't be initiator"));
return -1;
}
if (l->cache > 0) {
for (j = 0; j < def->mem_nodes[l->target].ncaches; j++) {
numa_conf: Properly check for caches in virDomainNumaDefValidate() When adding support for HMAT, in f0611fe8830 I've introduced a check which aims to validate /domain/cpu/numa/interconnects. As a part of that, there is a loop which checks whether all <latency/> with @cache attribute refer to an existing cache level. For instance: <cpu mode='host-model' check='partial'> <numa> <cell id='0' cpus='0-5' memory='512000' unit='KiB' discard='yes'> <cache level='1' associativity='direct' policy='writeback'> <size value='8' unit='KiB'/> <line value='5' unit='B'/> </cache> </cell> <interconnects> <latency initiator='0' target='0' cache='1' type='access' value='5'/> <bandwidth initiator='0' target='0' type='access' value='204800' unit='KiB'/> </interconnects> </numa> </cpu> This XML defines that accessing L1 cache of node #0 from node #0 has latency of 5ns. However, the loop was not written properly. Well, the check in it, as it was always checking for the first cache in the target node and not the rest. Therefore, the following example errors out: <cpu mode='host-model' check='partial'> <numa> <cell id='0' cpus='0-5' memory='512000' unit='KiB' discard='yes'> <cache level='3' associativity='direct' policy='writeback'> <size value='10' unit='KiB'/> <line value='8' unit='B'/> </cache> <cache level='1' associativity='direct' policy='writeback'> <size value='8' unit='KiB'/> <line value='5' unit='B'/> </cache> </cell> <interconnects> <latency initiator='0' target='0' cache='1' type='access' value='5'/> <bandwidth initiator='0' target='0' type='access' value='204800' unit='KiB'/> </interconnects> </numa> </cpu> This errors out even though it is a valid configuration. The L1 cache under node #0 is still present. Fixes: f0611fe8830 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Laine Stump <laine@redhat.com>
2020-08-18 10:46:38 +00:00
const virDomainNumaCache *cache = &def->mem_nodes[l->target].caches[j];
if (l->cache == cache->level)
break;
}
if (j == def->mem_nodes[l->target].ncaches) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("'cache' refers to a non-existent NUMA node cache"));
return -1;
}
}
for (j = 0; j < i; j++) {
const virDomainNumaInterconnect *ll = &def->interconnects[j];
if (l->type == ll->type &&
l->initiator == ll->initiator &&
l->target == ll->target &&
l->cache == ll->cache &&
l->accessType == ll->accessType) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Duplicate info for NUMA latencies"));
return -1;
}
if (l->initiator != l->target &&
l->initiator == ll->target &&
l->target == ll->initiator) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Link already defined"));
return -1;
}
}
}
return 0;
}
unsigned int
virDomainNumaGetCPUCountTotal(virDomainNumaPtr numa)
{
size_t i;
unsigned int ret = 0;
for (i = 0; i < numa->nmem_nodes; i++) {
virBitmapPtr cpumask = virDomainNumaGetNodeCpumask(numa, i);
if (cpumask)
ret += virBitmapCountBits(cpumask);
}
return ret;
}
unsigned int
virDomainNumaGetMaxCPUID(virDomainNumaPtr numa)
{
size_t i;
unsigned int ret = 0;
for (i = 0; i < numa->nmem_nodes; i++) {
virBitmapPtr cpumask = virDomainNumaGetNodeCpumask(numa, i);
int bit;
if (cpumask) {
bit = virBitmapLastSetBit(cpumask);
if (bit > ret)
ret = bit;
}
}
return ret;
}
virDomainNumaPtr
virDomainNumaNew(void)
{
return g_new0(virDomainNuma, 1);
}
bool
virDomainNumaCheckABIStability(virDomainNumaPtr src,
virDomainNumaPtr tgt)
{
size_t i;
size_t j;
if (virDomainNumaGetNodeCount(src) != virDomainNumaGetNodeCount(tgt)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Target NUMA node count '%zu' doesn't match "
"source '%zu'"),
virDomainNumaGetNodeCount(tgt),
virDomainNumaGetNodeCount(src));
return false;
}
for (i = 0; i < virDomainNumaGetNodeCount(src); i++) {
if (virDomainNumaGetNodeMemorySize(src, i) !=
virDomainNumaGetNodeMemorySize(tgt, i)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Size of target NUMA node %zu (%llu) doesn't "
"match source (%llu)"), i,
virDomainNumaGetNodeMemorySize(tgt, i),
virDomainNumaGetNodeMemorySize(src, i));
return false;
}
if (!virBitmapEqual(virDomainNumaGetNodeCpumask(src, i),
virDomainNumaGetNodeCpumask(tgt, i))) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Processor mask of target NUMA node %zu doesn't "
"match source"), i);
return false;
}
for (j = 0; j < virDomainNumaGetNodeCount(src); j++) {
if (virDomainNumaGetNodeDistance(src, i, j) !=
virDomainNumaGetNodeDistance(tgt, i, j)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Target NUMA distance from %zu to %zu "
"doesn't match source"), i, j);
return false;
}
}
}
return true;
}
size_t
virDomainNumaGetNodeCount(virDomainNumaPtr numa)
{
if (!numa)
return 0;
return numa->nmem_nodes;
}
xenconfig: add domxml conversions for xen-xl This patch converts NUMA configurations between the Xen libxl configuration file format and libvirt's XML format. XML HVM domain on a 4 node (2 cores/socket) configuration: <cpu> <numa> <cell id='0' cpus='0-1' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='2-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='3-4' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='3' cpus='5-6' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> Xen xl.cfg domain configuration: vnuma = [["pnode=0","size=2048","vcpus=0-1","vdistances=10,21,31,21"], ["pnode=1","size=2048","vcpus=2-3","vdistances=21,10,21,31"], ["pnode=2","size=2048","vcpus=4-5","vdistances=31,21,10,21"], ["pnode=3","size=2048","vcpus=6-7","vdistances=21,31,21,10"]] If there is no XML <distances> description amongst the <cell> data the conversion schema from xml to native will generate 10 for local and 20 for all remote instances. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Jim Fehlig <jfehlig@suse.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:21 +00:00
size_t
virDomainNumaSetNodeCount(virDomainNumaPtr numa, size_t nmem_nodes)
{
if (!nmem_nodes) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot set an empty mem_nodes set"));
return 0;
}
if (numa->mem_nodes) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot alter an existing mem_nodes set"));
return 0;
}
numa->mem_nodes = g_new0(struct _virDomainNumaNode, nmem_nodes);
xenconfig: add domxml conversions for xen-xl This patch converts NUMA configurations between the Xen libxl configuration file format and libvirt's XML format. XML HVM domain on a 4 node (2 cores/socket) configuration: <cpu> <numa> <cell id='0' cpus='0-1' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='2-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='3-4' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='3' cpus='5-6' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> Xen xl.cfg domain configuration: vnuma = [["pnode=0","size=2048","vcpus=0-1","vdistances=10,21,31,21"], ["pnode=1","size=2048","vcpus=2-3","vdistances=21,10,21,31"], ["pnode=2","size=2048","vcpus=4-5","vdistances=31,21,10,21"], ["pnode=3","size=2048","vcpus=6-7","vdistances=21,31,21,10"]] If there is no XML <distances> description amongst the <cell> data the conversion schema from xml to native will generate 10 for local and 20 for all remote instances. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Jim Fehlig <jfehlig@suse.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:21 +00:00
numa->nmem_nodes = nmem_nodes;
return numa->nmem_nodes;
}
bool
virDomainNumaNodeDistanceIsUsingDefaults(virDomainNumaPtr numa,
size_t node,
size_t sibling)
{
if (node >= numa->nmem_nodes ||
sibling >= numa->nmem_nodes)
return false;
if (!numa->mem_nodes[node].distances)
return true;
if (numa->mem_nodes[node].distances[sibling].value == LOCAL_DISTANCE ||
numa->mem_nodes[node].distances[sibling].value == REMOTE_DISTANCE)
return true;
return false;
}
bool
virDomainNumaNodesDistancesAreBeingSet(virDomainNumaPtr numa)
{
size_t ncells = virDomainNumaGetNodeCount(numa);
size_t i, j;
for (i = 0; i < ncells; i++) {
for (j = 0; j < ncells; j++) {
if (virDomainNumaNodeDistanceIsUsingDefaults(numa, i, j))
continue;
return true;
}
}
return false;
}
xenconfig: add domxml conversions for xen-xl This patch converts NUMA configurations between the Xen libxl configuration file format and libvirt's XML format. XML HVM domain on a 4 node (2 cores/socket) configuration: <cpu> <numa> <cell id='0' cpus='0-1' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='2-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='3-4' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='3' cpus='5-6' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> Xen xl.cfg domain configuration: vnuma = [["pnode=0","size=2048","vcpus=0-1","vdistances=10,21,31,21"], ["pnode=1","size=2048","vcpus=2-3","vdistances=21,10,21,31"], ["pnode=2","size=2048","vcpus=4-5","vdistances=31,21,10,21"], ["pnode=3","size=2048","vcpus=6-7","vdistances=21,31,21,10"]] If there is no XML <distances> description amongst the <cell> data the conversion schema from xml to native will generate 10 for local and 20 for all remote instances. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Jim Fehlig <jfehlig@suse.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:21 +00:00
size_t
virDomainNumaGetNodeDistance(virDomainNumaPtr numa,
size_t node,
size_t cellid)
{
virDomainNumaDistancePtr distances = NULL;
if (node < numa->nmem_nodes)
distances = numa->mem_nodes[node].distances;
/*
* Present the configured distance value. If
* out of range or not available set the platform
* defined default for local and remote nodes.
*/
if (!distances ||
cellid >= numa->nmem_nodes ||
!distances[cellid].value)
xenconfig: add domxml conversions for xen-xl This patch converts NUMA configurations between the Xen libxl configuration file format and libvirt's XML format. XML HVM domain on a 4 node (2 cores/socket) configuration: <cpu> <numa> <cell id='0' cpus='0-1' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='2-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='3-4' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='3' cpus='5-6' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> Xen xl.cfg domain configuration: vnuma = [["pnode=0","size=2048","vcpus=0-1","vdistances=10,21,31,21"], ["pnode=1","size=2048","vcpus=2-3","vdistances=21,10,21,31"], ["pnode=2","size=2048","vcpus=4-5","vdistances=31,21,10,21"], ["pnode=3","size=2048","vcpus=6-7","vdistances=21,31,21,10"]] If there is no XML <distances> description amongst the <cell> data the conversion schema from xml to native will generate 10 for local and 20 for all remote instances. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Jim Fehlig <jfehlig@suse.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:21 +00:00
return (node == cellid) ? LOCAL_DISTANCE : REMOTE_DISTANCE;
return distances[cellid].value;
}
int
virDomainNumaSetNodeDistance(virDomainNumaPtr numa,
size_t node,
size_t cellid,
unsigned int value)
{
virDomainNumaDistancePtr distances;
if (node >= numa->nmem_nodes) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Argument 'node' %zu outranges "
"defined number of NUMA nodes"),
node);
return -1;
}
distances = numa->mem_nodes[node].distances;
if (!distances ||
cellid >= numa->mem_nodes[node].ndistances) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Arguments under memnode element do not "
"correspond with existing guest's NUMA cell"));
return -1;
}
/*
* Advanced Configuration and Power Interface
* Specification version 6.1. Chapter 5.2.17
* System Locality Distance Information Table
* ... Distance values of 0-9 are reserved.
*/
if (value < LOCAL_DISTANCE ||
value > UNREACHABLE) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Distance value of %d is not in valid range"),
value);
return -1;
}
if (value == LOCAL_DISTANCE && node != cellid) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Distance value %d under node %zu is "
"LOCAL_DISTANCE and should be set to 10"),
value, node);
return -1;
}
distances[cellid].cellid = cellid;
distances[cellid].value = value;
return distances[cellid].value;
}
size_t
virDomainNumaSetNodeDistanceCount(virDomainNumaPtr numa,
size_t node,
size_t ndistances)
{
virDomainNumaDistancePtr distances;
distances = numa->mem_nodes[node].distances;
if (distances) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Cannot alter an existing nmem_nodes distances set for node: %zu"),
node);
return 0;
}
distances = g_new0(struct _virDomainNumaDistance, ndistances);
xenconfig: add domxml conversions for xen-xl This patch converts NUMA configurations between the Xen libxl configuration file format and libvirt's XML format. XML HVM domain on a 4 node (2 cores/socket) configuration: <cpu> <numa> <cell id='0' cpus='0-1' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='2-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='3-4' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='3' cpus='5-6' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> Xen xl.cfg domain configuration: vnuma = [["pnode=0","size=2048","vcpus=0-1","vdistances=10,21,31,21"], ["pnode=1","size=2048","vcpus=2-3","vdistances=21,10,21,31"], ["pnode=2","size=2048","vcpus=4-5","vdistances=31,21,10,21"], ["pnode=3","size=2048","vcpus=6-7","vdistances=21,31,21,10"]] If there is no XML <distances> description amongst the <cell> data the conversion schema from xml to native will generate 10 for local and 20 for all remote instances. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Jim Fehlig <jfehlig@suse.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:21 +00:00
numa->mem_nodes[node].distances = distances;
numa->mem_nodes[node].ndistances = ndistances;
return numa->mem_nodes[node].ndistances;
}
virBitmapPtr
virDomainNumaGetNodeCpumask(virDomainNumaPtr numa,
size_t node)
{
return numa->mem_nodes[node].cpumask;
}
void
xenconfig: add domxml conversions for xen-xl This patch converts NUMA configurations between the Xen libxl configuration file format and libvirt's XML format. XML HVM domain on a 4 node (2 cores/socket) configuration: <cpu> <numa> <cell id='0' cpus='0-1' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='10'/> <sibling id='1' value='21'/> <sibling id='2' value='31'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='1' cpus='2-3' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='10'/> <sibling id='2' value='21'/> <sibling id='3' value='31'/> </distances> </cell> <cell id='2' cpus='3-4' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='31'/> <sibling id='1' value='21'/> <sibling id='2' value='10'/> <sibling id='3' value='21'/> </distances> </cell> <cell id='3' cpus='5-6' memory='2097152' unit='KiB'> <distances> <sibling id='0' value='21'/> <sibling id='1' value='31'/> <sibling id='2' value='21'/> <sibling id='3' value='10'/> </distances> </cell> </numa> </cpu> Xen xl.cfg domain configuration: vnuma = [["pnode=0","size=2048","vcpus=0-1","vdistances=10,21,31,21"], ["pnode=1","size=2048","vcpus=2-3","vdistances=21,10,21,31"], ["pnode=2","size=2048","vcpus=4-5","vdistances=31,21,10,21"], ["pnode=3","size=2048","vcpus=6-7","vdistances=21,31,21,10"]] If there is no XML <distances> description amongst the <cell> data the conversion schema from xml to native will generate 10 for local and 20 for all remote instances. Signed-off-by: Wim ten Have <wim.ten.have@oracle.com> Reviewed-by: Jim Fehlig <jfehlig@suse.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2017-11-02 15:47:21 +00:00
virDomainNumaSetNodeCpumask(virDomainNumaPtr numa,
size_t node,
virBitmapPtr cpumask)
{
numa->mem_nodes[node].cpumask = cpumask;
}
virDomainMemoryAccess
virDomainNumaGetNodeMemoryAccessMode(virDomainNumaPtr numa,
size_t node)
{
return numa->mem_nodes[node].memAccess;
}
virTristateBool
virDomainNumaGetNodeDiscard(virDomainNumaPtr numa,
size_t node)
{
return numa->mem_nodes[node].discard;
}
unsigned long long
virDomainNumaGetNodeMemorySize(virDomainNumaPtr numa,
size_t node)
{
return numa->mem_nodes[node].mem;
}
void
virDomainNumaSetNodeMemorySize(virDomainNumaPtr numa,
size_t node,
unsigned long long size)
{
numa->mem_nodes[node].mem = size;
}
unsigned long long
virDomainNumaGetMemorySize(virDomainNumaPtr numa)
{
size_t i;
unsigned long long ret = 0;
for (i = 0; i < numa->nmem_nodes; i++)
ret += numa->mem_nodes[i].mem;
return ret;
}
int
virDomainNumaFillCPUsInNode(virDomainNumaPtr numa,
size_t node,
unsigned int maxCpus)
{
g_autoptr(virBitmap) maxCPUsBitmap = virBitmapNew(maxCpus);
size_t i;
if (node >= virDomainNumaGetNodeCount(numa))
return -1;
virBitmapSetAll(maxCPUsBitmap);
for (i = 0; i < numa->nmem_nodes; i++) {
virBitmapPtr nodeCpus = virDomainNumaGetNodeCpumask(numa, i);
if (i == node || !nodeCpus)
continue;
virBitmapSubtract(maxCPUsBitmap, nodeCpus);
}
if (!virBitmapEqual(numa->mem_nodes[node].cpumask, maxCPUsBitmap)) {
virBitmapFree(numa->mem_nodes[node].cpumask);
numa->mem_nodes[node].cpumask = g_steal_pointer(&maxCPUsBitmap);
}
return 0;
}
bool
virDomainNumaHasHMAT(const virDomainNuma *numa)
{
size_t i;
if (!numa)
return false;
if (numa->ninterconnects)
return true;
for (i = 0; i < numa->nmem_nodes; i++) {
if (numa->mem_nodes[i].ncaches)
return true;
}
return false;
}
size_t
virDomainNumaGetNodeCacheCount(const virDomainNuma *numa,
size_t node)
{
if (!numa || node >= numa->nmem_nodes)
return 0;
return numa->mem_nodes[node].ncaches;
}
int
virDomainNumaGetNodeCache(const virDomainNuma *numa,
size_t node,
size_t cache,
unsigned int *level,
unsigned int *size,
unsigned int *line,
virDomainCacheAssociativity *associativity,
virDomainCachePolicy *policy)
{
const virDomainNumaNode *cell;
if (!numa || node >= numa->nmem_nodes)
return -1;
cell = &numa->mem_nodes[node];
if (cache >= cell->ncaches)
return -1;
*level = cell->caches[cache].level;
*size = cell->caches[cache].size;
*line = cell->caches[cache].line;
*associativity = cell->caches[cache].associativity;
*policy = cell->caches[cache].policy;
return 0;
}
ssize_t
virDomainNumaGetNodeInitiator(const virDomainNuma *numa,
size_t node)
{
size_t i;
unsigned int maxBandwidth = 0;
ssize_t candidateBandwidth = -1;
unsigned int minLatency = UINT_MAX;
ssize_t candidateLatency = -1;
if (!numa || node >= numa->nmem_nodes)
return -1;
/* A NUMA node which has at least one vCPU is initiator to itself by
* definition. */
if (numa->mem_nodes[node].cpumask)
return node;
/* For the rest, "NUMA node that has best performance (the lowest
* latency or largest bandwidth) to this NUMA node." */
for (i = 0; i < numa->ninterconnects; i++) {
const virDomainNumaInterconnect *l = &numa->interconnects[i];
if (l->target != node)
continue;
switch (l->type) {
case VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_LATENCY:
if (l->value < minLatency) {
minLatency = l->value;
candidateLatency = l->initiator;
}
break;
case VIR_DOMAIN_NUMA_INTERCONNECT_TYPE_BANDWIDTH:
if (l->value > maxBandwidth) {
maxBandwidth = l->value;
candidateBandwidth = l->initiator;
}
break;
}
}
if (candidateLatency >= 0)
return candidateLatency;
return candidateBandwidth;
}
size_t
virDomainNumaGetInterconnectsCount(const virDomainNuma *numa)
{
if (!numa)
return 0;
return numa->ninterconnects;
}
int
virDomainNumaGetInterconnect(const virDomainNuma *numa,
size_t i,
virDomainNumaInterconnectType *type,
unsigned int *initiator,
unsigned int *target,
unsigned int *cache,
virDomainMemoryLatency *accessType,
unsigned long *value)
{
const virDomainNumaInterconnect *l;
if (!numa || i >= numa->ninterconnects)
return -1;
l = &numa->interconnects[i];
*type = l->type;
*initiator = l->initiator;
*target = l->target;
*cache = l->cache;
*accessType = l->accessType;
*value = l->value;
return 0;
}