/* zero_out_sent() */ static void zero_out_sent(struct tree_ *t) { link_t *stack; struct tree_node_ *root; struct tree_node_ *n; struct share_acct *s; stack = make_link(); root = t->root; n = root->child; znovu: while (n) { if (n->child) enqueue_link(stack, n); s = n->data; s->sent = 0; n = n->right; } n = pop_link(stack); if (n) { root = n; n = root->child; goto znovu; } fin_link(stack); }
void freeResVal(struct resVal *resVal) { struct _rusage_ *r; if (resVal == NULL) return; FREEUP(resVal->indicies); FREEUP(resVal->selectStr); resVal->selectStrSize = 0; if (resVal->xorExprs) { int i; for (i = 0; resVal->xorExprs[i]; i++) FREEUP(resVal->xorExprs[i]); FREEUP(resVal->xorExprs); } _free_(resVal->val); _free_(resVal->rusage_bit_map); while ((r = pop_link(resVal->rl))) { _free_(r->bitmap); _free_(r->val); _free_(r); } fin_link(resVal->rl); }
/* sort_tree_by_shares() */ static void sort_tree_by_shares(struct tree_ *t) { link_t *stack; struct tree_node_ *root; struct tree_node_ *n; stack = make_link(); root = t->root; n = root->child; znovu: while (n) { if (n->child) enqueue_link(stack, n); n = n->right; } sort_siblings(root, node_cmp); n = pop_link(stack); if (n) { root = n; n = root->child; goto znovu; } fin_link(stack); make_leafs(t); }
/* parse_user_shares() * * parse user_shares[[g, 1] [e,1]] */ static link_t * parse_user_shares(const char *user_shares) { link_t *l; char *p; char *u; int cc; int n; struct share_acct *sacct; uint32_t sum_shares; linkiter_t iter; u = strdup(user_shares); assert(u); p = strchr(u, '['); *p++ = 0; tokenize(p); l = make_link(); sum_shares = 0; while (1 ) { char name[128]; uint32_t shares; cc = sscanf(p, "%s%u%n", name, &shares, &n); if (cc == EOF) break; if (cc != 2) goto bail; p = p + n; sacct = make_sacct(name, shares); assert(sacct); sum_shares = sum_shares + sacct->shares; enqueue_link(l, sacct); } traverse_init(l, &iter); while ((sacct = traverse_link(&iter))) { sacct->dshares = (double)sacct->shares/(double)sum_shares; } _free_(u); return l; bail: _free_(u); traverse_init(l, &iter); while ((sacct = traverse_link(&iter))) free_sacct(sacct); fin_link(l); return NULL; }
/* sort_tree_by_deviate() * */ static void sort_tree_by_deviate(struct tree_ *t) { struct tree_node_ *n; struct tree_node_ *n2; struct tree_node_ *root; link_t *stack; struct share_acct *s; uint64_t sum; uint64_t avail; stack = make_link(); root = t->root; n = root->child; znovu: n2 = n; sum = 0; while (n) { if (n->child) enqueue_link(stack, n); s = n->data; s->dsrv2 = 0; /* sum up the historical. */ sum = sum + s->numRAN; n = n->right; } avail = sum; n = n2; while (n) { avail = avail - compute_deviate(n, sum, avail); assert(avail >= 0); n = n->right; } sort_siblings(root, node_cmp2); n = pop_link(stack); if (n) { root = n; n = n->child; goto znovu; } fin_link(stack); make_leafs(t); }
/* sshare_make_tree() * In this function we match the user_shares as configured * in the queue file with the groups configured in lsb.users. * The fairshare configuration in the queues can be such * that they don't match for example: * * FAIRSHARE = USER_SHARES[[crock ,2] [zebra, 1]] * FAIRSHARE = USER_SHARES[[all, 1]] * * in these cases the shares are specified for users * directly and no groups are involved. */ struct tree_ *sshare_make_tree(const char *user_shares, uint32_t num_grp, struct group_acct *grp) { struct tree_ *t; link_t *l; link_t *stack; linkiter_t iter; struct share_acct *sacct; struct tree_node_ *n; struct tree_node_ *root; n = NULL; stack = make_link(); t = tree_init(""); /* root summarizes all the tree counters */ t->root->data = make_sacct("/", 1); root = NULL; /* First parse the user shares and make * the first level of the tree */ l = parse_user_shares(user_shares); z: if (root) l = parse_group_member(n->name, num_grp, grp); else root = t->root; if (l == NULL) { free_sacct(t->root->data); fin_link(stack); tree_free(t, free_sacct); return NULL; } traverse_init(l, &iter); while ((sacct = traverse_link(&iter))) { n = calloc(1, sizeof(struct tree_node_)); /* dup() the name as later we free both * the tree node and the share account */ n->name = strdup(sacct->name); n = tree_insert_node(root, n); enqueue_link(stack, n); n->data = sacct; } /* Sort by shares so the tree * is always sorted by share * priority */ sort_siblings(root, node_cmp); fin_link(l); n = pop_link(stack); if (n) { root = n; goto z; } fin_link(stack); n = t->root; while ((n = tree_next_node(n))) { char buf[BUFSIZ]; /* Create the hash table of nodes and their * immediate parent. */ sacct = n->data; if (n->child == NULL) { /* all and default are synonyms as they * both indicate a user that is not explicitly * defined. */ if (strcasecmp(sacct->name, "all") == 0 || strcasecmp(sacct->name, "default") == 0) { sacct->options |= SACCT_USER_ALL; } sacct->options |= SACCT_USER; sprintf(buf, "%s/%s", n->parent->name, n->name); hash_install(t->node_tab, buf, n, NULL); } else { sacct->options |= SACCT_GROUP; } sprintf(buf, "%s", n->name); hash_install(t->node_tab, buf, n, NULL); print_node(n, t); } traverse_init(t->leafs, &iter); while ((n = traverse_link(&iter))) print_node(n, t); /* Fairshare tree is built and sorted * by decreasing shares, the scheduler * algorithm will fill it up with * slots from now on. */ tree_walk2(t, print_node); sort_tree_by_shares(t); return t; }
/* sshare_distribute_own_slots() */ int sshare_distribute_own_slots(struct tree_ *t, uint32_t slots) { struct tree_node_ *n; link_t *stack; struct share_acct *sacct; uint32_t avail; int tried; int first; stack = make_link(); /* This must be emptied after every scheduling * cycle. There could be still some leafs * if not all jobs got dispatched. */ while (pop_link(t->leafs)) ; avail = slots; sort_tree_by_deviate(t); zero_out_sent(t); tried = 0; /* only after sort get the first child */ n = t->root->child; first = 0; znovu: /* Iterate at each tree level but * don't traverse branches without * tokens. */ while (n) { sacct = n->data; /* all is a dummy share account the * tree is populated with real ones. */ if (sacct->options & SACCT_USER_ALL) { n = n->right; continue; } /* enqueue as we want to traverse * the tree by priority */ if (n->child) enqueue_link(stack, n); /* Enforce the ownership/guarantee at the * first level of the tree. */ if (first == 0) { if (sacct->numRUN > sacct->shares) sacct->sent = 0; else sacct->sent = sacct->shares - sacct->numRUN; } else { avail = avail - compute_slots(n, slots, avail); } assert(avail >= 0); /* As we traverse in priority order * the leafs are also sorted */ if (n->child == NULL) enqueue_link(t->leafs, n); n = n->right; } ++first; n = pop_link(stack); if (n) { /* tokens come from the parent */ sacct = n->data; avail = slots = sacct->sent; n = n->child; goto znovu; } if (avail > 0 && tried == 0) { ++tried; n = t->root->child; goto znovu; } fin_link(stack); return 0; }
/* parseUsage() */ static int parseUsage(char *usageReq, struct resVal *resVal, struct lsInfo *lsInfo) { int i; int m; int entry; float value; char *token; link_t *link; linkiter_t iter; struct _rusage_ *r; char *s; int *rusage_bit_map; float *val; char *usageReq2; char *s2; if ((i = strlen(usageReq)) == 0) return PARSE_OK; for (m = 0; m < i; m++) if (usageReq[m] != ' ') break; if (m == i) return PARSE_OK; s2 = usageReq2 = strip_spaces(usageReq); resVal->rl = make_link(); link = get_rusage_entries(usageReq2); i = 0; traverse_init(link, &iter); while ((s = traverse_link(&iter))) { /* Allocate for each element of the link */ rusage_bit_map = calloc(GET_INTNUM(lsInfo->nRes), sizeof(int)); val = calloc(lsInfo->nRes, sizeof(float)); resVal->genClass = 0; while ((token = getNextToken(&s)) != NULL) { if (token[0] == '-') token++; entry = getKeyEntry(token); if (entry > 0) { if (entry != KEY_DURATION && entry != KEY_DECAY) goto pryc; if (s[0] == '=') { int returnValue; if (entry == KEY_DURATION) returnValue = getTimeVal(&s, &value); else returnValue = getVal(&s, &value); if (returnValue < 0 || value < 0.0) return PARSE_BAD_VAL; if (entry == KEY_DURATION) resVal->duration = value; else resVal->decay = value; continue; } } entry = getResEntry(token); if (entry < 0) goto pryc; if (!(lsInfo->resTable[entry].flags & RESF_DYNAMIC) && (lsInfo->resTable[entry].valueType != LS_NUMERIC)) { if (s[0] == '=') { if (getVal(&s, &value) < 0 || value < 0.0) goto pryc; } continue; } if (entry < MAXSRES) resVal->genClass |= 1 << entry; SET_BIT(entry, rusage_bit_map); if (s[0] == '=') { if (getVal(&s, &value) < 0 || value < 0.0) goto pryc; val[entry] = value; } } /* Save the current rusage block */ r = calloc(1, sizeof(struct _rusage_)); r->bitmap = rusage_bit_map; r->val = val; enqueue_link(resVal->rl, r); if (i == 0) { /* The entry 0 is both in the link and * in the resVal. The default values * were allocated in setDefaults() */ _free_(resVal->rusage_bit_map); _free_(resVal->val); /* Copy the values as later we free them separately */ resVal->rusage_bit_map = calloc(GET_INTNUM(lsInfo->nRes), sizeof(int)); memcpy(resVal->rusage_bit_map, rusage_bit_map, GET_INTNUM(lsInfo->nRes) * sizeof(int)); resVal->val = calloc(lsInfo->nRes, sizeof(float)); memcpy(resVal->val, r->val, lsInfo->nRes * sizeof(float)); } ++i; } /* while (s = traverse_link()) */ resVal->options |= PR_RUSAGE; while ((s = pop_link(link))) _free_(s); fin_link(link); _free_(s2); return PARSE_OK; pryc: _free_(rusage_bit_map); _free_(val); while ((s = pop_link(link))) _free_(s); fin_link(link); while ((r = pop_link(resVal->rl))) { _free_(r->bitmap); _free_(r->val); _free_(r); } fin_link(resVal->rl); resVal->rl = NULL; _free_(s2); return PARSE_BAD_NAME; }
/* parse_group_member() */ static link_t * parse_group_member(const char *gname, uint32_t num, struct group_acct *grps) { link_t *l; linkiter_t iter; struct group_acct *g; int cc; char *w; char *p; uint32_t sum; struct share_acct *sacct; l = make_link(); g = NULL; for (cc = 0; cc < num; cc++) { /* Match the group name and the group * must have shares. */ if (strcmp(gname, grps[cc].group) == 0 && grps[cc].user_shares) { g = calloc(1, sizeof(struct group_acct)); assert(g); g->group = strdup(grps[cc].group); g->memberList = strdup(grps[cc].memberList); g->user_shares = strdup(grps[cc].user_shares); tokenize(g->user_shares); break; } } /* gudness leaf member * caller will free the link */ if (g == NULL) return l; p = g->memberList; sum = 0; while ((w = get_next_word(&p))) { sacct = get_sacct(w, g->user_shares); if (sacct == NULL) { while ((sacct = pop_link(l))) free_sacct(sacct); fin_link(l); return NULL; } sum = sum + sacct->shares; enqueue_link(l, sacct); } traverse_init(l, &iter); while ((sacct = traverse_link(&iter))) { sacct->dshares = (double)sacct->shares/(double)sum; } _free_(g->group); _free_(g->memberList); _free_(g->user_shares); _free_(g); return l; }