1
/*___INFO__MARK_BEGIN__*/
2
/*************************************************************************
4
* The Contents of this file are made available subject to the terms of
5
* the Sun Industry Standards Source License Version 1.2
7
* Sun Microsystems Inc., March, 2001
10
* Sun Industry Standards Source License Version 1.2
11
* =================================================
12
* The contents of this file are subject to the Sun Industry Standards
13
* Source License Version 1.2 (the "License"); You may not use this file
14
* except in compliance with the License. You may obtain a copy of the
15
* License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
17
* Software provided under this License is provided on an "AS IS" basis,
18
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
19
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
20
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
21
* See the License for the specific provisions governing your rights and
22
* obligations concerning the Software.
24
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
26
* Copyright: 2001 by Sun Microsystems, Inc.
28
* All Rights Reserved.
30
************************************************************************/
31
/*___INFO__MARK_END__*/
36
#include <sys/types.h>
41
#ifndef NO_SGE_COMPILE_DEBUG
42
# define NO_SGE_COMPILE_DEBUG
45
#include "sge_all_listsL.h"
50
#include "sge_orders.h"
51
#include "sge_job_schedd.h"
53
#include "sge_support.h"
54
#include "sge_schedd_conf.h"
55
#include "sge_usageL.h"
56
#include "sge_userprj.h"
57
#include "sgeobj/sge_sharetree.h"
58
#include "valid_queue_user.h"
60
static const long sge_usage_interval = SGE_USAGE_INTERVAL;
62
/*--------------------------------------------------------------------
63
* decay_usage - decay usage for the passed usage list
64
*--------------------------------------------------------------------*/
67
decay_usage( lList *usage_list,
68
const lList *decay_list,
70
u_long usage_time_stamp )
72
lListElem *usage = NULL;
76
double default_decay = 0;
78
if (curr_time > usage_time_stamp) {
80
default_decay = pow(sconf_get_decay_constant(),
81
(double)(curr_time - usage_time_stamp) /
82
(double)sge_usage_interval);
84
for_each(usage, usage_list) {
85
lListElem *decay_elem;
87
((decay_elem = lGetElemStr(decay_list, UA_name,
88
lGetPosString(usage, UA_name_POS))))) {
90
decay = pow(lGetPosDouble(decay_elem, UA_value_POS),
91
(double)(curr_time - usage_time_stamp) /
92
(double)sge_usage_interval);
94
decay = default_decay;
96
lSetPosDouble(usage, UA_value_POS,
97
lGetPosDouble(usage, UA_value_POS) * decay);
104
/*--------------------------------------------------------------------
105
* decay_userprj_usage - decay usage for the passed user/project object
106
*--------------------------------------------------------------------*/
109
decay_userprj_usage( lListElem *userprj,
111
const lList *decay_list,
115
u_long usage_time_stamp;
116
int obj_usage_seqno_POS = is_user ? UU_usage_seqno_POS : PR_usage_seqno_POS;
117
int obj_usage_time_stamp_POS = is_user ? UU_usage_time_stamp_POS : PR_usage_time_stamp_POS;
118
int obj_usage_POS = is_user ? UU_usage_POS : PR_usage_POS;
119
int obj_project_POS = is_user ? UU_project_POS : PR_project_POS;
121
if (userprj && seqno != lGetPosUlong(userprj, obj_usage_seqno_POS)) {
123
/*-------------------------------------------------------------
124
* Note: In order to decay usage once per decay interval, we
125
* keep a time stamp in the user/project of when it was last
126
* decayed and then apply the approriate decay based on the time
127
* stamp. This allows the usage to be decayed on the scheduling
128
* interval, even though the decay interval is different than
129
* the scheduling interval.
130
*-------------------------------------------------------------*/
132
usage_time_stamp = lGetPosUlong(userprj, obj_usage_time_stamp_POS);
134
if (usage_time_stamp > 0) {
137
decay_usage(lGetPosList(userprj, obj_usage_POS), decay_list,
138
curr_time, usage_time_stamp);
140
for_each(upp, lGetPosList(userprj, obj_project_POS)) {
141
decay_usage(lGetPosList(upp, UPP_usage_POS), decay_list,
142
curr_time, usage_time_stamp);
147
lSetPosUlong(userprj, obj_usage_time_stamp_POS, curr_time);
148
if (seqno != (u_long) -1) {
149
lSetPosUlong(userprj, obj_usage_seqno_POS, seqno);
158
/*--------------------------------------------------------------------
159
* calculate_decay_constant - calculates decay rate and constant based
160
* on the decay half life and usage interval. The halftime argument
162
*--------------------------------------------------------------------*/
165
calculate_decay_constant( double halftime,
167
double *decay_constant )
172
} else if (halftime == 0) {
174
*decay_constant = 1.0;
176
*decay_rate = - log(0.5) / (halftime * 60);
177
*decay_constant = 1 - (*decay_rate * sge_usage_interval);
183
/*--------------------------------------------------------------------
184
* calculate_default_decay_constant - calculates the default decay
185
* rate and constant based on the decay half life and usage interval.
186
* The halftime argument is in hours.
187
*--------------------------------------------------------------------*/
190
calculate_default_decay_constant( int halftime )
192
double sge_decay_rate = 0.0;
193
double sge_decay_constant = 0.0;
195
calculate_decay_constant(halftime*60.0, &sge_decay_rate, &sge_decay_constant);
197
sconf_set_decay_constant(sge_decay_constant);
201
/*--------------------------------------------------------------------
202
* sge_for_each_node - visit each node and call the supplied function
203
* until a non-zero return code is returned.
204
*--------------------------------------------------------------------*/
207
sge_for_each_share_tree_node( lListElem *node,
208
sge_node_func_t func,
212
lList *children = NULL;
213
lListElem *child_node = NULL;
219
if ((retcode = (*func)(node, ptr))) {
223
if ((children = lGetPosList(node, STN_children_POS))) {
224
for_each(child_node, children) {
225
if ((retcode = sge_for_each_share_tree_node(child_node, func, ptr))) {
235
/*--------------------------------------------------------------------
236
* zero_node_fields - zero out the share tree node fields that are
237
* passed to the qmaster from schedd and are displayed at qmon
238
*--------------------------------------------------------------------*/
241
sge_zero_node_fields( lListElem *node,
244
lSetPosDouble(node, STN_m_share_POS, 0);
245
lSetPosDouble(node, STN_adjusted_current_proportion_POS, 0);
246
lSetPosUlong(node, STN_job_ref_count_POS, 0);
252
/*--------------------------------------------------------------------
253
* sge_init_node_fields - zero out the share tree node fields that are
254
* passed to the qmaster from schedd and are displayed at qmon
255
*--------------------------------------------------------------------*/
258
sge_init_node_fields( lListElem *root )
260
return sge_for_each_share_tree_node(root, sge_zero_node_fields, NULL);
264
/*--------------------------------------------------------------------
265
* sge_calc_node_usage - calculate usage for this share tree node
266
* and all descendant nodes.
267
*--------------------------------------------------------------------*/
270
sge_calc_node_usage( lListElem *node,
271
const lList *user_list,
272
const lList *project_list,
273
const lList *decay_list,
275
const char *projname,
278
double usage_value = 0;
279
int project_node = 0;
280
lListElem *child_node;
282
lListElem *userprj = NULL;
283
lList *usage_list=NULL;
284
lListElem *usage_weight, *usage_elem;
285
double sum_of_usage_weights = 0;
286
const char *usage_name;
287
bool is_user = false;
289
DENTER(TOP_LAYER, "sge_calc_node_usage");
291
children = lGetPosList(node, STN_children_POS);
297
/*-------------------------------------------------------------
298
* Get usage from project usage sub-list in user object
299
*-------------------------------------------------------------*/
302
if ((userprj = user_list_locate(user_list,
303
lGetPosString(node, STN_name_POS)))) {
304
lList *projects = lGetList(userprj, UU_project);
309
if ((upp=lGetElemStr(projects, UPP_name, projname))) {
310
usage_list = lGetList(upp, UPP_usage);
317
/*-------------------------------------------------------------
318
* Get usage directly from corresponding user or project object
319
*-------------------------------------------------------------*/
321
if ((userprj = user_list_locate(user_list,
322
lGetPosString(node, STN_name_POS)))) {
325
usage_list = lGetList(userprj, UU_usage);
327
} else if ((userprj = prj_list_locate(project_list,
328
lGetPosString(node, STN_name_POS)))) {
331
usage_list = lGetList(userprj, PR_usage);
337
/*-------------------------------------------------------------
338
* If this is a project node, then return the project usage
339
* rather than the children's usage
340
*-------------------------------------------------------------*/
342
if ((userprj = prj_list_locate(project_list,
343
lGetPosString(node, STN_name_POS)))) {
346
usage_list = lGetList(userprj, PR_usage);
347
projname = lGetString(userprj, PR_name);
354
lList *usage_weight_list = NULL;
356
/*-------------------------------------------------------------
358
*-------------------------------------------------------------*/
360
if (curr_time && userprj) {
361
decay_userprj_usage(userprj, is_user, decay_list, seqno, curr_time);
364
/*-------------------------------------------------------------
365
* Sum usage weighting factors
366
*-------------------------------------------------------------*/
369
usage_weight_list = sconf_get_usage_weight_list();
370
if (usage_weight_list) {
371
for_each(usage_weight, usage_weight_list)
372
sum_of_usage_weights +=
373
lGetPosDouble(usage_weight, UA_value_POS);
377
/*-------------------------------------------------------------
378
* Combine user/project usage based on usage weighting factors
379
*-------------------------------------------------------------*/
381
if (usage_weight_list) {
382
for_each(usage_elem, usage_list) {
383
usage_name = lGetPosString(usage_elem, UA_name_POS);
384
usage_weight = lGetElemStr(usage_weight_list, UA_name,
386
if (usage_weight && sum_of_usage_weights>0) {
387
usage_value += lGetPosDouble(usage_elem, UA_value_POS) *
388
(lGetPosDouble(usage_weight, UA_value_POS) /
389
sum_of_usage_weights);
394
lFreeList(&usage_weight_list);
396
/*-------------------------------------------------------------
397
* Store other usage values in node usage list
398
*-------------------------------------------------------------*/
400
for_each(usage_elem, usage_list) {
401
const char *nm = lGetPosString(usage_elem, UA_name_POS);
403
if (strcmp(nm, USAGE_ATTR_CPU) != 0 &&
404
strcmp(nm, USAGE_ATTR_MEM) != 0 &&
405
strcmp(nm, USAGE_ATTR_IO) != 0) {
406
if (((u=lGetElemStr(lGetPosList(node, STN_usage_list_POS),
408
((u = lAddSubStr(node, UA_name, nm, STN_usage_list, UA_Type))))
409
lSetPosDouble(u, UA_value_POS,
410
lGetPosDouble(u, UA_value_POS) +
411
lGetPosDouble(usage_elem, UA_value_POS));
417
double child_usage = 0;
419
/*-------------------------------------------------------------
421
*-------------------------------------------------------------*/
423
for_each(child_node, children) {
425
child_usage += sge_calc_node_usage(child_node, user_list,
426
project_list, decay_list, curr_time,
429
/*-------------------------------------------------------------
430
* Sum other usage values
431
*-------------------------------------------------------------*/
434
for_each(nu, lGetPosList(child_node, STN_usage_list_POS)) {
435
const char *nm = lGetPosString(nu, UA_name_POS);
437
if (((u=lGetElemStr(lGetPosList(node, STN_usage_list_POS),
439
((u=lAddSubStr(node, UA_name, nm, STN_usage_list, UA_Type))))
440
lSetPosDouble(u, UA_value_POS,
441
lGetPosDouble(u, UA_value_POS) +
442
lGetPosDouble(nu, UA_value_POS));
448
/* if this is not a project node, we include the child usage */
450
usage_value += child_usage;
454
/* If this is a project node, then we calculate the usage
455
being used by all users which map to the "default" user node
456
by subtracting the sum of all the child usage from the
457
project usage. Then, we add this usage to all of the nodes
458
leading to the "default" user node. */
460
ancestors_t ancestors;
462
if (search_ancestors(node, "default", &ancestors, 1)) {
463
double default_usage = usage_value - child_usage;
464
if (default_usage > 1.0) {
465
for(i=1; i<ancestors.depth; i++) {
466
double u = lGetPosDouble(ancestors.nodes[i], STN_combined_usage_POS);
467
lSetPosDouble(ancestors.nodes[i], STN_combined_usage_POS, u + default_usage);
470
free_ancestors(&ancestors);
476
lListElem *default_node;
477
if ((default_node=search_named_node(node, "default")))
478
lSetPosDouble(default_node, STN_combined_usage_POS,
479
MAX(usage_value - child_usage, 0));
485
/*-------------------------------------------------------------
486
* Set combined usage in the node
487
*-------------------------------------------------------------*/
489
lSetPosDouble(node, STN_combined_usage_POS, usage_value);
496
/*--------------------------------------------------------------------
497
* sge_calc_node_proportions - calculate share tree node proportions
498
* for this node and all descendant nodes.
499
*--------------------------------------------------------------------*/
502
sge_calc_node_proportion( lListElem *node,
505
lList *children = NULL;
506
lListElem *child_node = NULL;
508
/*-------------------------------------------------------------
509
* Calculate node proportions for all children
510
*-------------------------------------------------------------*/
512
if ((children = lGetPosList(node, STN_children_POS))) {
513
for_each(child_node, children) {
514
sge_calc_node_proportion(child_node, total_usage);
518
/*-------------------------------------------------------------
519
* Set proportion in the node
520
*-------------------------------------------------------------*/
522
if (total_usage == 0) {
523
lSetPosDouble(node, STN_actual_proportion_POS, 0);
526
lSetPosDouble(node, STN_actual_proportion_POS,
527
lGetPosDouble(node, STN_combined_usage_POS) / total_usage);
534
/*--------------------------------------------------------------------
535
* sge_calc_share_tree_proportions - calculate share tree node
536
* usage and proportions.
538
* Sets STN_combined_usage and STN_actual_proportion in each share
539
* tree node contained in the passed-in share_tree argument.
540
*--------------------------------------------------------------------*/
543
_sge_calc_share_tree_proportions( lList *share_tree,
544
const lList *user_list,
545
const lList *project_list,
546
const lList *decay_list,
552
DENTER(TOP_LAYER, "sge_calc_share_tree_proportions");
554
if (!share_tree || !((root=lFirst(share_tree)))) {
559
calculate_default_decay_constant( sconf_get_halftime());
561
total_usage = sge_calc_node_usage(root,
569
sge_calc_node_proportion(root, total_usage);
577
sge_calc_share_tree_proportions( lList *share_tree,
578
const lList *user_list,
579
const lList *project_list,
580
const lList *decay_list )
582
_sge_calc_share_tree_proportions(share_tree, user_list, project_list,
583
decay_list, sge_get_gmt());
588
/*--------------------------------------------------------------------
589
* set_share_tree_project_flags - set the share tree project flag for
590
* node and descendants
591
*--------------------------------------------------------------------*/
594
set_share_tree_project_flags( const lList *project_list,
600
if (!project_list || !node)
603
if (prj_list_locate(project_list, lGetString(node, STN_name)))
604
lSetUlong(node, STN_project, 1);
606
lSetUlong(node, STN_project, 0);
608
children = lGetList(node, STN_children);
610
for_each(child, children) {
611
set_share_tree_project_flags(project_list, child);
619
sge_add_default_user_nodes( lListElem *root_node,
620
const lList *user_list,
621
const lList *project_list,
622
const lList *userset_list)
624
lListElem *user, *project, *pnode, *dnode;
625
const char *proj_name, *user_name;
628
* do for each project and for no project
629
* if default node exists
631
* if user maps to default node
632
* add temp node as sibling to default node
639
set_share_tree_project_flags(project_list, root_node);
641
for_each(project, project_list) {
643
** check acl and xacl of project for the temp users
644
** only users that are allowed for the project are shown
646
lList *xacl = lGetList(project, PR_xacl);
647
lList *acl = lGetList(project, PR_acl);
649
proj_name = lGetString(project, PR_name);
651
if (search_userprj_node(root_node, "default", proj_name, NULL)) {
652
for_each(user, user_list) {
655
user_name = lGetString(user, UU_name);
658
** check if user would be allowed
660
has_access = sge_has_access_(user_name, NULL, acl, xacl, userset_list);
663
((dnode=search_userprj_node(root_node, user_name,
664
proj_name, &pnode))) &&
665
!strcmp("default", lGetString(dnode, STN_name))) {
667
lListElem *node = lCopyElem(dnode);
668
lSetString(node, STN_name, user_name);
669
lSetList(node, STN_children, NULL);
670
lSetUlong(node, STN_temp, 1);
671
if (lGetList(dnode,STN_children) == NULL) {
672
lList *children = lCreateList("display", STN_Type);
673
lSetList(dnode, STN_children, children);
675
lAppendElem(lGetList(dnode,STN_children), node);
682
if (search_userprj_node(root_node, "default", proj_name, NULL)) {
683
for_each(user, user_list) {
684
user_name = lGetString(user, UU_name);
685
if (((dnode=search_userprj_node(root_node, user_name, proj_name, &pnode))) &&
686
strcmp("default", lGetString(dnode, STN_name)) == 0) {
687
lListElem *node = lCopyElem(dnode);
688
lSetString(node, STN_name, user_name);
689
lSetList(node, STN_children, NULL);
690
lSetUlong(node, STN_temp, 1);
691
if (lGetList(dnode,STN_children) == NULL) {
692
lList *children = lCreateList("display", STN_Type);
693
lSetList(dnode, STN_children, children);
695
lAppendElem(lGetList(dnode,STN_children), node);
703
/********************************************************
704
Search the share tree for the node corresponding to the
705
user / project combination
706
********************************************************/
708
search_userprj_node_work( lListElem *ep, /* branch to search */
709
const char *username,
710
const char *projname,
711
lListElem **pep, /* parent of found node */
715
lListElem *cep, *fep;
716
const char *nodename;
719
if (ep == NULL || (username == NULL && projname == NULL)) {
723
nodename = lGetPosString(ep, STN_name_POS);
726
* skip project nodes which don't match
729
if (lGetPosUlong(ep, STN_project_POS) &&
731
(!projname || strcmp(nodename, projname))) {
735
children = lGetPosList(ep, STN_children_POS);
738
* if project name is supplied, look for the project
741
if (projname != NULL) {
743
if (strcmp(nodename, projname) == 0) {
746
* We have found the project node, now find the user node
747
* within the project sub-tree. If there are no children,
748
* return the project node.
751
if (children == NULL) {
755
return search_userprj_node_work(ep, username, NULL, pep, ep);
758
/* search the child nodes for the project */
759
for_each(cep, children) {
760
if ((fep = search_userprj_node_work(cep, username, projname, pep, root))) {
761
if (pep && (cep == fep)) {
767
/* project was not found, fall thru and return NULL */
772
if (strcmp(nodename, username) == 0) {
777
* no project name supplied, so search for child node
780
for_each(cep, children) {
781
if ((fep = search_userprj_node_work(cep, username, projname, pep, root))) {
782
if (pep && (cep == fep)) {
790
* if we've searched the entire tree, search for default user
793
if (ep == root && strcmp(username, "default")) {
794
return search_userprj_node(ep, "default", NULL, pep);
798
* user was not found, fall thru and return NULL
807
/********************************************************
808
Search the share tree for the node corresponding to the
809
user / project combination
810
********************************************************/
812
search_userprj_node( lListElem *ep, /* root of the tree */
813
const char *username,
814
const char *projname,
815
lListElem **pep ) /* parent of found node */
817
return search_userprj_node_work(ep, username, projname, pep, ep);
821
/*--------------------------------------------------------------------
822
* sgeee_sort_jobs - sort jobs according the task-priority and job number
823
*--------------------------------------------------------------------*/
825
void sgeee_sort_jobs( lList **job_list ) /* JB_Type */
827
sgeee_sort_jobs_by(job_list, SGEJ_priority, SGEJ_sort_decending , SGEJ_sort_ascending); /* decreasing priority then increasing job number */
830
void sgeee_sort_jobs_by( lList **job_list , int by_SGEJ_field, int field_sort_direction, int jobnum_sort_direction) /* JB_Type */
833
lListElem *job = NULL, *nxt_job = NULL;
834
lList *tmp_list = NULL; /* SGEJ_Type */
835
char *sortorder = NULL;
837
DENTER(TOP_LAYER, "sgeee_sort_jobs");
839
if (!job_list || !*job_list) {
845
DPRINTF(("+ + + + + + + + + + + + + + + + \n"));
846
DPRINTF((" SORTING SGEEE JOB LIST \n"));
847
DPRINTF(("+ + + + + + + + + + + + + + + + \n"));
850
/*-----------------------------------------------------------------
852
*-----------------------------------------------------------------*/
853
tmp_list = lCreateList("tmp list", SGEJ_Type);
855
nxt_job = lFirst(*job_list);
856
while((job=nxt_job)) {
857
lListElem *tmp_sge_job = NULL; /* SGEJ_Type */
859
nxt_job = lNext(nxt_job);
860
tmp_sge_job = lCreateElem(SGEJ_Type);
863
lListElem *tmp_task; /* JAT_Type */
866
* First try to find an enrolled task
867
* It will have the highest priority
869
tmp_task = lFirst(lGetList(job, JB_ja_tasks));
872
* If there is no enrolled task than take the template element
874
if (tmp_task == NULL) {
875
tmp_task = lFirst(lGetList(job, JB_ja_template));
878
lSetDouble(tmp_sge_job, SGEJ_priority,
879
lGetDouble(tmp_task, JAT_prio));
880
if (by_SGEJ_field != SGEJ_priority) {
881
lSetUlong(tmp_sge_job, SGEJ_state,
882
lGetUlong(tmp_task, JAT_state));
883
lSetString(tmp_sge_job, SGEJ_master_queue,
884
lGetString(tmp_task, JAT_master_queue));
889
** JB_job_number (Ulong)
891
** JB_job_name (String)
893
** JAT_status (Ulong)
894
** JAT_master_queue (String)
897
lSetUlong(tmp_sge_job, SGEJ_job_number, lGetUlong(job, JB_job_number));
898
if (by_SGEJ_field != SGEJ_priority) {
899
lSetString(tmp_sge_job, SGEJ_job_name, lGetString(job, JB_job_name));
900
lSetString(tmp_sge_job, SGEJ_owner, lGetString(job, JB_owner));
902
lSetRef(tmp_sge_job, SGEJ_job_reference, job);
904
DPRINTF(("JOB: "sge_u32" PRIORITY: %f NAME: %s OWNER: %s QUEUE: %s STATUS: "sge_u32"\n",
905
lGetUlong(tmp_sge_job, SGEJ_job_number),
906
lGetDouble(tmp_sge_job, SGEJ_priority),
907
lGetString(tmp_sge_job, SGEJ_job_name) ? lGetString(tmp_sge_job, SGEJ_job_name) : "",
908
lGetString(tmp_sge_job, SGEJ_owner) ? lGetString(tmp_sge_job, SGEJ_owner) : "",
909
lGetString(tmp_sge_job, SGEJ_master_queue) ? lGetString(tmp_sge_job, SGEJ_master_queue) :"",
910
lGetUlong(tmp_sge_job, SGEJ_state)));
912
lAppendElem(tmp_list, tmp_sge_job);
914
lDechainElem(*job_list, job);
917
/*-----------------------------------------------------------------
919
*-----------------------------------------------------------------*/
920
if ((field_sort_direction) && (jobnum_sort_direction)) {
921
sortorder = "%I+ %I+";
922
} else if (!field_sort_direction) {
923
sortorder = "%I- %I+";
924
} else if (!jobnum_sort_direction) {
925
sortorder = "%I+ %I-";
927
sortorder = "%I- %I-";
930
lPSortList(tmp_list, sortorder, by_SGEJ_field, SGEJ_job_number);
932
/*-----------------------------------------------------------------
933
* rebuild job_list according sort order
934
*-----------------------------------------------------------------*/
935
for_each(job, tmp_list) {
936
lAppendElem(*job_list, lGetRef(job, SGEJ_job_reference));
939
/*-----------------------------------------------------------------
941
*-----------------------------------------------------------------*/
942
lFreeList(&tmp_list);