int virQEMUBuildCommandLineJSONArrayBitmap(const char *key, virJSONValuePtr array, virBufferPtr buf) { ssize_t pos = -1; ssize_t end; virBitmapPtr bitmap = NULL; if (virJSONValueGetArrayAsBitmap(array, &bitmap) < 0) return -1; while ((pos = virBitmapNextSetBit(bitmap, pos)) > -1) { if ((end = virBitmapNextClearBit(bitmap, pos)) < 0) end = virBitmapLastSetBit(bitmap) + 1; if (end - 1 > pos) { virBufferAsprintf(buf, "%s=%zd-%zd,", key, pos, end - 1); pos = end; } else { virBufferAsprintf(buf, "%s=%zd,", key, pos); } } virBitmapFree(bitmap); return 0; }
/* Check whether the host subcore configuration is valid. * * A valid configuration is one where no secondary thread is online; * the primary thread in a subcore is always the first one */ static bool virHostCPUHasValidSubcoreConfiguration(int threads_per_subcore) { virBitmapPtr online_cpus = NULL; int cpu = -1; bool ret = false; /* No point in checking if subcores are not in use */ if (threads_per_subcore <= 0) goto cleanup; if (!(online_cpus = virHostCPUGetOnlineBitmap())) goto cleanup; while ((cpu = virBitmapNextSetBit(online_cpus, cpu)) >= 0) { /* A single online secondary thread is enough to * make the configuration invalid */ if (cpu % threads_per_subcore != 0) goto cleanup; } ret = true; cleanup: virBitmapFree(online_cpus); return ret; }
/* * Linux maintains cpu bit map. For example, if cpuid=5's flag is not set * and max cpu is 7. The map file shows 0-4,6-7. This function parses * it and returns cpumap. */ static virBitmapPtr linuxParseCPUmap(int *max_cpuid, const char *path) { virBitmapPtr map = NULL; char *str = NULL; int max_id = 0, i; if (virFileReadAll(path, 5 * VIR_DOMAIN_CPUMASK_LEN, &str) < 0) { virReportOOMError(); goto error; } if (virBitmapParse(str, 0, &map, VIR_DOMAIN_CPUMASK_LEN) < 0) { goto error; } i = -1; while ((i = virBitmapNextSetBit(map, i)) >= 0) { max_id = i; } *max_cpuid = max_id; VIR_FREE(str); return map; error: VIR_FREE(str); virBitmapFree(map); return NULL; }
/** * virBitmapFormat: * @bitmap: the bitmap * * This function is the counterpart of virBitmapParse. This function creates * a human-readable string representing the bits in bitmap. * * See virBitmapParse for the format of @str. * * Returns the string on success or NULL otherwise. Caller should call * VIR_FREE to free the string. */ char *virBitmapFormat(virBitmapPtr bitmap) { virBuffer buf = VIR_BUFFER_INITIALIZER; bool first = true; int start, cur, prev; if (!bitmap) return NULL; cur = virBitmapNextSetBit(bitmap, -1); if (cur < 0) { char *ret; ignore_value(VIR_STRDUP(ret, "")); return ret; } start = prev = cur; while (prev >= 0) { cur = virBitmapNextSetBit(bitmap, prev); if (cur == prev + 1) { prev = cur; continue; } /* cur < 0 or cur > prev + 1 */ if (!first) virBufferAddLit(&buf, ","); else first = false; if (prev == start) virBufferAsprintf(&buf, "%d", start); else virBufferAsprintf(&buf, "%d-%d", start, prev); start = prev = cur; } if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); return NULL; } return virBufferContentAndReset(&buf); }
virBitmapPtr virCapabilitiesGetCpusForNodemask(virCapsPtr caps, virBitmapPtr nodemask) { virBitmapPtr ret = NULL; unsigned int maxcpu = virCapabilitiesGetHostMaxcpu(caps); ssize_t node = -1; if (!(ret = virBitmapNew(maxcpu + 1))) return NULL; while ((node = virBitmapNextSetBit(nodemask, node)) >= 0) { if (virCapabilitiesGetCpusForNode(caps, node, ret) < 0) { virBitmapFree(ret); return NULL; } } return ret; }
int virNumaSetupMemoryPolicy(virDomainNumatuneMemMode mode, virBitmapPtr nodeset) { nodemask_t mask; int node = -1; int ret = -1; int bit = 0; size_t i; int maxnode = 0; if (!nodeset) return 0; if (!virNumaNodesetIsAvailable(nodeset)) return -1; maxnode = numa_max_node(); maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; /* Convert nodemask to NUMA bitmask. */ nodemask_zero(&mask); bit = -1; while ((bit = virBitmapNextSetBit(nodeset, bit)) >= 0) { if (bit > maxnode) { virReportError(VIR_ERR_INTERNAL_ERROR, _("NUMA node %d is out of range"), bit); return -1; } nodemask_set(&mask, bit); } switch (mode) { case VIR_DOMAIN_NUMATUNE_MEM_STRICT: numa_set_bind_policy(1); numa_set_membind(&mask); numa_set_bind_policy(0); break; case VIR_DOMAIN_NUMATUNE_MEM_PREFERRED: { int nnodes = 0; for (i = 0; i < NUMA_NUM_NODES; i++) { if (nodemask_isset(&mask, i)) { node = i; nnodes++; } } if (nnodes != 1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("NUMA memory tuning in 'preferred' mode " "only supports single node")); goto cleanup; } numa_set_bind_policy(0); numa_set_preferred(node); } break; case VIR_DOMAIN_NUMATUNE_MEM_INTERLEAVE: numa_set_interleave_mask(&mask); break; case VIR_DOMAIN_NUMATUNE_MEM_LAST: break; } ret = 0; cleanup: return ret; }
int virNumaSetupMemoryPolicy(virNumaTuneDef numatune, virBitmapPtr nodemask) { nodemask_t mask; int mode = -1; int node = -1; int ret = -1; int i = 0; int maxnode = 0; virBitmapPtr tmp_nodemask = NULL; if (numatune.memory.placement_mode == VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC) { if (!numatune.memory.nodemask) return 0; VIR_DEBUG("Set NUMA memory policy with specified nodeset"); tmp_nodemask = numatune.memory.nodemask; } else if (numatune.memory.placement_mode == VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_AUTO) { VIR_DEBUG("Set NUMA memory policy with advisory nodeset from numad"); tmp_nodemask = nodemask; } else { return 0; } if (numa_available() < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Host kernel is not aware of NUMA.")); return -1; } maxnode = numa_max_node() + 1; /* Convert nodemask to NUMA bitmask. */ nodemask_zero(&mask); i = -1; while ((i = virBitmapNextSetBit(tmp_nodemask, i)) >= 0) { if (i > maxnode || i > NUMA_NUM_NODES) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Nodeset is out of range, host cannot support " "NUMA node bigger than %d"), i); return -1; } nodemask_set(&mask, i); } mode = numatune.memory.mode; if (mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT) { numa_set_bind_policy(1); numa_set_membind(&mask); numa_set_bind_policy(0); } else if (mode == VIR_DOMAIN_NUMATUNE_MEM_PREFERRED) { int nnodes = 0; for (i = 0; i < NUMA_NUM_NODES; i++) { if (nodemask_isset(&mask, i)) { node = i; nnodes++; } } if (nnodes != 1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("NUMA memory tuning in 'preferred' mode " "only supports single node")); goto cleanup; } numa_set_bind_policy(0); numa_set_preferred(node); } else if (mode == VIR_DOMAIN_NUMATUNE_MEM_INTERLEAVE) { numa_set_interleave_mask(&mask); } else { /* XXX: Shouldn't go here, as we already do checking when * parsing domain XML. */ virReportError(VIR_ERR_XML_ERROR, "%s", _("Invalid mode for memory NUMA tuning.")); goto cleanup; } ret = 0; cleanup: return ret; }
static int virQEMUBuildObjectCommandLinePropsInternal(const char *key, const virJSONValue *value, virBufferPtr buf, bool nested) { virJSONValuePtr elem; virBitmapPtr bitmap = NULL; ssize_t pos = -1; ssize_t end; size_t i; switch ((virJSONType) value->type) { case VIR_JSON_TYPE_STRING: virBufferAsprintf(buf, ",%s=%s", key, value->data.string); break; case VIR_JSON_TYPE_NUMBER: virBufferAsprintf(buf, ",%s=%s", key, value->data.number); break; case VIR_JSON_TYPE_BOOLEAN: if (value->data.boolean) virBufferAsprintf(buf, ",%s=yes", key); else virBufferAsprintf(buf, ",%s=no", key); break; case VIR_JSON_TYPE_ARRAY: if (nested) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nested -object property arrays are not supported")); return -1; } if (virJSONValueGetArrayAsBitmap(value, &bitmap) == 0) { while ((pos = virBitmapNextSetBit(bitmap, pos)) > -1) { if ((end = virBitmapNextClearBit(bitmap, pos)) < 0) end = virBitmapLastSetBit(bitmap) + 1; if (end - 1 > pos) { virBufferAsprintf(buf, ",%s=%zd-%zd", key, pos, end - 1); pos = end; } else { virBufferAsprintf(buf, ",%s=%zd", key, pos); } } } else { /* fallback, treat the array as a non-bitmap, adding the key * for each member */ for (i = 0; i < virJSONValueArraySize(value); i++) { elem = virJSONValueArrayGet((virJSONValuePtr)value, i); /* recurse to avoid duplicating code */ if (virQEMUBuildObjectCommandLinePropsInternal(key, elem, buf, true) < 0) return -1; } } break; case VIR_JSON_TYPE_OBJECT: case VIR_JSON_TYPE_NULL: virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("NULL and OBJECT JSON types can't be converted to " "commandline string")); return -1; } virBitmapFree(bitmap); return 0; }
static int virLXCControllerSetupNUMAPolicy(virLXCControllerPtr ctrl) { nodemask_t mask; int mode = -1; int node = -1; int ret = -1; int i = 0; int maxnode = 0; bool warned = false; if (!ctrl->def->numatune.memory.nodemask) return 0; VIR_DEBUG("Setting NUMA memory policy"); if (numa_available() < 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Host kernel is not aware of NUMA.")); return -1; } maxnode = numa_max_node() + 1; /* Convert nodemask to NUMA bitmask. */ nodemask_zero(&mask); i = -1; while ((i = virBitmapNextSetBit(ctrl->def->numatune.memory.nodemask, i)) >= 0) { if (i > NUMA_NUM_NODES) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Host cannot support NUMA node %d"), i); return -1; } if (i > maxnode && !warned) { VIR_WARN("nodeset is out of range, there is only %d NUMA " "nodes on host", maxnode); warned = true; } nodemask_set(&mask, i); } mode = ctrl->def->numatune.memory.mode; if (mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT) { numa_set_bind_policy(1); numa_set_membind(&mask); numa_set_bind_policy(0); } else if (mode == VIR_DOMAIN_NUMATUNE_MEM_PREFERRED) { int nnodes = 0; for (i = 0; i < NUMA_NUM_NODES; i++) { if (nodemask_isset(&mask, i)) { node = i; nnodes++; } } if (nnodes != 1) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("NUMA memory tuning in 'preferred' mode " "only supports single node")); goto cleanup; } numa_set_bind_policy(0); numa_set_preferred(node); } else if (mode == VIR_DOMAIN_NUMATUNE_MEM_INTERLEAVE) { numa_set_interleave_mask(&mask); } else { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unable to set NUMA policy %s"), virDomainNumatuneMemModeTypeToString(mode)); goto cleanup; } ret = 0; cleanup: return ret; }