diff --git a/NEWS b/NEWS index e974c0459784e13d400909fcc4f0c69702740851..82b5a23da8dc292ddb044782da7dc7ebb3c0106e 100644 --- a/NEWS +++ b/NEWS @@ -222,6 +222,7 @@ documents those changes that are of interest to users and admins. options. -- when using -j option in sacct no user restriction will applied unless specified with the -u option. + -- significant speed up for association based reports in sreport * Changes in SLURM 1.3.13 ========================= diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c index 4dbb84ac5d72baa09cfc1735487dcde837791936..049770f8fc41079ddd9451524b2ce6e788cb2adf 100644 --- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c +++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c @@ -1226,7 +1226,7 @@ static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond, } else if(assoc_cond->user_list) { /* we want all the users, but no non-user associations */ set = 1; - xstrfmtcat(*extra, " && (%s.user!='')", prefix); + xstrfmtcat(*extra, " && (%s.user!='')", prefix); } if(assoc_cond->partition_list @@ -2487,6 +2487,208 @@ static int _get_db_index(MYSQL *db_conn, return db_index; } +/* checks should already be done before this to see if this is a valid + user or not. +*/ +static int _get_usage_for_list(mysql_conn_t *mysql_conn, + slurmdbd_msg_type_t type, List object_list, + time_t start, time_t end) +{ +#ifdef HAVE_MYSQL + int rc = SLURM_SUCCESS; + int i=0; + MYSQL_RES *result = NULL; + MYSQL_ROW row; + char *tmp = NULL; + char *my_usage_table = NULL; + char *query = NULL; + List usage_list = NULL; + char *id_str = NULL; + ListIterator itr = NULL, u_itr = NULL; + void *object = NULL; + acct_association_rec_t *assoc = NULL; + acct_wckey_rec_t *wckey = NULL; + acct_accounting_rec_t *accounting_rec = NULL; + + char *usage_req_inx[] = { + "t1.id", + "t1.period_start", + "t1.alloc_cpu_secs" + }; + + enum { + USAGE_ID, + USAGE_START, + USAGE_ACPU, + USAGE_COUNT + }; + + + if(!object_list) { + error("We need an object to set data for getting usage"); + return SLURM_ERROR; + } + + if(_check_connection(mysql_conn) != SLURM_SUCCESS) + return SLURM_ERROR; + + switch (type) { + case DBD_GET_ASSOC_USAGE: + itr = list_iterator_create(object_list); + while((assoc = list_next(itr))) { + if(id_str) + xstrfmtcat(id_str, " || t3.id=%d", assoc->id); + else + xstrfmtcat(id_str, "t3.id=%d", assoc->id); + } + list_iterator_destroy(itr); + + my_usage_table = assoc_day_table; + break; + case DBD_GET_WCKEY_USAGE: + itr = list_iterator_create(object_list); + while((wckey = list_next(itr))) { + if(id_str) + xstrfmtcat(id_str, " || id=%d", wckey->id); + else + xstrfmtcat(id_str, "id=%d", wckey->id); + } + list_iterator_destroy(itr); + + my_usage_table = wckey_day_table; + break; + default: + error("Unknown usage type %d", type); + return SLURM_ERROR; + break; + } + + if(_set_usage_information(&my_usage_table, type, &start, &end) + != SLURM_SUCCESS) { + xfree(id_str); + return SLURM_ERROR; + } + + xfree(tmp); + i=0; + xstrfmtcat(tmp, "%s", usage_req_inx[i]); + for(i=1; i<USAGE_COUNT; i++) { + xstrfmtcat(tmp, ", %s", usage_req_inx[i]); + } + switch (type) { + case DBD_GET_ASSOC_USAGE: + query = xstrdup_printf( + "select %s from %s as t1, %s as t2, %s as t3 " + "where (t1.period_start < %d && t1.period_start >= %d) " + "&& t1.id=t2.id && (%s) && " + "t2.lft between t3.lft and t3.rgt " + "order by t1.id, period_start;", + tmp, my_usage_table, assoc_table, assoc_table, + end, start, id_str); + break; + case DBD_GET_WCKEY_USAGE: + query = xstrdup_printf( + "select %s from %s as t1 " + "where (period_start < %d && period_start >= %d) " + "&& %s order by id, period_start;", + tmp, my_usage_table, end, start, id_str); + break; + default: + error("Unknown usage type %d", type); + xfree(id_str); + xfree(tmp); + return SLURM_ERROR; + break; + } + xfree(id_str); + xfree(tmp); + + debug4("%d(%d) query\n%s", mysql_conn->conn, __LINE__, query); + if(!(result = mysql_db_query_ret( + mysql_conn->db_conn, query, 0))) { + xfree(query); + return SLURM_ERROR; + } + xfree(query); + + usage_list = list_create(destroy_acct_accounting_rec); + + while((row = mysql_fetch_row(result))) { + acct_accounting_rec_t *accounting_rec = + xmalloc(sizeof(acct_accounting_rec_t)); + accounting_rec->id = atoi(row[USAGE_ID]); + accounting_rec->period_start = atoi(row[USAGE_START]); + accounting_rec->alloc_secs = atoll(row[USAGE_ACPU]); + list_append(usage_list, accounting_rec); + } + mysql_free_result(result); + + u_itr = list_iterator_create(usage_list); + itr = list_iterator_create(object_list); + while((object = list_next(itr))) { + int found = 0; + int id = 0; + List acct_list = NULL; + + switch (type) { + case DBD_GET_ASSOC_USAGE: + assoc = (acct_association_rec_t *)object; + if(!assoc->accounting_list) + assoc->accounting_list = list_create( + destroy_acct_accounting_rec); + acct_list = assoc->accounting_list; + id = assoc->id; + break; + case DBD_GET_WCKEY_USAGE: + wckey = (acct_wckey_rec_t *)object; + if(!wckey->accounting_list) + wckey->accounting_list = list_create( + destroy_acct_accounting_rec); + acct_list = wckey->accounting_list; + id = wckey->id; + break; + default: + continue; + break; + } + + while((accounting_rec = list_next(u_itr))) { + if(id == accounting_rec->id) { + list_append(acct_list, accounting_rec); + list_remove(u_itr); + found = 1; + } else if(found) { + /* here we know the + list is in id order so + if the next record + isn't the correct id + just continue since + there is no reason to + go through the rest of + the list when we know + it isn't going to be + the correct id */ + break; + } + } + list_iterator_reset(u_itr); + } + list_iterator_destroy(itr); + list_iterator_destroy(u_itr); + + if(list_count(usage_list)) + error("we have %d records not added " + "to the association list", + list_count(usage_list)); + list_destroy(usage_list); + + + return rc; +#else + return SLURM_ERROR; +#endif +} + static mysql_db_info_t *_mysql_acct_create_db_info() { mysql_db_info_t *db_info = xmalloc(sizeof(mysql_db_info_t)); @@ -7896,8 +8098,8 @@ empty: list_iterator_destroy(itr); list_iterator_destroy(assoc_itr); if(list_count(assoc_list)) - info("I have %d left over associations", - list_count(assoc_list)); + error("I have %d left over associations", + list_count(assoc_list)); list_destroy(assoc_list); return cluster_list; @@ -8162,13 +8364,6 @@ empty: else assoc->grp_cpu_mins = INFINITE; - /* get the usage if requested */ - if(with_usage) { - acct_storage_p_get_usage(mysql_conn, uid, assoc, - DBD_GET_ASSOC_USAGE, - assoc_cond->usage_start, - assoc_cond->usage_end); - } parent_acct = row[ASSOC_REQ_ACCT]; if(!without_parent_info && row[ASSOC_REQ_PARENT][0]) { @@ -8393,6 +8588,12 @@ empty: //info("parent id is %d", assoc->parent_id); //log_assoc_rec(assoc); } + + if(with_usage && assoc_list) + _get_usage_for_list(mysql_conn, DBD_GET_ASSOC_USAGE, + assoc_list, assoc_cond->usage_start, + assoc_cond->usage_end); + mysql_free_result(result); list_destroy(delta_qos_list); @@ -8766,17 +8967,15 @@ empty: wckey->name = xstrdup(""); wckey->cluster = xstrdup(row[WCKEY_REQ_CLUSTER]); - - /* get the usage if requested */ - if(with_usage) { - acct_storage_p_get_usage(mysql_conn, uid, wckey, - DBD_GET_WCKEY_USAGE, - wckey_cond->usage_start, - wckey_cond->usage_end); - } } mysql_free_result(result); + if(with_usage && wckey_list) + _get_usage_for_list(mysql_conn, DBD_GET_WCKEY_USAGE, + wckey_list, wckey_cond->usage_start, + wckey_cond->usage_end); + + //END_TIMER2("get_wckeys"); return wckey_list; #else @@ -9277,7 +9476,7 @@ extern int acct_storage_p_get_usage(mysql_conn_t *mysql_conn, uid_t uid, if(!acct_assoc->acct) { debug("No account name given " "in association."); - goto bad_user; + goto bad_user; } itr = list_iterator_create(user.coord_accts); diff --git a/src/sacctmgr/account_functions.c b/src/sacctmgr/account_functions.c index 65cbeceb46185cea14a38352be49f25c78bb3c9c..e9d5d8a6df07b47ec3e8a4807d6d81fa028c1751 100644 --- a/src/sacctmgr/account_functions.c +++ b/src/sacctmgr/account_functions.c @@ -137,6 +137,8 @@ static int _set_cond(int *start, int argc, char *argv[], if(format_list) slurm_addto_char_list(format_list, argv[i]+end); } else if (!strncasecmp (argv[i], "FairShare", + MAX(command_len, 1)) + || !strncasecmp (argv[i], "Shares", MAX(command_len, 1))) { if(!assoc_cond->fairshare_list) assoc_cond->fairshare_list = @@ -358,6 +360,8 @@ static int _set_rec(int *start, int argc, char *argv[], acct->description = strip_quotes(argv[i]+end, NULL, 1); u_set = 1; } else if (!strncasecmp (argv[i], "FairShare", + MAX(command_len, 1)) + || !strncasecmp (argv[i], "Shares", MAX(command_len, 1))) { if(!assoc) continue; @@ -1129,6 +1133,12 @@ extern int sacctmgr_list_account(int argc, char *argv[]) field->name = xstrdup("Par Name"); field->len = 10; field->print_routine = print_fields_str; + } else if(!strncasecmp("Shares", object, + MAX(command_len, 1))) { + field->type = PRINT_FAIRSHARE; + field->name = xstrdup("Shares"); + field->len = 9; + field->print_routine = print_fields_uint; } else if(!strncasecmp("User", object, MAX(command_len, 1))) { field->type = PRINT_USER; field->name = xstrdup("User"); diff --git a/src/sacctmgr/association_functions.c b/src/sacctmgr/association_functions.c index 788554cd62ef392904f84924507e443b9f5d7527..80203e679ff7277b5b768fae14c555f67961a039 100644 --- a/src/sacctmgr/association_functions.c +++ b/src/sacctmgr/association_functions.c @@ -132,6 +132,8 @@ static int _set_cond(int *start, int argc, char *argv[], slurm_addto_char_list(format_list, argv[i]+end); } else if (!strncasecmp (argv[i], "FairShare", + MAX(command_len, 1)) + || !strncasecmp (argv[i], "Shares", MAX(command_len, 1))) { if(!assoc_cond->fairshare_list) assoc_cond->fairshare_list = @@ -377,7 +379,7 @@ extern int sacctmgr_list_association(int argc, char *argv[]) field = xmalloc(sizeof(print_field_t)); if(!strncasecmp("Account", object, MAX(command_len, 1)) - || !strncasecmp ("Acct", object, MAX(command_len, 4))) { + || !strncasecmp("Acct", object, MAX(command_len, 4))) { field->type = PRINT_ACCOUNT; field->name = xstrdup("Account"); if(tree_display) @@ -526,6 +528,12 @@ extern int sacctmgr_list_association(int argc, char *argv[]) field->name = xstrdup("RGT"); field->len = 6; field->print_routine = print_fields_uint; + } else if(!strncasecmp("Shares", object, + MAX(command_len, 1))) { + field->type = PRINT_FAIRSHARE; + field->name = xstrdup("Shares"); + field->len = 9; + field->print_routine = print_fields_uint; } else if(!strncasecmp("User", object, MAX(command_len, 1))) { field->type = PRINT_USER; field->name = xstrdup("User"); diff --git a/src/sacctmgr/cluster_functions.c b/src/sacctmgr/cluster_functions.c index a5613b3eac2f16cbe2535ae61300b018bee3a6fd..d1b4bd6b36a7d699a134823049c32709ad117b4f 100644 --- a/src/sacctmgr/cluster_functions.c +++ b/src/sacctmgr/cluster_functions.c @@ -131,6 +131,8 @@ static int _set_rec(int *start, int argc, char *argv[], if(name_list) slurm_addto_char_list(name_list, argv[i]+end); } else if (!strncasecmp (argv[i], "FairShare", + MAX(command_len, 1)) + || !strncasecmp (argv[i], "Shares", MAX(command_len, 1))) { if (get_uint(argv[i]+end, &assoc->shares_raw, "FairShare") == SLURM_SUCCESS) @@ -568,6 +570,12 @@ extern int sacctmgr_list_cluster(int argc, char *argv[]) field->name = xstrdup("RPC"); field->len = 3; field->print_routine = print_fields_uint; + } else if(!strncasecmp("Shares", object, + MAX(command_len, 1))) { + field->type = PRINT_FAIRSHARE; + field->name = xstrdup("Shares"); + field->len = 9; + field->print_routine = print_fields_uint; } else { exit_code=1; fprintf(stderr, "Unknown field '%s'\n", object); diff --git a/src/sacctmgr/file_functions.c b/src/sacctmgr/file_functions.c index 3b841b049ba0929e4567351902f33bef7323ec39..ef8c8a8183bc028bf4ea8620176ee636abafa89f 100644 --- a/src/sacctmgr/file_functions.c +++ b/src/sacctmgr/file_functions.c @@ -337,6 +337,8 @@ static sacctmgr_file_opts_t *_parse_options(char *options) MAX(command_len, 3))) { file_opts->desc = xstrdup(option); } else if (!strncasecmp (sub, "FairShare", + MAX(command_len, 1)) + || !strncasecmp (sub, "Shares", MAX(command_len, 1))) { if (get_uint(option, &file_opts->fairshare, "FairShare") != SLURM_SUCCESS) { @@ -585,7 +587,9 @@ static List _set_up_print_fields(List format_list) field->len = 20; field->print_routine = print_fields_str; } else if(!strncasecmp("FairShare", object, - MAX(command_len, 1))) { + MAX(command_len, 1)) + || !strncasecmp("Shares", object, + MAX(command_len, 1))) { field->type = PRINT_FAIRSHARE; field->name = xstrdup("FairShare"); field->len = 9; diff --git a/src/sacctmgr/user_functions.c b/src/sacctmgr/user_functions.c index 261548ffb0204696d6a44596fc069c8e40fd8760..7d50ca8a7b7907fcd03eb7a676a439d8a6f9695a 100644 --- a/src/sacctmgr/user_functions.c +++ b/src/sacctmgr/user_functions.c @@ -160,6 +160,8 @@ static int _set_cond(int *start, int argc, char *argv[], if(format_list) slurm_addto_char_list(format_list, argv[i]+end); } else if (!strncasecmp (argv[i], "FairShare", + MAX(command_len, 1)) + || !strncasecmp (argv[i], "Shares", MAX(command_len, 1))) { if(!assoc_cond->fairshare_list) assoc_cond->fairshare_list = @@ -373,6 +375,8 @@ static int _set_rec(int *start, int argc, char *argv[], strip_quotes(argv[i]+end, NULL, 1); u_set = 1; } else if (!strncasecmp (argv[i], "FairShare", + MAX(command_len, 1)) + || !strncasecmp (argv[i], "Shares", MAX(command_len, 1))) { if(!assoc) continue; @@ -744,6 +748,8 @@ extern int sacctmgr_add_user(int argc, char *argv[]) slurm_addto_char_list(wckey_cond->name_list, default_wckey); } else if (!strncasecmp (argv[i], "FairShare", + MAX(command_len, 1)) + || !strncasecmp (argv[i], "Shares", MAX(command_len, 1))) { if (get_uint(argv[i]+end, &start_assoc.shares_raw, "FairShare") == SLURM_SUCCESS) @@ -1686,6 +1692,12 @@ extern int sacctmgr_list_user(int argc, char *argv[]) field->name = xstrdup("Partition"); field->len = 10; field->print_routine = print_fields_str; + } else if(!strncasecmp("Shares", object, + MAX(command_len, 1))) { + field->type = PRINT_FAIRSHARE; + field->name = xstrdup("Shares"); + field->len = 9; + field->print_routine = print_fields_uint; } else if(!strncasecmp("User", object, MAX(command_len, 1)) || !strncasecmp("Name", object, MAX(command_len, 2))) { diff --git a/src/sreport/user_reports.c b/src/sreport/user_reports.c index 5a1a545dd3c9d5686a54439483d5d356d88c53e0..bf751f180f71724dcedf7bf5737904e3be516df5 100644 --- a/src/sreport/user_reports.c +++ b/src/sreport/user_reports.c @@ -76,7 +76,7 @@ static int _set_cond(int *start, int argc, char *argv[], user_cond->assoc_cond->with_usage = 1; } assoc_cond = user_cond->assoc_cond; - + if(!assoc_cond->cluster_list) assoc_cond->cluster_list = list_create(slurm_destroy_char); for (i=(*start); i<argc; i++) { @@ -265,6 +265,8 @@ extern int user_top(int argc, char *argv[]) _set_cond(&i, argc, argv, user_cond, format_list); + user_cond->assoc_cond->without_parent_info = 1; + if(!list_count(format_list)) slurm_addto_char_list(format_list, "Cl,L,P,A,U");