From 65a90ba03d2803457adbb175535750d0ecad70be Mon Sep 17 00:00:00 2001 From: Ryan Cox <ryan_cox@byu.edu> Date: Thu, 4 Dec 2014 13:38:07 -0800 Subject: [PATCH] Update code for the new fairshare algorithm. --- src/plugins/priority/multifactor/fair_tree.c | 110 +++++++++++++------ testsuite/expect/test24.4 | 2 +- 2 files changed, 77 insertions(+), 35 deletions(-) diff --git a/src/plugins/priority/multifactor/fair_tree.c b/src/plugins/priority/multifactor/fair_tree.c index dfe16524d3d..8a66404c7cc 100644 --- a/src/plugins/priority/multifactor/fair_tree.c +++ b/src/plugins/priority/multifactor/fair_tree.c @@ -208,34 +208,52 @@ static void _calc_assoc_fs(slurmdb_association_rec_t *assoc) } -static slurmdb_association_rec_t** _append_children_to_array( +/* Append list of associations to array + * IN list - list of associations + * IN merged - array of associations to append to + * IN/OUT merged_size - number of associations in merged array + * RET - New array. Must be freed. + */ +static slurmdb_association_rec_t** _append_list_to_array( List list, slurmdb_association_rec_t** merged, - size_t *child_count) + size_t *merged_size) { ListIterator itr; slurmdb_association_rec_t *next; - size_t i = *child_count; - *child_count += list_count(list); + size_t bytes; + size_t i = *merged_size; + *merged_size += list_count(list); - merged = xrealloc(merged, sizeof(slurmdb_association_rec_t*) - * (*child_count + 1)); + /* must be null-terminated, so add one extra slot */ + bytes = sizeof(slurmdb_association_rec_t*) * (*merged_size + 1); + merged = xrealloc(merged, bytes); itr = list_iterator_create(list); while ((next = list_next(itr))) merged[i++] = next; list_iterator_destroy(itr); + /* null terminate the array */ + merged[*merged_size] = NULL; return merged; } +/* Returns number of tied sibling accounts. + * IN assocs - array of siblings, sorted by level_fs + * IN begin_ndx - begin looking for ties at this index + * RET - number of sibling accounts with equal level_fs values + */ static size_t _count_tied_accounts(slurmdb_association_rec_t** assocs, - size_t i) + size_t begin_ndx) { slurmdb_association_rec_t* next_assoc; - slurmdb_association_rec_t* assoc = assocs[i]; + slurmdb_association_rec_t* assoc = assocs[begin_ndx]; + size_t i = begin_ndx; size_t tied_accounts = 0; while ((next_assoc = assocs[++i])) { + /* Users are sorted to the left of accounts, so no user we + * encounter here will be equal to this account */ if (!next_assoc->user) break; if (assoc->usage->level_fs != next_assoc->usage->level_fs) @@ -246,12 +264,20 @@ static size_t _count_tied_accounts(slurmdb_association_rec_t** assocs, } +/* Copy the children of accounts [begin, end] into a single array. + * IN siblings - array of siblings, sorted by level_fs + * IN begin - index of first account to merge + * IN end - index of last account to merge + * IN assoc_level - depth in the tree (root is 0) + * RET - Array of the children. Must be freed. + */ static slurmdb_association_rec_t** _merge_accounts( slurmdb_association_rec_t** siblings, size_t begin, size_t end, uint16_t assoc_level) { size_t i; - size_t child_count = 0; + /* number of associations in merged array */ + size_t merged_size = 0; /* merged is a null terminated array */ slurmdb_association_rec_t** merged = (slurmdb_association_rec_t **) xmalloc(sizeof(slurmdb_association_rec_t *)); @@ -260,6 +286,7 @@ static slurmdb_association_rec_t** _merge_accounts( for (i = begin; i <= end; i++) { List children = siblings[i]->usage->children_list; + /* the first account's debug was already printed */ if (priority_debug && i > begin) _ft_debug(siblings[i], assoc_level, true); @@ -267,8 +294,7 @@ static slurmdb_association_rec_t** _merge_accounts( continue; } - merged = _append_children_to_array(children, merged, - &child_count); + merged = _append_list_to_array(children, merged, &merged_size); } return merged; } @@ -279,61 +305,77 @@ static slurmdb_association_rec_t** _merge_accounts( * This portion of the tree is now sorted and users are given a fairshare value * based on the order they are operated on. The basic equation is * (rank / g_user_assoc_count), though ties are allowed. The rank is decremented - * for each user that is encountered. + * for each user that is encountered except when ties occur. + * + * Tie Handling Rules: + * 1) Sibling users with the same level_fs receive the same rank + * 2) Sibling accounts with the same level_fs have their children lists + * merged before sorting + * 3) A user with the same level_fs as a sibling account will receive + * the same rank as the account's highest ranked user + * + * IN siblings - array of siblings + * IN assoc_level - depth in the tree (root is 0) + * IN/OUT rank - current user ranking, starting at g_user_assoc_count + * IN/OUT rnt - rank, no ties (what rank would be if no tie exists) + * IN account_tied - is this account tied with the previous user */ static void _calc_tree_fs(slurmdb_association_rec_t** siblings, - uint16_t assoc_level, uint32_t *rank, uint32_t *i, - bool account_tied) + uint16_t assoc_level, uint32_t *rank, + uint32_t *rnt, bool account_tied) { slurmdb_association_rec_t *assoc = NULL; long double prev_level_fs = (long double) NO_VAL; bool tied = false; - size_t ndx; + size_t i; /* Calculate level_fs for each child */ - for (ndx = 0; (assoc = siblings[ndx]); ndx++) + for (i = 0; (assoc = siblings[i]); i++) _calc_assoc_fs(assoc); /* Sort children by level_fs */ - qsort(siblings, ndx, sizeof(slurmdb_association_rec_t *), - _cmp_level_fs); + qsort(siblings, i, sizeof(slurmdb_association_rec_t *), _cmp_level_fs); /* Iterate through children in sorted order. If it's a user, calculate * fs_factor, otherwise recurse. */ - for (ndx = 0; (assoc = siblings[ndx]); ndx++) { - if (account_tied) { + for (i = 0; (assoc = siblings[i]); i++) { + /* tied is used while iterating across siblings. + * account_tied preserves ties while recursing */ + if (i == 0 && account_tied) { + /* The parent was tied so this level starts out tied */ tied = true; - account_tied = false; } else { tied = prev_level_fs == assoc->usage->level_fs; } if (priority_debug) _ft_debug(assoc, assoc_level, tied); + + /* If user, set their final fairshare factor and handle ranking. + * If account, merge any tied accounts then recurse with the + * merged children array. */ if (assoc->user) { if (!tied) - *rank = *i; + *rank = *rnt; - /* Set the final fairshare factor for this user */ assoc->usage->fs_factor = *rank / (double) g_user_assoc_count; - (*i)--; + + (*rnt)--; } else { slurmdb_association_rec_t** children; - size_t merge_count = - _count_tied_accounts(siblings, ndx); + size_t merge_count = _count_tied_accounts(siblings, i); /* Merging does not affect child level_fs calculations * since the necessary information is stored on each * assoc's usage struct */ - children = _merge_accounts(siblings, ndx, - ndx + merge_count, + children = _merge_accounts(siblings, i, i + merge_count, assoc_level); - _calc_tree_fs(children, assoc_level + 1, rank, i, tied); + _calc_tree_fs(children, assoc_level+1, rank, rnt, tied); /* Skip over any merged accounts */ - ndx += merge_count; + i += merge_count; xfree(children); } @@ -348,21 +390,21 @@ static void _apply_priority_fs(void) { slurmdb_association_rec_t** children = NULL; uint32_t rank = g_user_assoc_count; - uint32_t i = rank; + uint32_t rnt = rank; size_t child_count = 0; if (priority_debug) info("Fair Tree fairshare algorithm, starting at root:"); - assoc_mgr_root_assoc->usage->level_fs = 1L; + assoc_mgr_root_assoc->usage->level_fs = (long double) NO_VAL; /* _calc_tree_fs requires an array instead of List */ - children = _append_children_to_array( + children = _append_list_to_array( assoc_mgr_root_assoc->usage->children_list, children, &child_count); - _calc_tree_fs(children, 0, &rank, &i, false); + _calc_tree_fs(children, 0, &rank, &rnt, false); xfree(children); } diff --git a/testsuite/expect/test24.4 b/testsuite/expect/test24.4 index 3ea66e72972..7fb9c7ea466 100755 --- a/testsuite/expect/test24.4 +++ b/testsuite/expect/test24.4 @@ -78,7 +78,7 @@ expect { exp_continue } - "root|||0.000000|240||1.000000||1.000000|0|0|" { + "root|||0.000000|240||1.000000|||0|0|" { incr matches exp_continue } -- GitLab