1 /* Copyright (c) 2004-2015. The SimGrid Team.
2 * All rights reserved. */
4 /* This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
7 /* \file callbacks.h */
9 #include "xbt/sysdep.h"
11 #include "xbt/mallocator.h"
12 #include "maxmin_private.hpp"
14 #include <stdio.h> /* sprintf */
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_maxmin, surf,
17 "Logging specific to SURF (maxmin)");
19 typedef struct s_dyn_light {
23 } s_dyn_light_t, *dyn_light_t;
25 double sg_maxmin_precision = 0.00001;
26 double sg_surf_precision = 0.00001;
28 static void *lmm_variable_mallocator_new_f(void);
29 static void lmm_variable_mallocator_free_f(void *var);
30 #define lmm_variable_mallocator_reset_f ((void_f_pvoid_t)NULL)
31 static void lmm_update_modified_set(lmm_system_t sys,
32 lmm_constraint_t cnst);
33 static void lmm_remove_all_modified_set(lmm_system_t sys);
34 static int Global_debug_id = 1;
35 static int Global_const_debug_id = 1;
37 static void lmm_var_free(lmm_system_t sys, lmm_variable_t var);
38 static XBT_INLINE void lmm_cnst_free(lmm_system_t sys,
39 lmm_constraint_t cnst);
41 static void lmm_on_disabled_var(lmm_system_t sys, lmm_constraint_t cnstr);
42 static void lmm_enable_var(lmm_system_t sys, lmm_variable_t var);
43 static int lmm_can_enable_var(lmm_variable_t var);
44 static void lmm_disable_var(lmm_system_t sys, lmm_variable_t var);
45 static int lmm_concurrency_slack(lmm_constraint_t cnstr);
46 static int lmm_cnstrs_min_concurrency_slack(lmm_variable_t var);
48 static void lmm_check_concurrency(lmm_system_t sys);
50 inline int lmm_element_concurrency(lmm_element_t elem) {
51 //Ignore element with weight less than one (e.g. cross-traffic)
52 return (elem->value>=1)?1:0;
53 //There are other alternatives, but they will change the behaviour of the model..
54 //So do not use it unless you want to make a new model.
55 //If you do, remember to change the variables concurrency share to reflect it.
56 //Potential examples are:
57 //return (elem->weight>0)?1:0;//Include element as soon as weight is non-zero
58 //return (int)ceil(elem->weight);//Include element as the rounded-up integer value of the element weight
61 inline void lmm_decrease_concurrency(lmm_element_t elem) {
62 xbt_assert(elem->constraint->concurrency_current>=lmm_element_concurrency(elem));
63 elem->constraint->concurrency_current-=lmm_element_concurrency(elem);
66 inline void lmm_increase_concurrency(lmm_element_t elem) {
68 elem->constraint->concurrency_current+= lmm_element_concurrency(elem);
70 lmm_constraint_t cnstr=elem->constraint;
72 if(cnstr->concurrency_current > cnstr->concurrency_maximum)
73 cnstr->concurrency_maximum= cnstr->concurrency_current;
75 xbt_assert(cnstr->concurrency_limit<0 || cnstr->concurrency_current<=cnstr->concurrency_limit,"Concurrency limit overflow!");
78 lmm_system_t lmm_system_new(int selective_update)
80 lmm_system_t l = NULL;
82 s_lmm_constraint_t cnst;
84 l = xbt_new0(s_lmm_system_t, 1);
87 l->selective_update_active = selective_update;
88 l->visited_counter = 1;
90 XBT_DEBUG("Setting selective_update_active flag to %d",
91 l->selective_update_active);
93 xbt_swag_init(&(l->variable_set),
94 xbt_swag_offset(var, variable_set_hookup));
95 xbt_swag_init(&(l->constraint_set),
96 xbt_swag_offset(cnst, constraint_set_hookup));
98 xbt_swag_init(&(l->active_constraint_set),
99 xbt_swag_offset(cnst, active_constraint_set_hookup));
101 xbt_swag_init(&(l->modified_constraint_set),
102 xbt_swag_offset(cnst, modified_constraint_set_hookup));
103 xbt_swag_init(&(l->saturated_variable_set),
104 xbt_swag_offset(var, saturated_variable_set_hookup));
105 xbt_swag_init(&(l->saturated_constraint_set),
106 xbt_swag_offset(cnst, saturated_constraint_set_hookup));
108 l->variable_mallocator = xbt_mallocator_new(65536,
109 lmm_variable_mallocator_new_f,
110 lmm_variable_mallocator_free_f,
111 lmm_variable_mallocator_reset_f);
116 void lmm_system_free(lmm_system_t sys)
118 lmm_variable_t var = NULL;
119 lmm_constraint_t cnst = NULL;
122 while ((var = (lmm_variable_t) extract_variable(sys))) {
124 ("Variable %p (%d) still in system when freing it: this may be a bug",
126 lmm_var_free(sys, var);
129 while ((cnst = (lmm_constraint_t) extract_constraint(sys)))
130 lmm_cnst_free(sys, cnst);
132 xbt_mallocator_free(sys->variable_mallocator);
136 static XBT_INLINE void lmm_variable_remove(lmm_system_t sys, lmm_variable_t var)
141 lmm_element_t elem = NULL;
143 XBT_IN("(sys=%p, var=%p)", sys, var);
146 //TODOLATER Can do better than that by leaving only the variable in only one element_set, call lmm_update_modified_set, and then remove it..
147 if(var->cnsts_number)
148 lmm_update_modified_set(sys, var->cnsts[0].constraint);
150 for (i = 0; i < var->cnsts_number; i++) {
151 elem = &var->cnsts[i];
153 lmm_decrease_concurrency(elem);
154 xbt_swag_remove(elem, &(elem->constraint->element_set));
155 xbt_swag_remove(elem, &(elem->constraint->active_element_set));
156 nelements=xbt_swag_size(&(elem->constraint->element_set));
158 make_constraint_inactive(sys, elem->constraint);
159 //Check if we can enable new variables going through the constraints where var was.
161 lmm_on_disabled_var(sys,elem->constraint);
164 var->cnsts_number = 0;
168 static void lmm_var_free(lmm_system_t sys, lmm_variable_t var)
171 lmm_variable_remove(sys, var);
172 xbt_mallocator_release(sys->variable_mallocator, var);
175 static XBT_INLINE void lmm_cnst_free(lmm_system_t sys,
176 lmm_constraint_t cnst)
178 /* xbt_assert(xbt_swag_size(&(cnst->element_set)), */
179 /* "This list should be empty!"); */
180 make_constraint_inactive(sys, cnst);
184 lmm_constraint_t lmm_constraint_new(lmm_system_t sys, void *id,
187 lmm_constraint_t cnst = NULL;
188 s_lmm_element_t elem;
190 cnst = xbt_new0(s_lmm_constraint_t, 1);
192 cnst->id_int = Global_const_debug_id++;
193 xbt_swag_init(&(cnst->element_set),
194 xbt_swag_offset(elem, element_set_hookup));
195 xbt_swag_init(&(cnst->active_element_set),
196 xbt_swag_offset(elem, active_element_set_hookup));
198 cnst->bound = bound_value;
199 cnst->concurrency_maximum=0;
200 cnst->concurrency_current=0;
201 //TODO MARTIN Maybe a configuration item for the default cap concurrency?
202 cnst->concurrency_limit=100;
204 cnst->sharing_policy = 1; /* FIXME: don't hardcode the value */
205 insert_constraint(sys, cnst);
210 int lmm_constraint_concurrency_limit_get(lmm_constraint_t cnst)
212 return cnst->concurrency_limit;
215 void lmm_constraint_concurrency_limit_set(lmm_constraint_t cnst, int concurrency_limit)
217 xbt_assert(concurrency_limit<0 || cnst->concurrency_maximum<=concurrency_limit,"New concurrency limit should be larger than observed concurrency maximum. Maybe you want to call lmm_constraint_concurrency_maximum_reset() to reset the maximum?");
218 cnst->concurrency_limit = concurrency_limit;
221 void lmm_constraint_concurrency_maximum_reset(lmm_constraint_t cnst)
223 cnst->concurrency_maximum = 0;
226 int lmm_constraint_concurrency_maximum_get(lmm_constraint_t cnst)
228 xbt_assert(cnst->concurrency_limit<0 || cnst->concurrency_maximum<=cnst->concurrency_limit,"Very bad: maximum observed concurrency is higher than limit. This is a bug of SURF, please report it.");
229 return cnst->concurrency_maximum;
232 void lmm_constraint_shared(lmm_constraint_t cnst)
234 cnst->sharing_policy = 0;
237 /** Return true if the constraint is shared, and false if it's FATPIPE */
238 int lmm_constraint_sharing_policy(lmm_constraint_t cnst)
240 return (cnst->sharing_policy);
243 /* @brief Remove a constraint
244 * Currently this is dead code, but it is exposed in maxmin.h
245 * Apparently, this call was designed assuming that constraint would no more have elements in it.
246 * If this is not the case, assertion will fail, and you need to add calls e.g. to lmm_shrink before effectively removing it.
248 XBT_INLINE void lmm_constraint_free(lmm_system_t sys,
249 lmm_constraint_t cnst)
251 xbt_assert(!xbt_swag_size(&(cnst->active_element_set)),"Removing constraint but it still has active elements");
252 xbt_assert(!xbt_swag_size(&(cnst->element_set)),"Removing constraint but it still has elements");
253 remove_constraint(sys, cnst);
254 lmm_cnst_free(sys, cnst);
257 static void *lmm_variable_mallocator_new_f(void)
259 lmm_variable_t var = xbt_new(s_lmm_variable_t, 1);
260 var->cnsts = NULL; /* will be created by realloc */
264 static void lmm_variable_mallocator_free_f(void *var)
266 xbt_free(((lmm_variable_t) var)->cnsts);
270 lmm_variable_t lmm_variable_new(lmm_system_t sys, void *id,
272 double bound, int number_of_constraints)
274 lmm_variable_t var = NULL;
277 XBT_IN("(sys=%p, id=%p, weight=%f, bound=%f, num_cons =%d)",
278 sys, id, weight, bound, number_of_constraints);
280 var = (lmm_variable_t) xbt_mallocator_get(sys->variable_mallocator);
282 var->id_int = Global_debug_id++;
283 var->cnsts = (s_lmm_element_t *) xbt_realloc(var->cnsts, number_of_constraints * sizeof(s_lmm_element_t));
284 for (i = 0; i < number_of_constraints; i++) {
285 var->cnsts[i].element_set_hookup.next = NULL;
286 var->cnsts[i].element_set_hookup.prev = NULL;
287 var->cnsts[i].active_element_set_hookup.next = NULL;
288 var->cnsts[i].active_element_set_hookup.prev = NULL;
289 var->cnsts[i].constraint = NULL;
290 var->cnsts[i].variable = NULL;
291 var->cnsts[i].value = 0.0;
293 var->cnsts_size = number_of_constraints;
294 var->cnsts_number = 0;
295 var->weight = weight;
296 var->staged_weight = 0.0;
298 var->concurrency_share = 1;
300 var->visited = sys->visited_counter - 1;
303 var->func_f = func_f_def;
304 var->func_fp = func_fp_def;
305 var->func_fpi = func_fpi_def;
307 var->variable_set_hookup.next = NULL;
308 var->variable_set_hookup.prev = NULL;
309 var->saturated_variable_set_hookup.next = NULL;
310 var->saturated_variable_set_hookup.prev = NULL;
313 xbt_swag_insert_at_head(var, &(sys->variable_set));
315 xbt_swag_insert_at_tail(var, &(sys->variable_set));
317 XBT_OUT(" returns %p", var);
321 void lmm_variable_free(lmm_system_t sys, lmm_variable_t var)
323 remove_variable(sys, var);
324 lmm_var_free(sys, var);
327 double lmm_variable_getvalue(lmm_variable_t var)
333 void lmm_variable_concurrency_share_set(lmm_variable_t var, short int concurrency_share)
335 var->concurrency_share=concurrency_share;
338 double lmm_variable_getbound(lmm_variable_t var)
343 void lmm_shrink(lmm_system_t sys, lmm_constraint_t cnst,
346 lmm_element_t elem = NULL;
350 for (i = 0; i < var->cnsts_number; i++) {
351 elem = &(var->cnsts[i]);
352 if (elem->constraint == cnst) {
359 XBT_DEBUG("cnst %p is not found in var %p", cnst, var);
365 XBT_DEBUG("remove elem(value %f, cnst %p, var %p) in var %p",
366 elem->value, elem->constraint, elem->variable, var);
368 /* We are going to change the constraint object and the variable object.
369 * Propagate this change to other objects. Calling here before removing variable from not active elements (inactive elements are not visited)
371 lmm_update_modified_set(sys, cnst);
372 //Useful in case var was already removed from the constraint
373 lmm_update_modified_set(sys, var->cnsts[0].constraint); // will look up element_set of this constraint, and then each var in the element_set, and each var->cnsts[i].
375 if(xbt_swag_remove(elem, &(elem->constraint->element_set)) && var->weight>0)
376 lmm_decrease_concurrency(elem);
378 xbt_swag_remove(elem, &(elem->constraint->active_element_set));
379 elem->constraint = NULL;
380 elem->variable = NULL;
383 var->cnsts_number -= 1;
385 //No variable in this constraint -> make it inactive
386 if (xbt_swag_size(&(cnst->element_set)) == 0)
387 make_constraint_inactive(sys, cnst);
389 //Check maxconcurrency to see if we can enable new variables
390 lmm_on_disabled_var(sys,elem->constraint);
393 lmm_check_concurrency(sys);
396 void lmm_expand(lmm_system_t sys, lmm_constraint_t cnst,
397 lmm_variable_t var, double value)
399 lmm_element_t elem = NULL;
405 if(var->weight>0 && lmm_concurrency_slack(cnst)==0){
407 lmm_disable_var(sys,var);
408 for (i = 0; i < var->cnsts_number; i++)
409 lmm_on_disabled_var(sys,var->cnsts[i].constraint);
411 var->staged_weight=weight;
412 xbt_assert(!var->weight);
415 xbt_assert(var->cnsts_number < var->cnsts_size, "Too much constraints");
417 elem = &(var->cnsts[var->cnsts_number++]);
420 elem->constraint = cnst;
421 elem->variable = var;
425 xbt_swag_insert_at_head(elem, &(elem->constraint->element_set));
426 lmm_increase_concurrency(elem);
429 xbt_swag_insert_at_tail(elem, &(elem->constraint->element_set));
431 if(!sys->selective_update_active) {
432 make_constraint_active(sys, cnst);
433 } else if(elem->value>0 || var->weight >0) {
434 make_constraint_active(sys, cnst);
435 lmm_update_modified_set(sys, cnst);
436 //TODOLATER: Why do we need this second call?
437 if (var->cnsts_number > 1)
438 lmm_update_modified_set(sys, var->cnsts[0].constraint);
441 lmm_check_concurrency(sys);
444 void lmm_expand_add(lmm_system_t sys, lmm_constraint_t cnst,
445 lmm_variable_t var, double value)
450 lmm_check_concurrency(sys);
452 for (i = 0; i < var->cnsts_number; i++)
453 if (var->cnsts[i].constraint == cnst)
456 if (i < var->cnsts_number) {
457 if (cnst->sharing_policy)
458 var->cnsts[i].value += value;
460 var->cnsts[i].value = MAX(var->cnsts[i].value, value);
461 lmm_update_modified_set(sys, cnst);
463 lmm_expand(sys, cnst, var, value);
465 lmm_check_concurrency(sys);
468 lmm_constraint_t lmm_get_cnst_from_var(lmm_system_t /*sys*/,
472 if (num < var->cnsts_number)
473 return (var->cnsts[num].constraint);
478 double lmm_get_cnst_weight_from_var(lmm_system_t /*sys*/,
482 if (num < var->cnsts_number)
483 return (var->cnsts[num].value);
488 int lmm_get_number_of_cnst_from_var(lmm_system_t /*sys*/,
491 return (var->cnsts_number);
494 lmm_variable_t lmm_get_var_from_cnst(lmm_system_t /*sys*/,
495 lmm_constraint_t cnst,
496 lmm_element_t * elem)
499 *elem = (lmm_element_t) xbt_swag_getFirst(&(cnst->element_set));
501 *elem = (lmm_element_t) xbt_swag_getNext(*elem, cnst->element_set.offset);
503 return (*elem)->variable;
508 //if we modify the swag between calls, normal version may loop forever
509 //this safe version ensures that we browse the swag elements only once
510 lmm_variable_t lmm_get_var_from_cnst_safe(lmm_system_t /*sys*/,
511 lmm_constraint_t cnst,
512 lmm_element_t * elem,
513 lmm_element_t * nextelem,
517 *elem = (lmm_element_t) xbt_swag_getFirst(&(cnst->element_set));
518 *numelem = xbt_swag_size(&(cnst->element_set))-1;
527 *nextelem = (lmm_element_t) xbt_swag_getNext(*elem, cnst->element_set.offset);
528 return (*elem)->variable;
533 void *lmm_constraint_id(lmm_constraint_t cnst)
538 void *lmm_variable_id(lmm_variable_t var)
543 static XBT_INLINE void saturated_constraint_set_update(double usage,
545 dyn_light_t saturated_constraint_set,
548 xbt_assert(usage > 0,"Impossible");
550 if (*min_usage < 0 || *min_usage > usage) {
552 XBT_HERE(" min_usage=%f (cnst->remaining / cnst->usage =%f)", *min_usage, usage);
553 saturated_constraint_set->data[0] = cnst_light_num;
554 saturated_constraint_set->pos = 1;
555 } else if (*min_usage == usage) {
556 if(saturated_constraint_set->pos == saturated_constraint_set->size) { // realloc the size
557 saturated_constraint_set->size *= 2;
558 saturated_constraint_set->data = (int*) xbt_realloc(saturated_constraint_set->data, (saturated_constraint_set->size) * sizeof(int));
560 saturated_constraint_set->data[saturated_constraint_set->pos] = cnst_light_num;
561 saturated_constraint_set->pos++;
565 static XBT_INLINE void saturated_variable_set_update(
566 s_lmm_constraint_light_t *cnst_light_tab,
567 dyn_light_t saturated_constraint_set,
570 /* Add active variables (i.e. variables that need to be set) from the set of constraints to saturate (cnst_light_tab)*/
571 lmm_constraint_light_t cnst = NULL;
573 lmm_element_t elem = NULL;
574 xbt_swag_t elem_list = NULL;
576 for(i = 0; i< saturated_constraint_set->pos; i++){
577 cnst = &cnst_light_tab[saturated_constraint_set->data[i]];
578 elem_list = &(cnst->cnst->active_element_set);
579 xbt_swag_foreach(_elem, elem_list) {
580 elem = (lmm_element_t)_elem;
581 //Visiting active_element_set, so, by construction, should never get a zero weight, correct?
582 xbt_assert(elem->variable->weight > 0);
583 if ((elem->value > 0))
584 xbt_swag_insert(elem->variable, &(sys->saturated_variable_set));
589 void lmm_print(lmm_system_t sys)
591 void *_cnst, *_elem, *_var;
592 lmm_constraint_t cnst = NULL;
593 lmm_element_t elem = NULL;
594 lmm_variable_t var = NULL;
595 xbt_swag_t cnst_list = NULL;
596 xbt_swag_t var_list = NULL;
597 xbt_swag_t elem_list = NULL;
598 char print_buf[1024];
599 char *trace_buf = (char*) xbt_malloc0(sizeof(char));
602 /* Printing Objective */
603 var_list = &(sys->variable_set);
604 sprintf(print_buf, "MAX-MIN ( ");
606 xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
607 strcat(trace_buf, print_buf);
608 xbt_swag_foreach(_var, var_list) {
609 var = (lmm_variable_t)_var;
610 sprintf(print_buf, "'%d'(%f) ", var->id_int, var->weight);
612 xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
613 strcat(trace_buf, print_buf);
615 sprintf(print_buf, ")");
617 xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
618 strcat(trace_buf, print_buf);
619 XBT_DEBUG("%20s", trace_buf);
620 trace_buf[0] = '\000';
622 XBT_DEBUG("Constraints");
623 /* Printing Constraints */
624 cnst_list = &(sys->active_constraint_set);
625 xbt_swag_foreach(_cnst, cnst_list) {
626 cnst = (lmm_constraint_t)_cnst;
628 elem_list = &(cnst->element_set);
629 sprintf(print_buf, "\t");
631 xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
632 strcat(trace_buf, print_buf);
633 sprintf(print_buf, "%s(",(cnst->sharing_policy)?"":"max");
635 xbt_realloc(trace_buf,
636 strlen(trace_buf) + strlen(print_buf) + 1);
637 strcat(trace_buf, print_buf);
638 xbt_swag_foreach(_elem, elem_list) {
639 elem = (lmm_element_t)_elem;
640 sprintf(print_buf, "%f.'%d'(%f) %s ", elem->value,
641 elem->variable->id_int, elem->variable->value,(cnst->sharing_policy)?"+":",");
643 xbt_realloc(trace_buf,
644 strlen(trace_buf) + strlen(print_buf) + 1);
645 strcat(trace_buf, print_buf);
646 if(cnst->sharing_policy)
647 sum += elem->value * elem->variable->value;
649 sum = MAX(sum,elem->value * elem->variable->value);
651 sprintf(print_buf, "0) <= %f ('%d')", cnst->bound, cnst->id_int);
653 xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
654 strcat(trace_buf, print_buf);
656 if (!cnst->sharing_policy) {
657 sprintf(print_buf, " [MAX-Constraint]");
659 xbt_realloc(trace_buf,
660 strlen(trace_buf) + strlen(print_buf) + 1);
661 strcat(trace_buf, print_buf);
663 XBT_DEBUG("%s", trace_buf);
664 trace_buf[0] = '\000';
665 xbt_assert(!double_positive(sum - cnst->bound, cnst->bound*sg_maxmin_precision),
666 "Incorrect value (%f is not smaller than %f): %g",
667 sum, cnst->bound, sum - cnst->bound);
670 XBT_DEBUG("Variables");
671 /* Printing Result */
672 xbt_swag_foreach(_var, var_list) {
673 var = (lmm_variable_t)_var;
674 if (var->bound > 0) {
675 XBT_DEBUG("'%d'(%f) : %f (<=%f)", var->id_int, var->weight, var->value,
677 xbt_assert(!double_positive(var->value - var->bound, var->bound*sg_maxmin_precision),
678 "Incorrect value (%f is not smaller than %f",
679 var->value, var->bound);
681 XBT_DEBUG("'%d'(%f) : %f", var->id_int, var->weight, var->value);
688 void lmm_solve(lmm_system_t sys)
690 void *_var, *_cnst, *_cnst_next, *_elem;
691 lmm_variable_t var = NULL;
692 lmm_constraint_t cnst = NULL;
693 lmm_element_t elem = NULL;
694 xbt_swag_t cnst_list = NULL;
695 xbt_swag_t var_list = NULL;
696 xbt_swag_t elem_list = NULL;
697 double min_usage = -1;
698 double min_bound = -1;
700 if (!(sys->modified))
703 XBT_IN("(sys=%p)", sys);
706 * Compute Usage and store the variables that reach the maximum. If selective_update_active is true, only constraints that changed are considered. Otherwise all constraints with active actions are considered.
710 selective_update_active ? &(sys->modified_constraint_set) :
711 &(sys->active_constraint_set);
713 XBT_DEBUG("Active constraints : %d", xbt_swag_size(cnst_list));
714 /* Init: Only modified code portions: reset the value of active variables */
715 xbt_swag_foreach(_cnst, cnst_list) {
716 cnst = (lmm_constraint_t)_cnst;
717 elem_list = &(cnst->element_set);
718 //XBT_DEBUG("Variable set : %d", xbt_swag_size(elem_list));
719 xbt_swag_foreach(_elem, elem_list) {
720 var = ((lmm_element_t)_elem)->variable;
721 if (var->weight <= 0.0)
727 s_lmm_constraint_light_t *cnst_light_tab = (s_lmm_constraint_light_t *)xbt_malloc0(xbt_swag_size(cnst_list)*sizeof(s_lmm_constraint_light_t));
728 int cnst_light_num = 0;
729 dyn_light_t saturated_constraint_set = xbt_new0(s_dyn_light_t,1);
730 saturated_constraint_set->size = 5;
731 saturated_constraint_set->data = xbt_new0(int, saturated_constraint_set->size);
733 xbt_swag_foreach_safe(_cnst, _cnst_next, cnst_list) {
734 cnst = (lmm_constraint_t)_cnst;
735 /* INIT: Collect constraints that actually need to be saturated (i.e remaining and usage are strictly positive) into cnst_light_tab. */
736 cnst->remaining = cnst->bound;
737 if (!double_positive(cnst->remaining, cnst->bound*sg_maxmin_precision))
740 elem_list = &(cnst->element_set);
741 xbt_swag_foreach(_elem, elem_list) {
742 elem = (lmm_element_t)_elem;
743 /* 0-weighted elements (ie, sleep actions) are at the end of the swag and we don't want to consider them */
744 if (elem->variable->weight <= 0)
746 if ((elem->value > 0)) {
747 if (cnst->sharing_policy)
748 cnst->usage += elem->value / elem->variable->weight;
749 else if (cnst->usage < elem->value / elem->variable->weight)
750 cnst->usage = elem->value / elem->variable->weight;
752 make_elem_active(elem);
753 simgrid::surf::Action *action = static_cast<simgrid::surf::Action*>(elem->variable->id);
754 if (sys->keep_track && !action->is_linked())
755 sys->keep_track->push_back(*action);
758 XBT_DEBUG("Constraint '%d' usage: %f remaining: %f ", cnst->id_int, cnst->usage, cnst->remaining);
759 /* Saturated constraints update */
761 if(cnst->usage > 0) {
762 cnst_light_tab[cnst_light_num].cnst = cnst;
763 cnst->cnst_light = &(cnst_light_tab[cnst_light_num]);
764 cnst_light_tab[cnst_light_num].remaining_over_usage = cnst->remaining / cnst->usage;
765 saturated_constraint_set_update(cnst_light_tab[cnst_light_num].remaining_over_usage,
766 cnst_light_num, saturated_constraint_set, &min_usage);
767 xbt_assert(cnst->active_element_set.count>0, "There is no sense adding a constraint that has no active element!" );
772 saturated_variable_set_update( cnst_light_tab,
773 saturated_constraint_set,
776 /* Saturated variables update */
779 /* Fix the variables that have to be */
780 var_list = &(sys->saturated_variable_set);
782 xbt_swag_foreach(_var, var_list) {
783 var = (lmm_variable_t)_var;
784 if (var->weight <= 0.0)
786 /* First check if some of these variables could reach their upper
787 bound and update min_bound accordingly. */
789 ("var=%d, var->bound=%f, var->weight=%f, min_usage=%f, var->bound*var->weight=%f",
790 var->id_int, var->bound, var->weight, min_usage,
791 var->bound * var->weight);
792 if ((var->bound > 0) && (var->bound * var->weight < min_usage)) {
794 min_bound = var->bound*var->weight;
796 min_bound = MIN(min_bound, (var->bound*var->weight));
797 XBT_DEBUG("Updated min_bound=%f", min_bound);
802 while ((var = (lmm_variable_t)xbt_swag_getFirst(var_list))) {
806 //If no variable could reach its bound, deal iteratively the constraints usage ( at worst one constraint is saturated at each cycle)
807 var->value = min_usage / var->weight;
808 XBT_DEBUG("Setting %p (%d) value to %f\n", var, var->id_int, var->value);
810 //If there exist a variable that can reach its bound, only update it (and other with the same bound) for now.
811 if (double_equals(min_bound, var->bound*var->weight, sg_maxmin_precision)){
812 var->value = var->bound;
813 XBT_DEBUG("Setting %p (%d) value to %f\n", var, var->id_int, var->value);
816 // Variables which bound is different are not considered for this cycle, but they will be afterwards.
817 XBT_DEBUG("Do not consider %p (%d) \n", var, var->id_int);
818 xbt_swag_remove(var, var_list);
822 XBT_DEBUG("Min usage: %f, Var(%d)->weight: %f, Var(%d)->value: %f ",
823 min_usage, var->id_int, var->weight, var->id_int, var->value);
826 /* Update the usage of contraints where this variable is involved */
827 for (i = 0; i < var->cnsts_number; i++) {
828 elem = &var->cnsts[i];
829 cnst = elem->constraint;
830 if (cnst->sharing_policy) {
831 //Remember: shared constraints require that sum(elem->value * var->value) < cnst->bound
832 double_update(&(cnst->remaining), elem->value * var->value, cnst->bound*sg_maxmin_precision);
833 double_update(&(cnst->usage), elem->value / var->weight, sg_maxmin_precision);
834 //If the constraint is saturated, remove it from the set of active constraints (light_tab)
835 if(!double_positive(cnst->usage,sg_maxmin_precision) || !double_positive(cnst->remaining,cnst->bound*sg_maxmin_precision)) {
836 if (cnst->cnst_light) {
837 int index = (cnst->cnst_light-cnst_light_tab);
838 XBT_DEBUG("index: %d \t cnst_light_num: %d \t || \t cnst: %p \t cnst->cnst_light: %p \t cnst_light_tab: %p usage: %f remaining: %f bound: %f ",
839 index,cnst_light_num, cnst, cnst->cnst_light, cnst_light_tab, cnst->usage, cnst->remaining, cnst->bound);
840 cnst_light_tab[index]=cnst_light_tab[cnst_light_num-1];
841 cnst_light_tab[index].cnst->cnst_light = &cnst_light_tab[index];
843 cnst->cnst_light = NULL;
846 cnst->cnst_light->remaining_over_usage = cnst->remaining / cnst->usage;
848 make_elem_inactive(elem);
850 //Remember: non-shared constraints only require that max(elem->value * var->value) < cnst->bound
852 make_elem_inactive(elem);
853 elem_list = &(cnst->element_set);
854 xbt_swag_foreach(_elem, elem_list) {
855 elem = (lmm_element_t)_elem;
856 if (elem->variable->weight <= 0) break; //Found an inactive variable -> no more active variables
857 if (elem->variable->value > 0) continue;
859 cnst->usage = MAX(cnst->usage, elem->value / elem->variable->weight);
861 //If the constraint is saturated, remove it from the set of active constraints (light_tab)
862 if(!double_positive(cnst->usage,sg_maxmin_precision) || !double_positive(cnst->remaining,cnst->bound*sg_maxmin_precision)) {
863 if(cnst->cnst_light) {
864 int index = (cnst->cnst_light-cnst_light_tab);
865 XBT_DEBUG("index: %d \t cnst_light_num: %d \t || \t cnst: %p \t cnst->cnst_light: %p \t cnst_light_tab: %p usage: %f remaining: %f bound: %f ",
866 index,cnst_light_num, cnst, cnst->cnst_light, cnst_light_tab, cnst->usage, cnst->remaining, cnst->bound);
867 cnst_light_tab[index]=cnst_light_tab[cnst_light_num-1];
868 cnst_light_tab[index].cnst->cnst_light = &cnst_light_tab[index];
870 cnst->cnst_light = NULL;
873 cnst->cnst_light->remaining_over_usage = cnst->remaining / cnst->usage;
874 xbt_assert(cnst->active_element_set.count>0, "Should not keep a maximum constraint that has no active element! You want to check the maxmin precision and possible rounding effects." );
878 xbt_swag_remove(var, var_list);
881 /* Find out which variables reach the maximum */
884 saturated_constraint_set->pos = 0;
886 for(pos=0; pos<cnst_light_num; pos++){
887 xbt_assert(cnst_light_tab[pos].cnst->active_element_set.count>0, "Cannot saturate more a constraint that has no active element! You may want to change the maxmin precision (--cfg=maxmin/precision:<new_value>) because of possible rounding effects.\n\tFor the record, the usage of this constraint is %g while the maxmin precision to which it is compared is %g.\n\tThe usage of the previous constraint is %g.", cnst_light_tab[pos].cnst->usage, sg_maxmin_precision, cnst_light_tab[pos-1].cnst->usage);
888 saturated_constraint_set_update(
889 cnst_light_tab[pos].remaining_over_usage,
891 saturated_constraint_set,
895 saturated_variable_set_update( cnst_light_tab,
896 saturated_constraint_set,
899 } while (cnst_light_num > 0);
902 if (sys->selective_update_active)
903 lmm_remove_all_modified_set(sys);
905 if (XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug)) {
909 xbt_free(saturated_constraint_set->data);
910 xbt_free(saturated_constraint_set);
911 xbt_free(cnst_light_tab);
916 /** \brief Attribute the value bound to var->bound.
918 * \param sys the lmm_system_t
919 * \param var the lmm_variable_t
920 * \param bound the new bound to associate with var
922 * Makes var->bound equal to bound. Whenever this function is called
923 * a change is signed in the system. To
924 * avoid false system changing detection it is a good idea to test
925 * (bound != 0) before calling it.
928 void lmm_update_variable_bound(lmm_system_t sys, lmm_variable_t var,
934 if (var->cnsts_number)
935 lmm_update_modified_set(sys, var->cnsts[0].constraint);
940 int lmm_concurrency_slack(lmm_constraint_t cnstr){
947 //FIXME MARTIN: Replace by infinite value std::numeric_limits<int>::(max)(), or something better within Simgrid?
948 if(cnstr->concurrency_limit<0)
951 if (XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug)) {
952 xbt_swag_foreach(_elem, &(cnstr->element_set)) {
953 elem = (lmm_element_t)_elem;
954 concurrency+=lmm_element_concurrency(elem);
957 slack=cnstr->concurrency_limit-concurrency;
958 xbt_assert(slack>=0,"concurrency slack should not be negative!");
962 return cnstr->concurrency_limit - cnstr->concurrency_current;
966 /** \brief Measure the minimum concurrency slack across all constraints where var is involved
968 * \param The variable to check for
971 int lmm_cnstrs_min_concurrency_slack(lmm_variable_t var){
973 //FIXME MARTIN: Replace by infinite value std::numeric_limits<int>::(max)(), or something better within Simgrid?
974 int slack,minslack=666;
975 for (i = 0; i < var->cnsts_number; i++) {
976 slack=lmm_concurrency_slack(var->cnsts[i].constraint);
978 //This is only an optimization, to avoid looking at more constraints when slack is already zero
979 //Disable it when debugging to let lmm_concurrency_slack catch nasty things
980 if(!slack && !XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug))
990 /* /Check if a variable can be enabled
992 * Make sure to set staged_weight before, if your intent is only to check concurrency
994 int lmm_can_enable_var(lmm_variable_t var){
995 return var->staged_weight>0 && lmm_cnstrs_min_concurrency_slack(var)>=var->concurrency_share;
999 //Small remark: In this implementation of lmm_enable_var and lmm_disable_var, we will meet multiple times with var when running lmm_update_modified_set.
1000 //A priori not a big performance issue, but we might do better by calling lmm_update_modified_set within the for loops (after doing the first for enabling==1, and before doing the last for disabling==1)
1002 void lmm_enable_var(lmm_system_t sys, lmm_variable_t var){
1007 xbt_assert(lmm_can_enable_var(var));
1009 var->weight = var->staged_weight;
1010 var->staged_weight = 0;
1012 //Enabling the variable, move to var to list head. Subtility is: here, we need to call lmm_update_modified_set AFTER moving at least one element of var.
1014 xbt_swag_remove(var, &(sys->variable_set));
1015 xbt_swag_insert_at_head(var, &(sys->variable_set));
1016 for (i = 0; i < var->cnsts_number; i++) {
1017 elem = &var->cnsts[i];
1018 xbt_swag_remove(elem, &(elem->constraint->element_set));
1019 xbt_swag_insert_at_head(elem, &(elem->constraint->element_set));
1020 lmm_increase_concurrency(elem);
1022 if (var->cnsts_number)
1023 lmm_update_modified_set(sys, var->cnsts[0].constraint);
1025 lmm_check_concurrency(sys);
1028 void lmm_disable_var(lmm_system_t sys, lmm_variable_t var){
1032 xbt_assert(!var->staged_weight,"Staged weight should have been cleared");
1033 //Disabling the variable, move to var to list tail. Subtility is: here, we need to call lmm_update_modified_set BEFORE moving the last element of var.
1034 xbt_swag_remove(var, &(sys->variable_set));
1035 xbt_swag_insert_at_tail(var, &(sys->variable_set));
1036 if (var->cnsts_number)
1037 lmm_update_modified_set(sys, var->cnsts[0].constraint);
1038 for (i = 0; i < var->cnsts_number; i++) {
1039 elem = &var->cnsts[i];
1040 xbt_swag_remove(elem, &(elem->constraint->element_set));
1041 xbt_swag_insert_at_tail(elem, &(elem->constraint->element_set));
1043 xbt_swag_remove(elem, &(elem->constraint->active_element_set));
1045 lmm_decrease_concurrency(elem);
1049 var->staged_weight=0.0;
1051 lmm_check_concurrency(sys);
1054 /* /brief Find variables that can be enabled and enable them.
1056 * Assuming that the variable has already been removed from non-zero weights
1057 * Can we find a staged variable to add?
1058 * If yes, check that none of the constraints that this variable is involved in is at the limit of its concurrency
1059 * And then add it to active variables
1061 void lmm_on_disabled_var(lmm_system_t sys, lmm_constraint_t cnstr){
1064 if(cnstr->concurrency_limit<0)
1068 xbt_swag_foreach(elem, &(cnstr->element_set)) {
1070 //active variables are checked to see if we already reached the maximum (SHOULD NOT HAPPEN BECAUSE WE SHOULD HAVE JUST DEACTIVATED ONE)
1071 if (elem->variable->weight > 0){
1072 concurrency+=lmm_element_concurrency(elem);
1073 xbt_assert(elem->variable->staged_weight==0.0,"Staged weight should have been reset");
1074 } else if (elem->variable->staged_weight>0 )
1076 //Found a staged variable
1077 //TODOLATER: Add random timing function to model reservation protocol fuzziness? Then how to make sure that staged variables will eventually be called?
1078 if(lmm_can_enable_var(elem->variable)){
1079 lmm_enable_var(sys,elem->variable);
1080 concurrency+=lmm_element_concurrency(elem);
1084 xbt_assert(concurrency<=cnstr->concurrency_limit,"Concurrency overflow!");
1085 if(concurrency==cnstr->concurrency_limit)
1089 lmm_check_concurrency(sys);
1093 /* \brief update the weight of a variable, and enable/disable it.
1094 * @return Returns whether a change was made
1096 void lmm_update_variable_weight(lmm_system_t sys, lmm_variable_t var,
1101 xbt_assert(weight>=0,"Variable weight should not be negative!");
1103 if (weight == var->weight)
1106 int enabling_var= (weight>0 && var->weight<=0);
1107 int disabling_var= (weight<=0 && var->weight>0);
1109 XBT_IN("(sys=%p, var=%p, weight=%f)", sys, var, weight);
1113 //Are we enabling this variable?
1115 var->staged_weight = weight;
1116 minslack=lmm_cnstrs_min_concurrency_slack(var);
1118 XBT_DEBUG("Staging var (instead of enabling) because min concurrency slack %i, with weight %f", minslack, weight);
1121 XBT_DEBUG("Enabling var with min concurrency slack %i", minslack);
1122 lmm_enable_var(sys,var);
1123 } else if (disabling_var){
1124 //Are we disabling this variable?
1125 lmm_disable_var(sys,var);
1130 lmm_check_concurrency(sys);
1136 double lmm_get_variable_weight(lmm_variable_t var)
1141 void lmm_update_constraint_bound(lmm_system_t sys,
1142 lmm_constraint_t cnst,
1146 lmm_update_modified_set(sys, cnst);
1147 cnst->bound = bound;
1150 int lmm_constraint_used(lmm_system_t sys, lmm_constraint_t cnst)
1152 return xbt_swag_belongs(cnst, &(sys->active_constraint_set));
1155 XBT_INLINE lmm_constraint_t lmm_get_first_active_constraint(lmm_system_t
1158 return (lmm_constraint_t)xbt_swag_getFirst(&(sys->active_constraint_set));
1161 XBT_INLINE lmm_constraint_t lmm_get_next_active_constraint(lmm_system_t
1166 return (lmm_constraint_t)xbt_swag_getNext(cnst, (sys->active_constraint_set).offset);
1169 #ifdef HAVE_LATENCY_BOUND_TRACKING
1170 XBT_INLINE int lmm_is_variable_limited_by_latency(lmm_variable_t var)
1172 return (double_equals(var->bound, var->value, var->bound*sg_maxmin_precision));
1177 /** \brief Update the constraint set propagating recursively to
1178 * other constraints so the system should not be entirely computed.
1180 * \param sys the lmm_system_t
1181 * \param cnst the lmm_constraint_t affected by the change
1183 * A recursive algorithm to optimize the system recalculation selecting only
1184 * constraints that have changed. Each constraint change is propagated
1185 * to the list of constraints for each variable.
1187 static void lmm_update_modified_set_rec(lmm_system_t sys,
1188 lmm_constraint_t cnst)
1192 //TODOLATER: Why lmm_modified_set has been changed in git version 2392B5157...? Looks equivalent logically and less obvious..
1194 xbt_swag_foreach(_elem, &cnst->element_set) {
1195 lmm_variable_t var = ((lmm_element_t)_elem)->variable;
1196 s_lmm_element_t *cnsts = var->cnsts;
1198 /* No need to update variables that are not active (because we made sure that also variables in the process of being disabled are still in the active element set of the original constraint given as argument) */
1201 for (i = 0; var->visited != sys->visited_counter
1202 && i < var->cnsts_number ; i++) {
1203 if (cnsts[i].constraint != cnst
1204 && !xbt_swag_belongs(cnsts[i].constraint,
1205 &sys->modified_constraint_set)) {
1206 xbt_swag_insert(cnsts[i].constraint, &sys->modified_constraint_set);
1207 lmm_update_modified_set_rec(sys, cnsts[i].constraint);
1210 //var will be ignored in later visits as long as sys->visited_counter does not move
1211 var->visited = sys->visited_counter;
1215 static void lmm_update_modified_set(lmm_system_t sys,
1216 lmm_constraint_t cnst)
1218 /* nothing to do if selective update isn't active */
1219 if (sys->selective_update_active
1220 && !xbt_swag_belongs(cnst, &sys->modified_constraint_set)) {
1221 xbt_swag_insert(cnst, &sys->modified_constraint_set);
1222 lmm_update_modified_set_rec(sys, cnst);
1226 /** \brief Remove all constraints of the modified_constraint_set.
1228 * \param sys the lmm_system_t
1231 static void lmm_remove_all_modified_set(lmm_system_t sys)
1234 //We cleverly un-flag all variables just by incrementing sys->visited_counter
1235 //In effect, the var->visited value will no more be equal to sys->visited counter
1236 //To be clean, when visited counter has wrapped around, we force these var->visited values so that variables that were in the modified a long (long long) time ago are not wrongly skipped here, which would lead to very nasty bugs (i.e. not readibily reproducible, and requiring a lot of run time before happening).
1237 if (++sys->visited_counter == 1) {
1238 /* the counter wrapped around, reset each variable->visited */
1240 xbt_swag_foreach(_var, &sys->variable_set)
1241 ((lmm_variable_t)_var)->visited = 0;
1243 xbt_swag_reset(&sys->modified_constraint_set);
1247 * Returns total resource load
1249 * \param cnst the lmm_constraint_t associated to the resource
1252 * This is dead code, but we may use it later for debug/trace.
1254 double lmm_constraint_get_usage(lmm_constraint_t cnst) {
1256 xbt_swag_t elem_list = &(cnst->element_set);
1258 lmm_element_t elem = NULL;
1260 xbt_swag_foreach(_elem, elem_list) {
1261 elem = (lmm_element_t)_elem;
1262 /* 0-weighted elements (ie, sleep actions) are at the end of the swag and we don't want to consider them */
1263 if (elem->variable->weight <= 0)
1265 if ((elem->value > 0)) {
1266 if (cnst->sharing_policy)
1267 usage += elem->value * elem->variable->value;
1268 else if (usage < elem->value * elem->variable->value)
1269 usage = elem->value * elem->variable->value;
1275 void lmm_check_concurrency(lmm_system_t sys){
1279 lmm_constraint_t cnst;
1282 //These checks are very expensive, so do them only if we want to debug SURF LMM
1283 if (XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug)) {
1285 xbt_swag_foreach(_cnst, &(sys->constraint_set)) {
1286 cnst = (lmm_constraint_t) _cnst;
1288 if(cnst->concurrency_limit<0)
1290 xbt_swag_foreach(_elem, &(cnst->element_set)) {
1291 elem = (lmm_element_t)_elem;
1292 if (elem->variable->weight > 0)
1293 concurrency+=lmm_element_concurrency(elem);
1295 //We should have staged variables only if conccurency is reached in some constraint
1296 xbt_assert(cnst->concurrency_limit<0 || elem->variable->staged_weight==0 || lmm_cnstrs_min_concurrency_slack(elem->variable) < elem->variable->concurrency_share,"should not have staged variable!");
1299 xbt_assert(cnst->concurrency_limit<0 || cnst->concurrency_limit >= concurrency,"concurrency check failed!");
1300 xbt_assert(cnst->concurrency_current == concurrency, "concurrency_current is out-of-date!");