int schd_bits2mask(char *string, Bitfield *mask) { int i, bit, len; Bitfield new_bit; BITFIELD_CLRALL(&new_bit); len = (int)strlen(string); /* Start with the low bit. */ bit = 0; for (i = 0; i < len; i++) { if (string[len - i - 1] == '1') BITFIELD_SETB(&new_bit, bit); else if (string[len - i - 1] != '0') return (-1); ++ bit; } /* Done. Copy the new nodemask and return success. */ BITFIELD_CPY(mask, &new_bit); return (0); }
/* * mask_mask is the mask of bits that are in this particular part of the * nodemask. ndmask is the actual nodemask in question. * * For instance, a mask_mask of: 00000000111111111111111100000000 * and a nodemask of : 00000000000000111111111100000000 * generate the output: ........------XXXXXXXXXX........ * * Note that the storage is static - copy the return before the next call! */ char * schd_format_nodemask(Bitfield *mask_mask, Bitfield *ndmask) { static char prt_bits[BITFIELD_SIZE + 2]; Bitfield bit; int idx; /* Find the most significant bit in the nodemask. */ BITFIELD_CLRALL(&bit); BITFIELD_SETB(&bit, (BITFIELD_SIZE - 1)); /* Walk the bits in the nodemask, from MSB to LSB. */ for (idx = 0; idx < BITFIELD_SIZE; idx ++) { if (BITFIELD_TSTM(&bit, mask_mask)) prt_bits[idx] = (BITFIELD_TSTM(ndmask, &bit)) ? 'X' : '-'; else prt_bits[idx] = '.'; BITFIELD_SHIFTR(&bit); } /* Null terminate the resulting string. */ prt_bits[idx] = '\0'; return (prt_bits); }
/** * @brief * availnodes() - Fill the supplied bitfield with a set bit for each node on which sufficient * resources (c.f. mapnodes.h) are configured. This is the set of nodes that * are physically available to be allocated -- policy, reserved nodes, etc, * may reduce the total number of nodes that are usable by jobs. * * NOTE: Must be called after mapnodes(). * * @param[out] maskp - pointer to Bitfield structure * * @return int * @retval 0 success * @retval !0 failure * */ int availnodes(Bitfield *maskp) { int node, i, count; Bitfield avail; /* This function needs a valid node map in order to find available nodes. */ if (nodemap == NULL) return 1; /* * If minimum resource values are not set, default them to reasonable * defaults. */ if (minnodemem < 0) minnodemem = minmem; if (minnodecpus < 0) minnodecpus = mincpus; if (memreserved < 0) memreserved = 0; (void)sprintf(log_buffer, "Minimum node resources: %d cpus, %d MB, %d MB rsvd", minnodecpus, minnodemem, memreserved); log_err(-1, __func__, log_buffer); BITFIELD_CLRALL(&avail); /* * Walk through the node map, checking for sufficient resources on each * node, and setting the appropriate bit on the mask for that node if it * is sufficiently endowed. See mapnodes.h for definition of "sufficient". */ for (node = 0; node <= maxnodeid; node++) { /* Enough CPUs? If not, skip it. */ for (count = i = 0; i < MAX_CPUS_PER_NODE; i++) if (nodemap[node].cpu[i] >= 0) count ++; /* Enough memory and cpus? If not, skip it. */ if (nodemap[node].memory < minnodemem || count < minnodecpus) { (void)sprintf(log_buffer, "node %d has only %luMB and %d cpus - cannot use", node, nodemap[node].memory, count); log_err(-1, __func__, log_buffer); continue; } /* Node has sufficient resources. Count this node as available. */ BITFIELD_SETB(&avail, node); } /* Copy the available mask to the passed-in storage, and return success. */ BITFIELD_CPY(maskp, &avail); return 0; }
int schd_alloc_nodes(int nnodes, Queue *queue, Bitfield *job_mask) { Bitfield *queue_mask; Bitfield *q_avail_mask; Bitfield new_bit; int candidate; int n_found; n_found = 0; BITFIELD_CLRALL(&new_bit); queue_mask = &(queue->queuemask); q_avail_mask = &(queue->availmask); candidate = (BITFIELD_SIZE - 1); while ((n_found < nnodes) && (candidate >= 0)) { if (BITFIELD_TSTB(queue_mask, candidate)) { if (BITFIELD_TSTB(q_avail_mask, candidate)) { /* available */ BITFIELD_SETB(&new_bit, candidate); ++n_found; } } -- candidate; } /* * If enough nodes were allocated, copy the resultant new nodemask * into the supplied area. */ if (nnodes == n_found) { BITFIELD_CPY(job_mask, &new_bit); return nnodes; } /* Didn't get enough nodes. Return 0 as an error. */ return 0; }
int schd_str2mask(char *maskstr, Bitfield *maskp) { char *id = "str2mask"; Bitfield nodemask; char hex; int ndbit = 0, len, dec, hxbit; unsigned long long compat; char *ptr; char buf[32]; if (maskstr == NULL) return (-1); /* Nodemask string must be in the format '0x...'. */ if ((maskstr[0] != '0') || (tolower(maskstr[1]) != 'x')) { /* XXX * For backwards compatability, if the string will convert * into an unsigned long long, then assume this is an old- * style decimal nodemask (on 8-128P machines, nodemask is * an unsigned long long, and was treated as such). * * Note that this assumes that sizeof(unsigned long long) * is the same as sizeof(unsigned long), which is only the * case with the 64-bit SGI compiler ABI. */ compat = strtoul(maskstr, &ptr, 10); if (*ptr != '\0') return (-1); /* * String converted to an unsigned long long. Print it as * a hex back into a buffer, and point at that buffer instead. * This will cause the newly created hex string to be used. */ (void)sprintf(buf, "0x%llx", compat); maskstr = buf; (void)sprintf(log_buffer, "converted old-style nodemask %lu to %s", compat, maskstr); log_record(PBSEVENT_SYSTEM, PBS_EVENTCLASS_SERVER, id, log_buffer); } /* Zero out the new nodemask struct, and fill it from the maskstr. */ BITFIELD_CLRALL(&nodemask); /* Walk backwards through the hex digits in the string 0x... */ for (len = (int)strlen(maskstr); len > 2 /* 0x... */; len --) { hex = maskstr[len - 1]; /* Make sure it's a hex digit. */ if (!isxdigit((int)hex)) return (-1); /* If this digit is a '0', it contributes nothing. */ if (hex != '0') { /* Convert the hex digit to a decimal int. */ dec = isdigit((int)hex) ? (hex - '0') : (tolower((int)hex) - 'a' + 10); for (hxbit = 0; hxbit < 4; hxbit ++) { if (dec & (1 << hxbit)) BITFIELD_SETB(&nodemask, ndbit); ndbit ++; } } else ndbit += 4; /* Make sure we haven't walked past the end of the nodemask. */ if (ndbit > (sizeof(Bitfield) * 8)) return (-1); } /* Copy the newly created nodemask into the handed-in one. */ BITFIELD_CPY(maskp, &nodemask); return (0); }
int schd_alloc_nodes(int request, Queue *queue, Bitfield *maskp) { char *id = "schd_alloc_nodes"; Bitfield avail; Bitfield mask; Bitfield contig; int remain; int qmsb; int qlsb; int i, n; int count; int found; /* Make certain the nodecount request can be fulfilled. */ if (request <= 0 || request > BITFIELD_NUM_ONES(&(queue->availmask))) return 0; /* * Make a copy of the queue's available bit mask to play with, and clear * the allocated nodes mask. */ BITFIELD_CPY(&avail, &(queue->availmask)); BITFIELD_CLRALL(&mask); /* How many have been found, and how many remain. */ found = 0; remain = request; while (remain > 0) { /* * Find first and last available bit positions in the * queue's available node mask. */ qmsb = BITFIELD_MS_ONE(&avail); qlsb = BITFIELD_LS_ONE(&avail); /* * Starting with the size of the remaining nodes needed to satisfy * this request, look for a set of 'n' contiguous bits in the * available node mask. If that is not found, try the next smallest * contiguous vector, etc. */ for (n = remain; n > 0; n--) { /* * Create a contiguous bitmask of 'n' bits, starting at the * position of the highest bit in the avail mask. */ BITFIELD_CLRALL(&contig); for (i = 0; i < n; i++) BITFIELD_SETB(&contig, qmsb - i); /* * Calculate how many times this contiguous bitmask needs to be * shifted to the right to cover every set of 'n' bits between * the qmsb and qlsb, inclusive. Count the initial configuration * as well (the trailing '+ 1'). */ count = (qmsb + 1 - qlsb) - n + 1; /* * Shift the contiguous mask right one bit at a time, checking * if all the bits in the mask are set in the available mask. */ for (i = 0; i < count; i++) { /* Are all bits in contig also set in the avail mask? */ if (BITFIELD_TSTALLM(&avail, &contig)) { break; } BITFIELD_SHIFTR(&contig); } /* * If the contiguous bits are available, add them to the new job * nodemask, and remove them from the avail mask. Adjust the * remaining node count, and start the next hunt for the remaining * nodes. */ if (i < count) { BITFIELD_SETM(&mask, &contig); BITFIELD_CLRM(&avail, &contig); found += n; remain -= n; break; /* for(n) loop */ } } /* Check for something going wrong. */ if (n == 0) { DBPRT(("%s: couldn't find any contiguous bits (even one!)\n", id)); break; /* while(remain) loop */ } } /* * If no bits remain to be allocated, copy the new mask into the provided * space, and return the number of bits requested. */ if (!remain && (found == request)) { BITFIELD_CPY(maskp, &mask); DBPRT(("%s: mask %s\n", id, schd_format_nodemask(&queue->queuemask, maskp))); return found; } return 0; }