static int _str_to_memset(nodemask_t *mask, const char* str) { int len = strlen(str); const char *ptr = str + len - 1; int base = 0; /* skip 0x, it's all hex anyway */ if (len > 1 && !memcmp(str, "0x", 2L)) str += 2; nodemask_zero(mask); while (ptr >= str) { char val = char_to_val(*ptr); if (val == (char) -1) return -1; if (val & 1) nodemask_set(mask, base); if (val & 2) nodemask_set(mask, base+1); if (val & 4) nodemask_set(mask, base+2); if (val & 8) nodemask_set(mask, base+3); len--; ptr--; base += 4; } return 0; }
int main(void) { #if HAVE_NUMA_H nodemask_t nodemask; void hardware(); if (numa_available() < 0) { printf("This system does not support NUMA policy\n"); numa_error("numa_available"); numa_exit_on_error = 1; exit(numa_exit_on_error); } nodemask_zero(&nodemask); nodemask_set(&nodemask, 1); numa_bind(&nodemask); hardware(); return numa_exit_on_error; #else printf("NUMA is not available\n"); return 1; #endif }
int get_memset(nodemask_t *mask, slurmd_job_t *job) { int nummasks, maskid, i, threads; char *curstr, *selstr; char mstr[1 + NUMA_NUM_NODES / 4]; int local_id = job->envtp->localid; debug3("get_memset (%d) %s", job->mem_bind_type, job->mem_bind); if (job->mem_bind_type & MEM_BIND_LOCAL) { *mask = numa_get_run_node_mask(); return true; } nodemask_zero(mask); if (job->mem_bind_type & MEM_BIND_NONE) { return true; } if (job->mem_bind_type & MEM_BIND_RANK) { threads = MAX(conf->threads, 1); nodemask_set(mask, job->envtp->localid % (job->cpus*threads)); return true; } if (!job->mem_bind) return false; nummasks = 1; maskid = 0; selstr = NULL; /* get number of strings present in mem_bind */ curstr = job->mem_bind; while (*curstr) { if (nummasks == local_id+1) { selstr = curstr; maskid = local_id; break; } if (*curstr == ',') nummasks++; curstr++; } /* if we didn't already find the mask... */ if (!selstr) { /* ...select mask string by wrapping task ID into list */ maskid = local_id % nummasks; i = maskid; curstr = job->mem_bind; while (*curstr && i) { if (*curstr == ',') i--; curstr++; } if (!*curstr) { return false; } selstr = curstr; } /* extract the selected mask from the list */ i = 0; curstr = mstr; while (*selstr && *selstr != ',' && i++ < (NUMA_NUM_NODES/4)) *curstr++ = *selstr++; *curstr = '\0'; if (job->mem_bind_type & MEM_BIND_MASK) { /* convert mask string into nodemask_t mask */ if (_str_to_memset(mask, mstr) < 0) { error("_str_to_memset %s", mstr); return false; } return true; } if (job->mem_bind_type & MEM_BIND_MAP) { unsigned int my_node = 0; if (strncmp(mstr, "0x", 2) == 0) { my_node = strtoul (&(mstr[2]), NULL, 16); } else { my_node = strtoul (mstr, NULL, 10); } nodemask_set(mask, my_node); return true; } return false; }
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; }
int INTERNAL qt_affinity_gendists(qthread_shepherd_t *sheps, qthread_shepherd_id_t nshepherds) { /*{{{ */ const size_t num_extant_nodes = numa_max_node() + 1; nodemask_t bmask; qthread_debug(AFFINITY_FUNCTIONS, "sheps(%p), nshepherds(%u), num_extant_nodes:%u\n", sheps, nshepherds, (unsigned)num_extant_nodes); if (numa_available() == -1) { return QTHREAD_THIRD_PARTY_ERROR; } nodemask_zero(&bmask); /* assign nodes */ qthread_debug(AFFINITY_DETAILS, "assign nodes...\n"); for (size_t i = 0; i < nshepherds; ++i) { sheps[i].node = i % num_extant_nodes; qthread_debug(AFFINITY_DETAILS, "set bit %u in bmask\n", i % num_extant_nodes); nodemask_set(&bmask, i % num_extant_nodes); } qthread_debug(AFFINITY_DETAILS, "numa_set_interleave_mask\n"); numa_set_interleave_mask(&bmask); qthread_debug(AFFINITY_DETAILS, "querying distances...\n"); /* truly ancient versions of libnuma (in the changelog, this is * considered "pre-history") do not have numa_distance() */ for (qthread_shepherd_id_t i = 0; i < nshepherds; i++) { qthread_debug(AFFINITY_DETAILS, "i = %u < %u...\n", i, nshepherds); const unsigned int node_i = sheps[i].node; size_t j, k; sheps[i].shep_dists = calloc(nshepherds, sizeof(unsigned int)); sheps[i].sorted_sheplist = calloc(nshepherds - 1, sizeof(qthread_shepherd_id_t)); qthread_debug(AFFINITY_DETAILS, "allocs %p %p\n", sheps[i].shep_dists, sheps[i].sorted_sheplist); assert(sheps[i].shep_dists); assert(sheps[i].sorted_sheplist); for (j = 0; j < nshepherds; j++) { const unsigned int node_j = sheps[j].node; #if QTHREAD_NUMA_DISTANCE_WORKING if ((node_i != QTHREAD_NO_NODE) && (node_j != QTHREAD_NO_NODE) && (node_i != node_j)) { sheps[i].shep_dists[j] = numa_distance(node_i, node_j); } else { #endif /* XXX too arbitrary */ if (i == j) { sheps[i].shep_dists[j] = 0; } else { sheps[i].shep_dists[j] = 20; } #if QTHREAD_NUMA_DISTANCE_WORKING } #endif qthread_debug(AFFINITY_DETAILS, "shep %u to shep %u distance: %u\n", i, j, sheps[i].shep_dists[j]); } k = 0; for (j = 0; j < nshepherds; j++) { if (j != i) { sheps[i].sorted_sheplist[k++] = j; } } if (nshepherds > 1) { sort_sheps(sheps[i].shep_dists, sheps[i].sorted_sheplist, nshepherds); } } return QTHREAD_SUCCESS; } /*}}} */
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; }