| /*****************************************************************************\ |
| * sort.c - sprio sorting functions |
| ***************************************************************************** |
| * Copyright (C) SchedMD LLC. |
| * |
| * This file is part of Slurm, a resource management program. |
| * For details, see <https://slurm.schedmd.com/>. |
| * Please also read the included file: DISCLAIMER. |
| * |
| * Slurm is free software; you can redistribute it and/or modify it under |
| * the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * In addition, as a special exception, the copyright holders give permission |
| * to link the code of portions of this program with the OpenSSL library under |
| * certain conditions as described in each individual source file, and |
| * distribute linked combinations including the two. You must obey the GNU |
| * General Public License in all respects for all of the code used other than |
| * OpenSSL. If you modify file(s) with this exception, you may extend this |
| * exception to your version of the file(s), but you are not obligated to do |
| * so. If you do not wish to do so, delete this exception statement from your |
| * version. If you delete this exception statement from all source files in |
| * the program, then also delete it here. |
| * |
| * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| * details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with Slurm; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| \*****************************************************************************/ |
| |
| #include <sys/types.h> |
| |
| #include "src/common/uid.h" |
| #include "src/common/xstring.h" |
| |
| #include "src/sprio/sprio.h" |
| |
| /* Constants */ |
| #define DEFAULT_SORT "i" |
| |
| /* Macros */ |
| #define COND_NEGATE(cond,val) ((cond)?(-(val)):(val)) |
| #define CMP_INT(a,b) (((a) < (b)) ? -1 : ((a) > (b))) |
| |
| /* Global variables */ |
| static bool sort_descend; |
| |
| /* Local sort functions */ |
| static int _sort_by_cluster_name(void *v1, void *v2); |
| static int _sort_by_job_id(void *v1, void *v2); |
| static int _sort_by_nice_level(void *v1, void *v2); |
| static int _sort_by_qos_name(void *v1, void *v2); |
| static int _sort_by_account(void *v1, void *v2); |
| static int _sort_by_partition(void *v1, void *v2); |
| static int _sort_by_username(void *v1, void *v2); |
| static int _sort_by_age_prio(void *v1, void *v2); |
| static int _sort_by_fairshare_prio(void *v1, void *v2); |
| static int _sort_by_jobsize_prio(void *v1, void *v2); |
| static int _sort_by_partition_prio(void *v1, void *v2); |
| static int _sort_by_qos_prio(void *v1, void *v2); |
| static int _sort_by_job_prio(void *v1, void *v2); |
| static int _sort_by_tres_prio(void *v1, void *v2); |
| |
| |
| extern void sort_job_list(list_t *job_list) |
| { |
| int i; |
| char c; |
| if (params.sort == NULL) |
| params.sort = xstrdup(DEFAULT_SORT); /* default: job priority */ |
| /* |
| * parse sort spec string from end, so the sorts happen in reverse |
| * order. |
| */ |
| for (i = strlen(params.sort); i --> 0;) { |
| c = params.sort[i]; |
| if (c == ',' || c == '-' || c == '+') |
| continue; |
| |
| /* + means ascending (default) and - means descending */ |
| sort_descend = false; |
| if (params.sort[i-1] == '-') |
| sort_descend = true; |
| |
| /* |
| * handle list sorting - weighted and normalized should |
| * sort the same, so sort by weighted |
| */ |
| switch (c) { |
| case 'c': /* sort by cluster name */ |
| list_sort(job_list, _sort_by_cluster_name); |
| break; |
| case 'i': /* sort by job id */ |
| list_sort(job_list, _sort_by_job_id); |
| break; |
| case 'N': /* sort by nice level ??? */ |
| list_sort(job_list, _sort_by_nice_level); |
| break; |
| case 'n': /* sort by QOS name */ |
| list_sort(job_list, _sort_by_qos_name); |
| break; |
| case 'o': /* sort by account name */ |
| list_sort(job_list, _sort_by_account); |
| break; |
| case 'r': /* sort by partition name */ |
| list_sort(job_list, _sort_by_partition); |
| break; |
| case 'u': /* sort by username */ |
| list_sort(job_list, _sort_by_username); |
| break; |
| case 'A': /* sort by age priority */ |
| case 'a': |
| list_sort(job_list, _sort_by_age_prio); |
| break; |
| case 'F': /* sort by fair share priority */ |
| case 'f': |
| list_sort(job_list, _sort_by_fairshare_prio); |
| break; |
| case 'J': /* sort by job size priority */ |
| case 'j': |
| list_sort(job_list, _sort_by_jobsize_prio); |
| break; |
| case 'P': /* sort by partition priority */ |
| case 'p': |
| list_sort(job_list, _sort_by_partition_prio); |
| break; |
| case 'Q': /* sort by qos priority */ |
| case 'q': |
| list_sort(job_list, _sort_by_qos_prio); |
| break; |
| case 'T': /* sort by TRES priority */ |
| case 't': |
| list_sort(job_list, _sort_by_tres_prio); |
| break; |
| case 'Y': /* sort by job priority */ |
| case 'y': |
| list_sort(job_list, _sort_by_job_prio); |
| break; |
| default: |
| error("Invalid sort specification: %c", |
| params.sort[i]); |
| exit(1); |
| } |
| } |
| } |
| |
| |
| /***************************************************************************** |
| * Local utility functions |
| *****************************************************************************/ |
| static inline void _get_job_prio_from_void(priority_factors_object_t **j1, |
| priority_factors_object_t **j2, |
| void *v1, void *v2) |
| { |
| *j1 = *(priority_factors_object_t **) v1; |
| *j2 = *(priority_factors_object_t **) v2; |
| } |
| |
| static inline double _compare_double(double a, double b) |
| { |
| if (fuzzy_equal(a, b)) |
| return 0; |
| return (a < b) ? -1 : 1; |
| } |
| |
| /***************************************************************************** |
| * Local sort functions |
| *****************************************************************************/ |
| static int _sort_by_cluster_name(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| cmp = xstrcmp(job1->cluster_name, job2->cluster_name); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_job_id(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| cmp = CMP_INT(job1->job_id, job2->job_id); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_qos_name(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| cmp = xstrcmp(job1->qos, job2->qos); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_nice_level(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| int val1, val2; |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| val1 = job1->prio_factors ? job1->prio_factors->nice : 0; |
| val2 = job1->prio_factors ? job2->prio_factors->nice : 0; |
| |
| cmp = CMP_INT(val1, val2); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_account(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| cmp = xstrcmp(job1->account, job2->account); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_partition(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| cmp = xstrcmp(job1->partition, job2->partition); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_username(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| char *name1, *name2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| name1 = uid_to_string_cached((uid_t) job1->user_id); |
| name2 = uid_to_string_cached((uid_t) job2->user_id); |
| cmp = xstrcmp(name1, name2); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_age_prio(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| double val1, val2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| val1 = job1->prio_factors ? job1->prio_factors->priority_age : 0; |
| val2 = job1->prio_factors ? job2->prio_factors->priority_age : 0; |
| |
| cmp = _compare_double(val1, val2); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_fairshare_prio(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| double val1, val2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| val1 = job1->prio_factors ? job1->prio_factors->priority_fs : 0; |
| val2 = job1->prio_factors ? job2->prio_factors->priority_fs : 0; |
| |
| cmp = _compare_double(val1, val2); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| |
| static int _sort_by_jobsize_prio(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| double val1, val2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| val1 = job1->prio_factors ? job1->prio_factors->priority_js : 0; |
| val2 = job1->prio_factors ? job2->prio_factors->priority_js : 0; |
| |
| cmp = _compare_double(val1, val2); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_partition_prio(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| double val1, val2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| val1 = job1->prio_factors ? job1->prio_factors->priority_part : 0; |
| val2 = job1->prio_factors ? job2->prio_factors->priority_part : 0; |
| |
| cmp = _compare_double(val1, val2); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_qos_prio(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| double val1, val2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| val1 = job1->prio_factors ? job1->prio_factors->priority_qos : 0; |
| val2 = job1->prio_factors ? job2->prio_factors->priority_qos : 0; |
| |
| cmp = _compare_double(val1, val2); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_tres_prio(void *v1, void *v2) |
| { |
| int cmp, i; |
| priority_factors_object_t *job1, *job2; |
| double job1_sum, job2_sum; |
| int val1, val2; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| val1 = job1->prio_factors ? job1->prio_factors->tres_cnt : 0; |
| val2 = job1->prio_factors ? job2->prio_factors->tres_cnt : 0; |
| |
| for (i = 0, job1_sum = 0; i < val1; i++) |
| job1_sum += job1->prio_factors->priority_tres[i]; |
| for (i = 0, job2_sum = 0; i < val2; i++) |
| job2_sum += job2->prio_factors->priority_tres[i]; |
| |
| cmp = _compare_double(job1_sum, job2_sum); |
| return COND_NEGATE(sort_descend, cmp); |
| } |
| |
| static int _sort_by_job_prio(void *v1, void *v2) |
| { |
| int cmp; |
| priority_factors_object_t *job1, *job2; |
| double j1_prio, j2_prio; |
| |
| _get_job_prio_from_void(&job1, &job2, v1, v2); |
| |
| j1_prio = get_priority_from_factors(job1); |
| j2_prio = get_priority_from_factors(job2); |
| cmp = _compare_double(j1_prio, j2_prio); |
| return COND_NEGATE(sort_descend, cmp); |
| } |