static char * _memset_to_str(nodemask_t *mask, char *str) { int base, begin = 0; char *ptr = str; char *ret = 0; for (base = NUMA_NUM_NODES - 4; base >= 0; base -= 4) { char val = 0; if (nodemask_isset(mask, base)) val |= 1; if (nodemask_isset(mask, base + 1)) val |= 2; if (nodemask_isset(mask, base + 2)) val |= 4; if (nodemask_isset(mask, base + 3)) val |= 8; if ((begin == 0) && (val == 0) && (base > 124)) { /* try to keep output to 32 bit mask */ continue; } begin = 1; if (!ret && val) ret = ptr; *ptr++ = val_to_char(val); } *ptr = 0; return ret ? ret : ptr - 1; }
static int filter_nodemask_mem(nodemask_t * nodemask, unsigned long max_node) { #if MPOL_F_MEMS_ALLOWED unsigned long nodemask_size = max_node / 8 + 1; memset(nodemask, 0, nodemask_size); /* * avoid numa_get_mems_allowed(), because of bug in getpol() * utility function in older versions: * http://www.spinics.net/lists/linux-numa/msg00849.html */ if (ltp_syscall(__NR_get_mempolicy, NULL, nodemask->n, max_node, 0, MPOL_F_MEMS_ALLOWED) < 0) return -2; #else int i; /* * old libnuma/kernel don't have MPOL_F_MEMS_ALLOWED, so let's assume * that we can use any node with memory > 0 */ for (i = 0; i < max_node; i++) { if (!nodemask_isset(nodemask, i)) continue; if (numa_node_size64(i, NULL) <= 0) nodemask_clr(nodemask, i); } #endif /* MPOL_F_MEMS_ALLOWED */ return 0; }
/* * get_current_nodeid_list() - fill arg array with nodes from * current thread's allowed node mask. return # of nodes in * mask. */ static int get_current_nodeid_list(unsigned int *fromids) { /* * FIXME (garrcoop): gcp is unitialized and shortly hereafter used in * an initialization statement..... UHHHHHHH... test writer fail? */ glctx_t *gcp; nodemask_t my_allowed_nodes; int nr_nodes = 0, max_node = gcp->numa_max_node; int node; gcp = &glctx; #if defined(LIBNUMA_API_VERSION) && LIBNUMA_API_VERSION == 2 my_allowed_nodes = numa_get_membind_compat(); #else my_allowed_nodes = numa_get_membind(); #endif for (node = 0; node <= max_node; ++node) { if (nodemask_isset(&my_allowed_nodes, node)) *(fromids + nr_nodes++) = node; } /* * shouldn't happen, but let 'em know if it does */ if (nr_nodes == 0) fprintf(stderr, "%s: my allowed node mask is empty !!???\n", gcp->program_name); return nr_nodes; }
int slurm_set_memset(char *path, nodemask_t *new_mask) { char file_path[PATH_MAX]; char mstr[1 + CPU_SETSIZE * 4], tmp[10]; int fd, i, max_node; ssize_t rc; snprintf(file_path, sizeof(file_path), "%s/mems", path); fd = open(file_path, O_CREAT | O_RDWR, 0700); if (fd < 0) { error("open(%s): %m", file_path); return -1; } mstr[0] = '\0'; max_node = numa_max_node(); for (i=0; i<=max_node; i++) { if (!nodemask_isset(new_mask, i)) continue; snprintf(tmp, sizeof(tmp), "%d", i); if (mstr[0]) strcat(mstr, ","); strcat(mstr, tmp); } i = strlen(mstr) + 1; rc = write(fd, mstr, i+1); close(fd); if (rc <= i) { error("write(%s): %m", file_path); return -1; } return 0; }
static void _numa_set_preferred(nodemask_t *new_mask) { int i; for (i = 0; i < NUMA_NUM_NODES; i++) { if (nodemask_isset(new_mask, i)) { numa_set_preferred(i); break; } } }
/* * get_arg_nodeid_list() -- get list [array] of node ids from comma-separated list. * * on success, returns count of id's in list; on error -1 */ static int get_arg_nodeid_list(char *args, unsigned int *list) { glctx_t *gcp; char *next; nodemask_t my_allowed_nodes; int node, count = 0; gcp = &glctx; #if defined(LIBNUMA_API_VERSION) && LIBNUMA_API_VERSION == 2 my_allowed_nodes = numa_get_membind_compat(); #else my_allowed_nodes = numa_get_membind(); #endif while (*args != '\0') { if (!isdigit(*args)) { fprintf(stderr, "%s: expected digit for <node/list>\n", gcp->program_name); return -1; } node = strtoul(args, &next, 10); if (node > gcp->numa_max_node) { fprintf(stderr, "%s: node ids must be <= %d\n", gcp->program_name, gcp->numa_max_node); return -1; } if (!nodemask_isset(&my_allowed_nodes, node)) { fprintf(stderr, "%s: node %d is not in my allowed node mask\n", gcp->program_name, node); return -1; } *(list + count++) = node; if (*next == '\0') return count; if (*next != ',') { break; } if (count >= gcp->numa_max_node) { fprintf(stderr, "%s: too many node ids in list\n", gcp->program_name); } args = next + 1; } return -1; }
/* * get_allowed_nodes_arr - get number and array of available nodes * @num_nodes: pointer where number of available nodes will be stored * @nodes: array of available node ids, this is MPOL_F_MEMS_ALLOWED * node bitmask compacted (without holes), so that each field * contains node number. If NULL only num_nodes is * returned, otherwise it cotains new allocated array, * which caller is responsible to free. * RETURNS: * 0 on success * -1 on allocation failure * -2 on get_mempolicy failure */ int get_allowed_nodes_arr(int flag, int *num_nodes, int **nodes) { int ret = 0; #if HAVE_NUMA_H int i; nodemask_t *nodemask = NULL; #endif *num_nodes = 0; if (nodes) *nodes = NULL; #if HAVE_NUMA_H unsigned long max_node = LTP_ALIGN(get_max_node(), sizeof(unsigned long)*8); unsigned long nodemask_size = max_node / 8; nodemask = malloc(nodemask_size); if (nodes) *nodes = malloc(sizeof(int) * max_node); do { if (nodemask == NULL || (nodes && (*nodes == NULL))) { ret = -1; break; } /* allow all nodes at start, then filter based on flags */ get_nodemask_allnodes(nodemask, max_node); if ((flag & NH_MEMS) == NH_MEMS) { ret = filter_nodemask_mem(nodemask, max_node); if (ret < 0) break; } if ((flag & NH_CPUS) == NH_CPUS) filter_nodemask_cpu(nodemask, max_node); for (i = 0; i < max_node; i++) { if (nodemask_isset(nodemask, i)) { if (nodes) (*nodes)[*num_nodes] = i; (*num_nodes)++; } } } while (0); free(nodemask); #endif return ret; }
static void filter_nodemask_cpu(nodemask_t * nodemask, unsigned long max_node) { char *cpumask = NULL; char fn[64]; FILE *f; size_t len; int i, ret; for (i = 0; i < max_node; i++) { if (!nodemask_isset(nodemask, i)) continue; sprintf(fn, "/sys/devices/system/node/node%d/cpumap", i); f = fopen(fn, "r"); if (f) { ret = getdelim(&cpumask, &len, '\n', f); if ((ret > 0) && (!cpumask_has_cpus(cpumask, len))) nodemask_clr(nodemask, i); fclose(f); } } free(cpumask); }
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 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; }