qemu_command: Introduce qemuBuildThreadContextProps()

The aim of thread-context object is to set affinity on threads
that allocate memory for a memory-backend-* object. For instance:

-object '{"qom-type":"thread-context","id":"tc-ram-node0","node-affinity":[3]}' \
-object '{"qom-type":"memory-backend-memfd","id":"ram-node0","hugetlb":true,\
          "hugetlbsize":2097152,"share":true,"prealloc":true,"prealloc-threads":8,\
          "size":15032385536,"host-nodes":[3],"policy":"preferred",\
          "prealloc-context":"tc-ram-node0"}' \

allocates 14GiB worth of memory, backed by 2MiB hugepages from
host NUMA node 3, using 8 threads. If it weren't for
thread-context these threads wouldn't have any affinity and thus
theoretically could be scheduled to run on CPUs of different NUMA
node (which is what I saw occasionally).

Therefore, whenever we are pinning memory (IOW setting host-nodes
attribute), we can generate thread-context object with the same
affinity.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
This commit is contained in:
Michal Privoznik 2022-11-02 12:08:52 +01:00
parent d5320907e3
commit b03386d148
2 changed files with 52 additions and 0 deletions

View File

@ -3603,6 +3603,53 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg,
}
int
qemuBuildThreadContextProps(virJSONValue **tcProps,
virJSONValue **memProps,
qemuDomainObjPrivate *priv)
{
g_autoptr(virJSONValue) props = NULL;
virJSONValue *nodemask = NULL;
g_autoptr(virJSONValue) nodemaskCopy = NULL;
g_autofree char *tcAlias = NULL;
const char *memalias = NULL;
*tcProps = NULL;
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_THREAD_CONTEXT))
return 0;
nodemask = virJSONValueObjectGetArray(*memProps, "host-nodes");
if (!nodemask)
return 0;
memalias = virJSONValueObjectGetString(*memProps, "id");
if (!memalias) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("memory device alias is not assigned"));
return -1;
}
tcAlias = g_strdup_printf("tc-%s", memalias);
nodemaskCopy = virJSONValueCopy(nodemask);
if (virJSONValueObjectAdd(&props,
"s:qom-type", "thread-context",
"s:id", tcAlias,
"a:node-affinity", &nodemaskCopy,
NULL) < 0)
return -1;
if (virJSONValueObjectAdd(memProps,
"s:prealloc-context", tcAlias,
NULL) < 0)
return -1;
*tcProps = g_steal_pointer(&props);
return 0;
}
static char *
qemuBuildLegacyNicStr(virDomainNetDef *net)
{

View File

@ -147,6 +147,11 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg,
const virDomainDef *def,
const virDomainMemoryDef *mem);
int
qemuBuildThreadContextProps(virJSONValue **tcProps,
virJSONValue **memProps,
qemuDomainObjPrivate *priv);
/* Current, best practice */
virJSONValue *
qemuBuildPCIHostdevDevProps(const virDomainDef *def,