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 void lmm_decrease_concurrency(lmm_constraint_t cnstr){
51 xbt_assert(cnstr->concurrency_current>0);
52 cnstr->concurrency_current--;
55 inline void lmm_increase_concurrency(lmm_constraint_t cnstr){
56 if(++cnstr->concurrency_current > cnstr->concurrency_maximum)
57 cnstr->concurrency_maximum=cnstr->concurrency_current;
58 xbt_assert(cnstr->concurrency_limit<0 || cnstr->concurrency_current<=cnstr->concurrency_limit,"Concurrency limit overflow!");
61 lmm_system_t lmm_system_new(int selective_update)
63 lmm_system_t l = NULL;
65 s_lmm_constraint_t cnst;
67 l = xbt_new0(s_lmm_system_t, 1);
70 l->selective_update_active = selective_update;
71 l->visited_counter = 1;
73 XBT_DEBUG("Setting selective_update_active flag to %d",
74 l->selective_update_active);
76 xbt_swag_init(&(l->variable_set),
77 xbt_swag_offset(var, variable_set_hookup));
78 xbt_swag_init(&(l->constraint_set),
79 xbt_swag_offset(cnst, constraint_set_hookup));
81 xbt_swag_init(&(l->active_constraint_set),
82 xbt_swag_offset(cnst, active_constraint_set_hookup));
84 xbt_swag_init(&(l->modified_constraint_set),
85 xbt_swag_offset(cnst, modified_constraint_set_hookup));
86 xbt_swag_init(&(l->saturated_variable_set),
87 xbt_swag_offset(var, saturated_variable_set_hookup));
88 xbt_swag_init(&(l->saturated_constraint_set),
89 xbt_swag_offset(cnst, saturated_constraint_set_hookup));
91 l->variable_mallocator = xbt_mallocator_new(65536,
92 lmm_variable_mallocator_new_f,
93 lmm_variable_mallocator_free_f,
94 lmm_variable_mallocator_reset_f);
99 void lmm_system_free(lmm_system_t sys)
101 lmm_variable_t var = NULL;
102 lmm_constraint_t cnst = NULL;
105 while ((var = (lmm_variable_t) extract_variable(sys))) {
107 ("Variable %p (%d) still in system when freing it: this may be a bug",
109 lmm_var_free(sys, var);
112 while ((cnst = (lmm_constraint_t) extract_constraint(sys)))
113 lmm_cnst_free(sys, cnst);
115 xbt_mallocator_free(sys->variable_mallocator);
119 static XBT_INLINE void lmm_variable_remove(lmm_system_t sys, lmm_variable_t var)
124 lmm_element_t elem = NULL;
126 XBT_IN("(sys=%p, var=%p)", sys, var);
129 //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..
130 if(var->cnsts_number)
131 lmm_update_modified_set(sys, var->cnsts[0].constraint);
133 for (i = 0; i < var->cnsts_number; i++) {
134 elem = &var->cnsts[i];
136 lmm_decrease_concurrency(elem->constraint);
137 xbt_swag_remove(elem, &(elem->constraint->element_set));
138 xbt_swag_remove(elem, &(elem->constraint->active_element_set));
139 nelements=xbt_swag_size(&(elem->constraint->element_set));
141 make_constraint_inactive(sys, elem->constraint);
142 //Check if we can enable new variables going through the constraints where var was.
144 lmm_on_disabled_var(sys,elem->constraint);
147 var->cnsts_number = 0;
151 static void lmm_var_free(lmm_system_t sys, lmm_variable_t var)
154 lmm_variable_remove(sys, var);
155 xbt_mallocator_release(sys->variable_mallocator, var);
158 static XBT_INLINE void lmm_cnst_free(lmm_system_t sys,
159 lmm_constraint_t cnst)
161 /* xbt_assert(xbt_swag_size(&(cnst->element_set)), */
162 /* "This list should be empty!"); */
163 make_constraint_inactive(sys, cnst);
167 lmm_constraint_t lmm_constraint_new(lmm_system_t sys, void *id,
170 lmm_constraint_t cnst = NULL;
171 s_lmm_element_t elem;
173 cnst = xbt_new0(s_lmm_constraint_t, 1);
175 cnst->id_int = Global_const_debug_id++;
176 xbt_swag_init(&(cnst->element_set),
177 xbt_swag_offset(elem, element_set_hookup));
178 xbt_swag_init(&(cnst->active_element_set),
179 xbt_swag_offset(elem, active_element_set_hookup));
181 cnst->bound = bound_value;
182 cnst->concurrency_maximum=0;
183 cnst->concurrency_current=0;
184 //TODO MARTIN Maybe a configuration item for the default cap concurrency?
185 cnst->concurrency_limit=100;
187 cnst->sharing_policy = 1; /* FIXME: don't hardcode the value */
188 insert_constraint(sys, cnst);
193 void lmm_constraint_concurrency_limit_set(lmm_constraint_t cnst, int concurrency_limit)
195 cnst->concurrency_limit = concurrency_limit;
198 void lmm_constraint_concurrency_maximum_reset(lmm_constraint_t cnst)
200 cnst->concurrency_maximum = 0;
203 int lmm_constraint_concurrency_maximum_get(lmm_constraint_t cnst)
205 return cnst->concurrency_maximum;
208 void lmm_constraint_shared(lmm_constraint_t cnst)
210 cnst->sharing_policy = 0;
213 /** Return true if the constraint is shared, and false if it's FATPIPE */
214 int lmm_constraint_sharing_policy(lmm_constraint_t cnst)
216 return (cnst->sharing_policy);
219 /* @brief Remove a constraint
220 * Currently this is dead code, but it is exposed in maxmin.h
221 * Apparently, this call was designed assuming that constraint would no more have elements in it.
222 * If this is not the case, assertion will fail, and you need to add calls e.g. to lmm_shrink before effectively removing it.
224 XBT_INLINE void lmm_constraint_free(lmm_system_t sys,
225 lmm_constraint_t cnst)
227 xbt_assert(!xbt_swag_size(&(cnst->active_element_set)),"Removing constraint but it still has active elements");
228 xbt_assert(!xbt_swag_size(&(cnst->element_set)),"Removing constraint but it still has elements");
229 remove_constraint(sys, cnst);
230 lmm_cnst_free(sys, cnst);
233 static void *lmm_variable_mallocator_new_f(void)
235 lmm_variable_t var = xbt_new(s_lmm_variable_t, 1);
236 var->cnsts = NULL; /* will be created by realloc */
240 static void lmm_variable_mallocator_free_f(void *var)
242 xbt_free(((lmm_variable_t) var)->cnsts);
246 lmm_variable_t lmm_variable_new(lmm_system_t sys, void *id,
248 double bound, int number_of_constraints)
250 lmm_variable_t var = NULL;
253 XBT_IN("(sys=%p, id=%p, weight=%f, bound=%f, num_cons =%d)",
254 sys, id, weight, bound, number_of_constraints);
256 var = (lmm_variable_t) xbt_mallocator_get(sys->variable_mallocator);
258 var->id_int = Global_debug_id++;
259 var->cnsts = (s_lmm_element_t *) xbt_realloc(var->cnsts, number_of_constraints * sizeof(s_lmm_element_t));
260 for (i = 0; i < number_of_constraints; i++) {
261 var->cnsts[i].element_set_hookup.next = NULL;
262 var->cnsts[i].element_set_hookup.prev = NULL;
263 var->cnsts[i].active_element_set_hookup.next = NULL;
264 var->cnsts[i].active_element_set_hookup.prev = NULL;
265 var->cnsts[i].constraint = NULL;
266 var->cnsts[i].variable = NULL;
267 var->cnsts[i].value = 0.0;
269 var->cnsts_size = number_of_constraints;
270 var->cnsts_number = 0;
271 var->weight = weight;
272 var->staged_weight = 0.0;
274 var->concurrency_share = 1;
276 var->visited = sys->visited_counter - 1;
279 var->func_f = func_f_def;
280 var->func_fp = func_fp_def;
281 var->func_fpi = func_fpi_def;
283 var->variable_set_hookup.next = NULL;
284 var->variable_set_hookup.prev = NULL;
285 var->saturated_variable_set_hookup.next = NULL;
286 var->saturated_variable_set_hookup.prev = NULL;
289 xbt_swag_insert_at_head(var, &(sys->variable_set));
291 xbt_swag_insert_at_tail(var, &(sys->variable_set));
293 XBT_OUT(" returns %p", var);
297 void lmm_variable_free(lmm_system_t sys, lmm_variable_t var)
299 remove_variable(sys, var);
300 lmm_var_free(sys, var);
303 double lmm_variable_getvalue(lmm_variable_t var)
309 void lmm_variable_concurrency_share_set(lmm_variable_t var, short int concurrency_share)
311 var->concurrency_share=concurrency_share;
314 double lmm_variable_getbound(lmm_variable_t var)
319 void lmm_shrink(lmm_system_t sys, lmm_constraint_t cnst,
322 lmm_element_t elem = NULL;
326 for (i = 0; i < var->cnsts_number; i++) {
327 elem = &(var->cnsts[i]);
328 if (elem->constraint == cnst) {
335 XBT_DEBUG("cnst %p is not found in var %p", cnst, var);
341 XBT_DEBUG("remove elem(value %f, cnst %p, var %p) in var %p",
342 elem->value, elem->constraint, elem->variable, var);
344 /* We are going to change the constraint object and the variable object.
345 * Propagate this change to other objects. Calling here before removing variable from not active elements (inactive elements are not visited)
347 lmm_update_modified_set(sys, cnst);
348 //Useful in case var was already removed from the constraint
349 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].
351 if(xbt_swag_remove(elem, &(elem->constraint->element_set)) && var->weight>0)
352 lmm_decrease_concurrency(elem->constraint);
354 xbt_swag_remove(elem, &(elem->constraint->active_element_set));
355 elem->constraint = NULL;
356 elem->variable = NULL;
359 var->cnsts_number -= 1;
361 //No variable in this constraint -> make it inactive
362 if (xbt_swag_size(&(cnst->element_set)) == 0)
363 make_constraint_inactive(sys, cnst);
365 //Check maxconcurrency to see if we can enable new variables
366 lmm_on_disabled_var(sys,elem->constraint);
369 lmm_check_concurrency(sys);
372 void lmm_expand(lmm_system_t sys, lmm_constraint_t cnst,
373 lmm_variable_t var, double value)
375 lmm_element_t elem = NULL;
381 if(var->weight>0 && lmm_concurrency_slack(cnst)==0){
383 lmm_disable_var(sys,var);
384 for (i = 0; i < var->cnsts_number; i++)
385 lmm_on_disabled_var(sys,var->cnsts[i].constraint);
387 var->staged_weight=weight;
388 xbt_assert(!var->weight);
391 xbt_assert(var->cnsts_number < var->cnsts_size, "Too much constraints");
393 elem = &(var->cnsts[var->cnsts_number++]);
396 elem->constraint = cnst;
397 elem->variable = var;
401 xbt_swag_insert_at_head(elem, &(elem->constraint->element_set));
402 lmm_increase_concurrency(elem->constraint);
405 xbt_swag_insert_at_tail(elem, &(elem->constraint->element_set));
407 if(!sys->selective_update_active) {
408 make_constraint_active(sys, cnst);
409 } else if(elem->value>0 || var->weight >0) {
410 make_constraint_active(sys, cnst);
411 lmm_update_modified_set(sys, cnst);
412 //TODOLATER: Why do we need this second call?
413 if (var->cnsts_number > 1)
414 lmm_update_modified_set(sys, var->cnsts[0].constraint);
417 lmm_check_concurrency(sys);
420 void lmm_expand_add(lmm_system_t sys, lmm_constraint_t cnst,
421 lmm_variable_t var, double value)
426 lmm_check_concurrency(sys);
428 for (i = 0; i < var->cnsts_number; i++)
429 if (var->cnsts[i].constraint == cnst)
432 if (i < var->cnsts_number) {
433 if (cnst->sharing_policy)
434 var->cnsts[i].value += value;
436 var->cnsts[i].value = MAX(var->cnsts[i].value, value);
437 lmm_update_modified_set(sys, cnst);
439 lmm_expand(sys, cnst, var, value);
441 lmm_check_concurrency(sys);
444 lmm_constraint_t lmm_get_cnst_from_var(lmm_system_t /*sys*/,
448 if (num < var->cnsts_number)
449 return (var->cnsts[num].constraint);
454 double lmm_get_cnst_weight_from_var(lmm_system_t /*sys*/,
458 if (num < var->cnsts_number)
459 return (var->cnsts[num].value);
464 int lmm_get_number_of_cnst_from_var(lmm_system_t /*sys*/,
467 return (var->cnsts_number);
470 lmm_variable_t lmm_get_var_from_cnst(lmm_system_t /*sys*/,
471 lmm_constraint_t cnst,
472 lmm_element_t * elem)
475 *elem = (lmm_element_t) xbt_swag_getFirst(&(cnst->element_set));
477 *elem = (lmm_element_t) xbt_swag_getNext(*elem, cnst->element_set.offset);
479 return (*elem)->variable;
484 //if we modify the swag between calls, normal version may loop forever
485 //this safe version ensures that we browse the swag elements only once
486 lmm_variable_t lmm_get_var_from_cnst_safe(lmm_system_t /*sys*/,
487 lmm_constraint_t cnst,
488 lmm_element_t * elem,
489 lmm_element_t * nextelem,
493 *elem = (lmm_element_t) xbt_swag_getFirst(&(cnst->element_set));
494 *numelem = xbt_swag_size(&(cnst->element_set))-1;
503 *nextelem = (lmm_element_t) xbt_swag_getNext(*elem, cnst->element_set.offset);
504 return (*elem)->variable;
509 void *lmm_constraint_id(lmm_constraint_t cnst)
514 void *lmm_variable_id(lmm_variable_t var)
519 static XBT_INLINE void saturated_constraint_set_update(double usage,
521 dyn_light_t saturated_constraint_set,
524 xbt_assert(usage > 0,"Impossible");
526 if (*min_usage < 0 || *min_usage > usage) {
528 XBT_HERE(" min_usage=%f (cnst->remaining / cnst->usage =%f)", *min_usage, usage);
529 saturated_constraint_set->data[0] = cnst_light_num;
530 saturated_constraint_set->pos = 1;
531 } else if (*min_usage == usage) {
532 if(saturated_constraint_set->pos == saturated_constraint_set->size) { // realloc the size
533 saturated_constraint_set->size *= 2;
534 saturated_constraint_set->data = (int*) xbt_realloc(saturated_constraint_set->data, (saturated_constraint_set->size) * sizeof(int));
536 saturated_constraint_set->data[saturated_constraint_set->pos] = cnst_light_num;
537 saturated_constraint_set->pos++;
541 static XBT_INLINE void saturated_variable_set_update(
542 s_lmm_constraint_light_t *cnst_light_tab,
543 dyn_light_t saturated_constraint_set,
546 /* Add active variables (i.e. variables that need to be set) from the set of constraints to saturate (cnst_light_tab)*/
547 lmm_constraint_light_t cnst = NULL;
549 lmm_element_t elem = NULL;
550 xbt_swag_t elem_list = NULL;
552 for(i = 0; i< saturated_constraint_set->pos; i++){
553 cnst = &cnst_light_tab[saturated_constraint_set->data[i]];
554 elem_list = &(cnst->cnst->active_element_set);
555 xbt_swag_foreach(_elem, elem_list) {
556 elem = (lmm_element_t)_elem;
557 //Visiting active_element_set, so, by construction, should never get a zero weight, correct?
558 xbt_assert(elem->variable->weight > 0);
559 if ((elem->value > 0))
560 xbt_swag_insert(elem->variable, &(sys->saturated_variable_set));
565 void lmm_print(lmm_system_t sys)
567 void *_cnst, *_elem, *_var;
568 lmm_constraint_t cnst = NULL;
569 lmm_element_t elem = NULL;
570 lmm_variable_t var = NULL;
571 xbt_swag_t cnst_list = NULL;
572 xbt_swag_t var_list = NULL;
573 xbt_swag_t elem_list = NULL;
574 char print_buf[1024];
575 char *trace_buf = (char*) xbt_malloc0(sizeof(char));
578 /* Printing Objective */
579 var_list = &(sys->variable_set);
580 sprintf(print_buf, "MAX-MIN ( ");
582 xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
583 strcat(trace_buf, print_buf);
584 xbt_swag_foreach(_var, var_list) {
585 var = (lmm_variable_t)_var;
586 sprintf(print_buf, "'%d'(%f) ", var->id_int, var->weight);
588 xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
589 strcat(trace_buf, print_buf);
591 sprintf(print_buf, ")");
593 xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
594 strcat(trace_buf, print_buf);
595 XBT_DEBUG("%20s", trace_buf);
596 trace_buf[0] = '\000';
598 XBT_DEBUG("Constraints");
599 /* Printing Constraints */
600 cnst_list = &(sys->active_constraint_set);
601 xbt_swag_foreach(_cnst, cnst_list) {
602 cnst = (lmm_constraint_t)_cnst;
604 elem_list = &(cnst->element_set);
605 sprintf(print_buf, "\t");
607 xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
608 strcat(trace_buf, print_buf);
609 sprintf(print_buf, "%s(",(cnst->sharing_policy)?"":"max");
611 xbt_realloc(trace_buf,
612 strlen(trace_buf) + strlen(print_buf) + 1);
613 strcat(trace_buf, print_buf);
614 xbt_swag_foreach(_elem, elem_list) {
615 elem = (lmm_element_t)_elem;
616 sprintf(print_buf, "%f.'%d'(%f) %s ", elem->value,
617 elem->variable->id_int, elem->variable->value,(cnst->sharing_policy)?"+":",");
619 xbt_realloc(trace_buf,
620 strlen(trace_buf) + strlen(print_buf) + 1);
621 strcat(trace_buf, print_buf);
622 if(cnst->sharing_policy)
623 sum += elem->value * elem->variable->value;
625 sum = MAX(sum,elem->value * elem->variable->value);
627 sprintf(print_buf, "0) <= %f ('%d')", cnst->bound, cnst->id_int);
629 xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
630 strcat(trace_buf, print_buf);
632 if (!cnst->sharing_policy) {
633 sprintf(print_buf, " [MAX-Constraint]");
635 xbt_realloc(trace_buf,
636 strlen(trace_buf) + strlen(print_buf) + 1);
637 strcat(trace_buf, print_buf);
639 XBT_DEBUG("%s", trace_buf);
640 trace_buf[0] = '\000';
641 xbt_assert(!double_positive(sum - cnst->bound, cnst->bound*sg_maxmin_precision),
642 "Incorrect value (%f is not smaller than %f): %g",
643 sum, cnst->bound, sum - cnst->bound);
646 XBT_DEBUG("Variables");
647 /* Printing Result */
648 xbt_swag_foreach(_var, var_list) {
649 var = (lmm_variable_t)_var;
650 if (var->bound > 0) {
651 XBT_DEBUG("'%d'(%f) : %f (<=%f)", var->id_int, var->weight, var->value,
653 xbt_assert(!double_positive(var->value - var->bound, var->bound*sg_maxmin_precision),
654 "Incorrect value (%f is not smaller than %f",
655 var->value, var->bound);
657 XBT_DEBUG("'%d'(%f) : %f", var->id_int, var->weight, var->value);
664 void lmm_solve(lmm_system_t sys)
666 void *_var, *_cnst, *_cnst_next, *_elem;
667 lmm_variable_t var = NULL;
668 lmm_constraint_t cnst = NULL;
669 lmm_element_t elem = NULL;
670 xbt_swag_t cnst_list = NULL;
671 xbt_swag_t var_list = NULL;
672 xbt_swag_t elem_list = NULL;
673 double min_usage = -1;
674 double min_bound = -1;
676 if (!(sys->modified))
679 XBT_IN("(sys=%p)", sys);
682 * 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.
686 selective_update_active ? &(sys->modified_constraint_set) :
687 &(sys->active_constraint_set);
689 XBT_DEBUG("Active constraints : %d", xbt_swag_size(cnst_list));
690 /* Init: Only modified code portions: reset the value of active variables */
691 xbt_swag_foreach(_cnst, cnst_list) {
692 cnst = (lmm_constraint_t)_cnst;
693 elem_list = &(cnst->element_set);
694 //XBT_DEBUG("Variable set : %d", xbt_swag_size(elem_list));
695 xbt_swag_foreach(_elem, elem_list) {
696 var = ((lmm_element_t)_elem)->variable;
697 if (var->weight <= 0.0)
703 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));
704 int cnst_light_num = 0;
705 dyn_light_t saturated_constraint_set = xbt_new0(s_dyn_light_t,1);
706 saturated_constraint_set->size = 5;
707 saturated_constraint_set->data = xbt_new0(int, saturated_constraint_set->size);
709 xbt_swag_foreach_safe(_cnst, _cnst_next, cnst_list) {
710 cnst = (lmm_constraint_t)_cnst;
711 /* INIT: Collect constraints that actually need to be saturated (i.e remaining and usage are strictly positive) into cnst_light_tab. */
712 cnst->remaining = cnst->bound;
713 if (!double_positive(cnst->remaining, cnst->bound*sg_maxmin_precision))
716 elem_list = &(cnst->element_set);
717 xbt_swag_foreach(_elem, elem_list) {
718 elem = (lmm_element_t)_elem;
719 /* 0-weighted elements (ie, sleep actions) are at the end of the swag and we don't want to consider them */
720 if (elem->variable->weight <= 0)
722 if ((elem->value > 0)) {
723 if (cnst->sharing_policy)
724 cnst->usage += elem->value / elem->variable->weight;
725 else if (cnst->usage < elem->value / elem->variable->weight)
726 cnst->usage = elem->value / elem->variable->weight;
728 make_elem_active(elem);
729 simgrid::surf::Action *action = static_cast<simgrid::surf::Action*>(elem->variable->id);
730 if (sys->keep_track && !action->is_linked())
731 sys->keep_track->push_back(*action);
734 XBT_DEBUG("Constraint '%d' usage: %f remaining: %f ", cnst->id_int, cnst->usage, cnst->remaining);
735 /* Saturated constraints update */
737 if(cnst->usage > 0) {
738 cnst_light_tab[cnst_light_num].cnst = cnst;
739 cnst->cnst_light = &(cnst_light_tab[cnst_light_num]);
740 cnst_light_tab[cnst_light_num].remaining_over_usage = cnst->remaining / cnst->usage;
741 saturated_constraint_set_update(cnst_light_tab[cnst_light_num].remaining_over_usage,
742 cnst_light_num, saturated_constraint_set, &min_usage);
743 xbt_assert(cnst->active_element_set.count>0, "There is no sense adding a constraint that has no active element!" );
748 saturated_variable_set_update( cnst_light_tab,
749 saturated_constraint_set,
752 /* Saturated variables update */
755 /* Fix the variables that have to be */
756 var_list = &(sys->saturated_variable_set);
758 xbt_swag_foreach(_var, var_list) {
759 var = (lmm_variable_t)_var;
760 if (var->weight <= 0.0)
762 /* First check if some of these variables could reach their upper
763 bound and update min_bound accordingly. */
765 ("var=%d, var->bound=%f, var->weight=%f, min_usage=%f, var->bound*var->weight=%f",
766 var->id_int, var->bound, var->weight, min_usage,
767 var->bound * var->weight);
768 if ((var->bound > 0) && (var->bound * var->weight < min_usage)) {
770 min_bound = var->bound*var->weight;
772 min_bound = MIN(min_bound, (var->bound*var->weight));
773 XBT_DEBUG("Updated min_bound=%f", min_bound);
778 while ((var = (lmm_variable_t)xbt_swag_getFirst(var_list))) {
782 //If no variable could reach its bound, deal iteratively the constraints usage ( at worst one constraint is saturated at each cycle)
783 var->value = min_usage / var->weight;
784 XBT_DEBUG("Setting %p (%d) value to %f\n", var, var->id_int, var->value);
786 //If there exist a variable that can reach its bound, only update it (and other with the same bound) for now.
787 if (double_equals(min_bound, var->bound*var->weight, sg_maxmin_precision)){
788 var->value = var->bound;
789 XBT_DEBUG("Setting %p (%d) value to %f\n", var, var->id_int, var->value);
792 // Variables which bound is different are not considered for this cycle, but they will be afterwards.
793 XBT_DEBUG("Do not consider %p (%d) \n", var, var->id_int);
794 xbt_swag_remove(var, var_list);
798 XBT_DEBUG("Min usage: %f, Var(%d)->weight: %f, Var(%d)->value: %f ",
799 min_usage, var->id_int, var->weight, var->id_int, var->value);
802 /* Update the usage of contraints where this variable is involved */
803 for (i = 0; i < var->cnsts_number; i++) {
804 elem = &var->cnsts[i];
805 cnst = elem->constraint;
806 if (cnst->sharing_policy) {
807 //Remember: shared constraints require that sum(elem->value * var->value) < cnst->bound
808 double_update(&(cnst->remaining), elem->value * var->value, cnst->bound*sg_maxmin_precision);
809 double_update(&(cnst->usage), elem->value / var->weight, sg_maxmin_precision);
810 //If the constraint is saturated, remove it from the set of active constraints (light_tab)
811 if(!double_positive(cnst->usage,sg_maxmin_precision) || !double_positive(cnst->remaining,cnst->bound*sg_maxmin_precision)) {
812 if (cnst->cnst_light) {
813 int index = (cnst->cnst_light-cnst_light_tab);
814 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 ",
815 index,cnst_light_num, cnst, cnst->cnst_light, cnst_light_tab, cnst->usage, cnst->remaining, cnst->bound);
816 cnst_light_tab[index]=cnst_light_tab[cnst_light_num-1];
817 cnst_light_tab[index].cnst->cnst_light = &cnst_light_tab[index];
819 cnst->cnst_light = NULL;
822 cnst->cnst_light->remaining_over_usage = cnst->remaining / cnst->usage;
824 make_elem_inactive(elem);
826 //Remember: non-shared constraints only require that max(elem->value * var->value) < cnst->bound
828 make_elem_inactive(elem);
829 elem_list = &(cnst->element_set);
830 xbt_swag_foreach(_elem, elem_list) {
831 elem = (lmm_element_t)_elem;
832 if (elem->variable->weight <= 0) break; //Found an inactive variable -> no more active variables
833 if (elem->variable->value > 0) continue;
835 cnst->usage = MAX(cnst->usage, elem->value / elem->variable->weight);
837 //If the constraint is saturated, remove it from the set of active constraints (light_tab)
838 if(!double_positive(cnst->usage,sg_maxmin_precision) || !double_positive(cnst->remaining,cnst->bound*sg_maxmin_precision)) {
839 if(cnst->cnst_light) {
840 int index = (cnst->cnst_light-cnst_light_tab);
841 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 ",
842 index,cnst_light_num, cnst, cnst->cnst_light, cnst_light_tab, cnst->usage, cnst->remaining, cnst->bound);
843 cnst_light_tab[index]=cnst_light_tab[cnst_light_num-1];
844 cnst_light_tab[index].cnst->cnst_light = &cnst_light_tab[index];
846 cnst->cnst_light = NULL;
849 cnst->cnst_light->remaining_over_usage = cnst->remaining / cnst->usage;
850 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." );
854 xbt_swag_remove(var, var_list);
857 /* Find out which variables reach the maximum */
860 saturated_constraint_set->pos = 0;
862 for(pos=0; pos<cnst_light_num; pos++){
863 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);
864 saturated_constraint_set_update(
865 cnst_light_tab[pos].remaining_over_usage,
867 saturated_constraint_set,
871 saturated_variable_set_update( cnst_light_tab,
872 saturated_constraint_set,
875 } while (cnst_light_num > 0);
878 if (sys->selective_update_active)
879 lmm_remove_all_modified_set(sys);
881 if (XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug)) {
885 xbt_free(saturated_constraint_set->data);
886 xbt_free(saturated_constraint_set);
887 xbt_free(cnst_light_tab);
892 /** \brief Attribute the value bound to var->bound.
894 * \param sys the lmm_system_t
895 * \param var the lmm_variable_t
896 * \param bound the new bound to associate with var
898 * Makes var->bound equal to bound. Whenever this function is called
899 * a change is signed in the system. To
900 * avoid false system changing detection it is a good idea to test
901 * (bound != 0) before calling it.
904 void lmm_update_variable_bound(lmm_system_t sys, lmm_variable_t var,
910 if (var->cnsts_number)
911 lmm_update_modified_set(sys, var->cnsts[0].constraint);
916 int lmm_concurrency_slack(lmm_constraint_t cnstr){
923 //FIXME MARTIN: Replace by infinite value std::numeric_limits<int>::(max)(), or something better within Simgrid?
924 if(cnstr->concurrency_limit<0)
927 if (XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug)) {
928 xbt_swag_foreach(_elem, &(cnstr->element_set)) {
929 elem = (lmm_element_t)_elem;
930 if (elem->variable->weight <= 0) break; //Found an inactive variable
934 slack=cnstr->concurrency_limit-concurrency;
935 xbt_assert(slack>=0,"concurrency slack should not be negative!");
939 return cnstr->concurrency_limit - cnstr->concurrency_current;
943 /** \brief Measure the minimum concurrency slack across all constraints where var is involved
945 * \param The variable to check for
948 int lmm_cnstrs_min_concurrency_slack(lmm_variable_t var){
950 //FIXME MARTIN: Replace by infinite value std::numeric_limits<int>::(max)(), or something better within Simgrid?
951 int slack,minslack=666;
952 for (i = 0; i < var->cnsts_number; i++) {
953 slack=lmm_concurrency_slack(var->cnsts[i].constraint);
955 //This is only an optimization, to avoid looking at more constraints when slack is already zero
956 //Disable it when debugging to let lmm_concurrency_slack catch nasty things
957 if(!slack && !XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug))
967 /* /Check if a variable can be enabled
969 * Make sure to set staged_weight before, if your intent is only to check concurrency
971 int lmm_can_enable_var(lmm_variable_t var){
972 return var->staged_weight>0 && lmm_cnstrs_min_concurrency_slack(var)>=var->concurrency_share;
976 //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.
977 //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)
979 void lmm_enable_var(lmm_system_t sys, lmm_variable_t var){
984 xbt_assert(lmm_can_enable_var(var));
986 var->weight = var->staged_weight;
987 var->staged_weight = 0;
989 //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.
991 xbt_swag_remove(var, &(sys->variable_set));
992 xbt_swag_insert_at_head(var, &(sys->variable_set));
993 for (i = 0; i < var->cnsts_number; i++) {
994 elem = &var->cnsts[i];
995 xbt_swag_remove(elem, &(elem->constraint->element_set));
996 xbt_swag_insert_at_head(elem, &(elem->constraint->element_set));
997 lmm_increase_concurrency(elem->constraint);
999 if (var->cnsts_number)
1000 lmm_update_modified_set(sys, var->cnsts[0].constraint);
1002 lmm_check_concurrency(sys);
1005 void lmm_disable_var(lmm_system_t sys, lmm_variable_t var){
1009 xbt_assert(!var->staged_weight,"Staged weight should have been cleared");
1010 //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.
1011 xbt_swag_remove(var, &(sys->variable_set));
1012 xbt_swag_insert_at_tail(var, &(sys->variable_set));
1013 if (var->cnsts_number)
1014 lmm_update_modified_set(sys, var->cnsts[0].constraint);
1015 for (i = 0; i < var->cnsts_number; i++) {
1016 elem = &var->cnsts[i];
1017 xbt_swag_remove(elem, &(elem->constraint->element_set));
1018 xbt_swag_insert_at_tail(elem, &(elem->constraint->element_set));
1020 xbt_swag_remove(elem, &(elem->constraint->active_element_set));
1022 lmm_decrease_concurrency(elem->constraint);
1026 var->staged_weight=0.0;
1028 lmm_check_concurrency(sys);
1031 /* /brief Find variables that can be enabled and enable them.
1033 * Assuming that the variable has already been removed from non-zero weights
1034 * Can we find a staged variable to add?
1035 * If yes, check that none of the constraints that this variable is involved in is at the limit of its concurrency
1036 * And then add it to active variables
1038 void lmm_on_disabled_var(lmm_system_t sys, lmm_constraint_t cnstr){
1041 if(cnstr->concurrency_limit<0)
1045 xbt_swag_foreach(elem, &(cnstr->element_set)) {
1047 //active variables are checked to see if we already reached the maximum (SHOULD NOT HAPPEN BECAUSE WE SHOULD HAVE JUST DEACTIVATED ONE)
1048 if (elem->variable->weight > 0){
1050 xbt_assert(elem->variable->staged_weight==0.0,"Staged weight should have been reset");
1051 } else if (elem->variable->staged_weight>0 )
1053 //Found a staged variable
1054 //TODOLATER: Add random timing function to model reservation protocol fuzziness? Then how to make sure that staged variables will eventually be called?
1055 if(lmm_can_enable_var(elem->variable)){
1056 lmm_enable_var(sys,elem->variable);
1061 xbt_assert(concurrency<=cnstr->concurrency_limit,"Concurrency overflow!");
1062 if(concurrency==cnstr->concurrency_limit)
1066 lmm_check_concurrency(sys);
1070 /* \brief update the weight of a variable, and enable/disable it.
1071 * @return Returns whether a change was made
1073 void lmm_update_variable_weight(lmm_system_t sys, lmm_variable_t var,
1078 xbt_assert(weight>=0,"Variable weight should not be negative!");
1080 if (weight == var->weight)
1083 int enabling_var= (weight>0 && var->weight<=0);
1084 int disabling_var= (weight<=0 && var->weight>0);
1086 XBT_IN("(sys=%p, var=%p, weight=%f)", sys, var, weight);
1090 //Are we enabling this variable?
1092 var->staged_weight = weight;
1093 minslack=lmm_cnstrs_min_concurrency_slack(var);
1095 XBT_DEBUG("Staging var (instead of enabling) because min concurrency slack %i, with weight %f", minslack, weight);
1098 XBT_DEBUG("Enabling var with min concurrency slack %i", minslack);
1099 lmm_enable_var(sys,var);
1100 } else if (disabling_var){
1101 //Are we disabling this variable?
1102 lmm_disable_var(sys,var);
1107 lmm_check_concurrency(sys);
1113 double lmm_get_variable_weight(lmm_variable_t var)
1118 void lmm_update_constraint_bound(lmm_system_t sys,
1119 lmm_constraint_t cnst,
1123 lmm_update_modified_set(sys, cnst);
1124 cnst->bound = bound;
1127 int lmm_constraint_used(lmm_system_t sys, lmm_constraint_t cnst)
1129 return xbt_swag_belongs(cnst, &(sys->active_constraint_set));
1132 XBT_INLINE lmm_constraint_t lmm_get_first_active_constraint(lmm_system_t
1135 return (lmm_constraint_t)xbt_swag_getFirst(&(sys->active_constraint_set));
1138 XBT_INLINE lmm_constraint_t lmm_get_next_active_constraint(lmm_system_t
1143 return (lmm_constraint_t)xbt_swag_getNext(cnst, (sys->active_constraint_set).offset);
1146 #ifdef HAVE_LATENCY_BOUND_TRACKING
1147 XBT_INLINE int lmm_is_variable_limited_by_latency(lmm_variable_t var)
1149 return (double_equals(var->bound, var->value, var->bound*sg_maxmin_precision));
1154 /** \brief Update the constraint set propagating recursively to
1155 * other constraints so the system should not be entirely computed.
1157 * \param sys the lmm_system_t
1158 * \param cnst the lmm_constraint_t affected by the change
1160 * A recursive algorithm to optimize the system recalculation selecting only
1161 * constraints that have changed. Each constraint change is propagated
1162 * to the list of constraints for each variable.
1164 static void lmm_update_modified_set_rec(lmm_system_t sys,
1165 lmm_constraint_t cnst)
1169 //TODOLATER: Why lmm_modified_set has been changed in git version 2392B5157...? Looks equivalent logically and less obvious..
1171 xbt_swag_foreach(_elem, &cnst->element_set) {
1172 lmm_variable_t var = ((lmm_element_t)_elem)->variable;
1173 s_lmm_element_t *cnsts = var->cnsts;
1175 /* 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) */
1178 for (i = 0; var->visited != sys->visited_counter
1179 && i < var->cnsts_number ; i++) {
1180 if (cnsts[i].constraint != cnst
1181 && !xbt_swag_belongs(cnsts[i].constraint,
1182 &sys->modified_constraint_set)) {
1183 xbt_swag_insert(cnsts[i].constraint, &sys->modified_constraint_set);
1184 lmm_update_modified_set_rec(sys, cnsts[i].constraint);
1187 //var will be ignored in later visits as long as sys->visited_counter does not move
1188 var->visited = sys->visited_counter;
1192 static void lmm_update_modified_set(lmm_system_t sys,
1193 lmm_constraint_t cnst)
1195 /* nothing to do if selective update isn't active */
1196 if (sys->selective_update_active
1197 && !xbt_swag_belongs(cnst, &sys->modified_constraint_set)) {
1198 xbt_swag_insert(cnst, &sys->modified_constraint_set);
1199 lmm_update_modified_set_rec(sys, cnst);
1203 /** \brief Remove all constraints of the modified_constraint_set.
1205 * \param sys the lmm_system_t
1208 static void lmm_remove_all_modified_set(lmm_system_t sys)
1211 //We cleverly un-flag all variables just by incrementing sys->visited_counter
1212 //In effect, the var->visited value will no more be equal to sys->visited counter
1213 //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).
1214 if (++sys->visited_counter == 1) {
1215 /* the counter wrapped around, reset each variable->visited */
1217 xbt_swag_foreach(_var, &sys->variable_set)
1218 ((lmm_variable_t)_var)->visited = 0;
1220 xbt_swag_reset(&sys->modified_constraint_set);
1224 * Returns total resource load
1226 * \param cnst the lmm_constraint_t associated to the resource
1229 * This is dead code, but we may use it later for debug/trace.
1231 double lmm_constraint_get_usage(lmm_constraint_t cnst) {
1233 xbt_swag_t elem_list = &(cnst->element_set);
1235 lmm_element_t elem = NULL;
1237 xbt_swag_foreach(_elem, elem_list) {
1238 elem = (lmm_element_t)_elem;
1239 /* 0-weighted elements (ie, sleep actions) are at the end of the swag and we don't want to consider them */
1240 if (elem->variable->weight <= 0)
1242 if ((elem->value > 0)) {
1243 if (cnst->sharing_policy)
1244 usage += elem->value * elem->variable->value;
1245 else if (usage < elem->value * elem->variable->value)
1246 usage = elem->value * elem->variable->value;
1252 void lmm_check_concurrency(lmm_system_t sys){
1256 lmm_constraint_t cnst;
1259 //These checks are very expensive, so do them only if we want to debug SURF LMM
1260 if (XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug)) {
1262 xbt_swag_foreach(_cnst, &(sys->constraint_set)) {
1263 cnst = (lmm_constraint_t) _cnst;
1265 if(cnst->concurrency_limit<0)
1267 xbt_swag_foreach(_elem, &(cnst->element_set)) {
1268 elem = (lmm_element_t)_elem;
1269 if (elem->variable->weight > 0)
1272 //We should have staged variables only if conccurency is reached in some constraint
1273 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!");
1276 xbt_assert(cnst->concurrency_limit<0 || cnst->concurrency_limit >= concurrency,"concurrency check failed!");
1277 xbt_assert(cnst->concurrency_current == concurrency, "concurrency_current is out-of-date!");