Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Enforce some order on the tags; needs flexml 1.8 to get relevant error messages when...
[simgrid.git] / src / surf / maxmin.c
1 /*      $Id$     */
2
3 /* Copyright (c) 2004 Arnaud Legrand. All rights reserved.                  */
4
5 /* This program is free software; you can redistribute it and/or modify it
6  * under the terms of the license (GNU LGPL) which comes with this package. */
7
8
9 #include "xbt/sysdep.h"
10 #include "xbt/log.h"
11 #include "xbt/mallocator.h"
12 #include "maxmin_private.h"
13 #include <stdlib.h>
14 #include <math.h>
15 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_maxmin, surf,
16                                 "Logging specific to SURF (maxmin)");
17
18 static void *lmm_variable_mallocator_new_f(void);
19 static void lmm_variable_mallocator_free_f(void *var);
20 static void lmm_variable_mallocator_reset_f(void *var);
21
22 lmm_system_t lmm_system_new(void)
23 {
24   lmm_system_t l = NULL;
25   s_lmm_variable_t var;
26   s_lmm_constraint_t cnst;
27
28   l = xbt_new0(s_lmm_system_t, 1);
29
30   l->modified = 0;
31   xbt_swag_init(&(l->variable_set),
32                 xbt_swag_offset(var, variable_set_hookup));
33   xbt_swag_init(&(l->constraint_set),
34                 xbt_swag_offset(cnst, constraint_set_hookup));
35
36   xbt_swag_init(&(l->active_constraint_set),
37                 xbt_swag_offset(cnst, active_constraint_set_hookup));
38
39   xbt_swag_init(&(l->saturated_variable_set),
40                 xbt_swag_offset(var, saturated_variable_set_hookup));
41   xbt_swag_init(&(l->saturated_constraint_set),
42                 xbt_swag_offset(cnst, saturated_constraint_set_hookup));
43
44   l->variable_mallocator = xbt_mallocator_new(64,
45                                               lmm_variable_mallocator_new_f,
46                                               lmm_variable_mallocator_free_f,
47                                               lmm_variable_mallocator_reset_f);
48
49   return l;
50 }
51
52 void lmm_system_free(lmm_system_t sys)
53 {
54   lmm_variable_t var = NULL;
55   lmm_constraint_t cnst = NULL;
56
57   while ((var = extract_variable(sys)))
58     lmm_var_free(sys, var);
59
60   while ((cnst = extract_constraint(sys)))
61     lmm_cnst_free(sys, cnst);
62
63   xbt_mallocator_free(sys->variable_mallocator);
64   free(sys);
65 }
66
67 void lmm_variable_disable(lmm_system_t sys, lmm_variable_t var)
68 {
69   int i;
70   lmm_element_t elem = NULL;
71
72   XBT_IN2("(sys=%p, var=%p)", sys, var);
73   sys->modified = 1;
74
75   for (i = 0; i < var->cnsts_number; i++) {
76     elem = &var->cnsts[i];
77     xbt_swag_remove(elem, &(elem->constraint->element_set));
78     xbt_swag_remove(elem, &(elem->constraint->active_element_set));
79     if (!xbt_swag_size(&(elem->constraint->element_set)))
80       make_constraint_inactive(sys, elem->constraint);
81   }
82   var->cnsts_number = 0;
83   XBT_OUT;
84 }
85
86 static void lmm_var_free(lmm_system_t sys, lmm_variable_t var)
87 {
88
89   lmm_variable_disable(sys, var);
90   free(var->cnsts);
91   xbt_mallocator_release(sys->variable_mallocator, var);
92 }
93
94 static void lmm_cnst_free(lmm_system_t sys, lmm_constraint_t cnst)
95 {
96 /*   xbt_assert0(xbt_swag_size(&(cnst->element_set)), */
97 /*            "This list should be empty!"); */
98   remove_active_constraint(sys, cnst);
99   free(cnst);
100 }
101
102 lmm_constraint_t lmm_constraint_new(lmm_system_t sys, void *id,
103                                     double bound_value)
104 {
105   lmm_constraint_t cnst = NULL;
106   s_lmm_element_t elem;
107
108   cnst = xbt_new0(s_lmm_constraint_t, 1);
109   cnst->id = id;
110   xbt_swag_init(&(cnst->element_set),
111                 xbt_swag_offset(elem, element_set_hookup));
112   xbt_swag_init(&(cnst->active_element_set),
113                 xbt_swag_offset(elem, active_element_set_hookup));
114
115   cnst->bound = bound_value;
116   cnst->usage = 0;
117   cnst->shared = 1;
118   insert_constraint(sys, cnst);
119
120   return cnst;
121 }
122
123 void lmm_constraint_shared(lmm_constraint_t cnst)
124 {
125   cnst->shared = 0;
126 }
127
128 void lmm_constraint_free(lmm_system_t sys, lmm_constraint_t cnst)
129 {
130   remove_constraint(sys, cnst);
131   lmm_cnst_free(sys, cnst);
132 }
133
134 static void *lmm_variable_mallocator_new_f(void)
135 {
136   return xbt_new(s_lmm_variable_t, 1);
137 }
138
139 static void lmm_variable_mallocator_free_f(void *var)
140 {
141   xbt_free(var);
142 }
143
144 static void lmm_variable_mallocator_reset_f(void *var)
145 {
146   /* memset to zero like calloc */
147   memset(var, 0, sizeof(s_lmm_variable_t));
148 }
149
150 lmm_variable_t lmm_variable_new(lmm_system_t sys, void *id,
151                                 double weight,
152                                 double bound, int number_of_constraints)
153 {
154   lmm_variable_t var = NULL;
155   int i;
156
157   XBT_IN5("(sys=%p, id=%p, weight=%f, bound=%f, num_cons =%d)",
158           sys, id, weight, bound, number_of_constraints);
159
160   var = xbt_mallocator_get(sys->variable_mallocator);
161   var->id = id;
162   var->cnsts = xbt_new0(s_lmm_element_t, number_of_constraints);
163   for (i = 0; i < number_of_constraints; i++) {
164     /* Should be useless because of the 
165        calloc but it seems to help valgrind... */
166     var->cnsts[i].element_set_hookup.next = NULL;
167     var->cnsts[i].element_set_hookup.prev = NULL;
168     var->cnsts[i].active_element_set_hookup.next = NULL;
169     var->cnsts[i].active_element_set_hookup.prev = NULL;
170     var->cnsts[i].constraint = NULL;
171     var->cnsts[i].variable = NULL;
172     var->cnsts[i].value = 0.0;
173   }
174   var->cnsts_size = number_of_constraints;
175   var->cnsts_number = 0;        /* Should be useless because of the 
176                                    calloc but it seems to help valgrind... */
177   var->weight = weight;
178   var->bound = bound;
179   var->value = 0.0;
180   var->df = 0.0;
181
182   var->func_f = func_f_def;
183   var->func_fp = func_fp_def;
184   var->func_fpi = func_fpi_def;
185
186   if (weight)
187     xbt_swag_insert_at_head(var, &(sys->variable_set));
188   else
189     xbt_swag_insert_at_tail(var, &(sys->variable_set));
190   XBT_OUT;
191   return var;
192 }
193
194 void lmm_variable_free(lmm_system_t sys, lmm_variable_t var)
195 {
196   remove_variable(sys, var);
197   lmm_var_free(sys, var);
198 }
199
200 double lmm_variable_getvalue(lmm_variable_t var)
201 {
202   return (var->value);
203 }
204
205 void lmm_expand(lmm_system_t sys, lmm_constraint_t cnst,
206                 lmm_variable_t var, double value)
207 {
208   lmm_element_t elem = NULL;
209
210   sys->modified = 1;
211
212   xbt_assert0(var->cnsts_number < var->cnsts_size, "Too much constraints");
213
214   elem = &(var->cnsts[var->cnsts_number++]);
215
216   elem->value = value;
217   elem->constraint = cnst;
218   elem->variable = var;
219
220   if (var->weight)
221     xbt_swag_insert_at_head(elem, &(elem->constraint->element_set));
222   else
223     xbt_swag_insert_at_tail(elem, &(elem->constraint->element_set));
224
225   make_constraint_active(sys, cnst);
226 }
227
228 void lmm_expand_add(lmm_system_t sys, lmm_constraint_t cnst,
229                     lmm_variable_t var, double value)
230 {
231   int i;
232   sys->modified = 1;
233
234   for (i = 0; i < var->cnsts_number; i++)
235     if (var->cnsts[i].constraint == cnst)
236       break;
237
238   if (i < var->cnsts_number)
239     var->cnsts[i].value += value;
240   else
241     lmm_expand(sys, cnst, var, value);
242 }
243
244 void lmm_elem_set_value(lmm_system_t sys, lmm_constraint_t cnst,
245                         lmm_variable_t var, double value)
246 {
247   int i;
248
249   for (i = 0; i < var->cnsts_number; i++)
250     if (var->cnsts[i].constraint == cnst)
251       break;
252
253   if (i < var->cnsts_number) {
254     var->cnsts[i].value = value;
255     sys->modified = 1;
256   } else
257     DIE_IMPOSSIBLE;
258 }
259
260 lmm_constraint_t lmm_get_cnst_from_var(lmm_system_t sys,
261                                        lmm_variable_t var, int num)
262 {
263   if (num < var->cnsts_number)
264     return (var->cnsts[num].constraint);
265   else
266     return NULL;
267 }
268
269 int lmm_get_number_of_cnst_from_var(lmm_system_t sys, lmm_variable_t var)
270 {
271   return (var->cnsts_number);
272 }
273
274 lmm_variable_t lmm_get_var_from_cnst(lmm_system_t sys,
275                                      lmm_constraint_t cnst,
276                                      lmm_variable_t * var)
277 {
278   if (!(*var))
279     xbt_swag_getFirst(&(cnst->element_set));
280   else
281     *var = xbt_swag_getNext(*var, cnst->element_set.offset);
282   return *var;
283 }
284
285 void *lmm_constraint_id(lmm_constraint_t cnst)
286 {
287   return cnst->id;
288 }
289
290 void *lmm_variable_id(lmm_variable_t var)
291 {
292   return var->id;
293 }
294
295 static void saturated_constraint_set_update(lmm_system_t sys,
296                                             lmm_constraint_t cnst,
297                                             double *min_usage)
298 {
299   lmm_constraint_t useless_cnst = NULL;
300
301   XBT_IN3("sys=%p, cnst=%p, min_usage=%f", sys, cnst, *min_usage);
302   if (cnst->usage <= 0) {
303     XBT_OUT;
304     return;
305   }
306   if (cnst->remaining <= 0) {
307     XBT_OUT;
308     return;
309   }
310   if ((*min_usage < 0) || (*min_usage > cnst->remaining / cnst->usage)) {
311     *min_usage = cnst->remaining / cnst->usage;
312     LOG3(xbt_log_priority_trace,
313          "min_usage=%f (cnst->remaining=%f, cnst->usage=%f)", *min_usage,
314          cnst->remaining, cnst->usage);
315     while ((useless_cnst =
316             xbt_swag_getFirst(&(sys->saturated_constraint_set))))
317       xbt_swag_remove(useless_cnst, &(sys->saturated_constraint_set));
318
319     xbt_swag_insert(cnst, &(sys->saturated_constraint_set));
320   } else if (*min_usage == cnst->remaining / cnst->usage) {
321     xbt_swag_insert(cnst, &(sys->saturated_constraint_set));
322   }
323   XBT_OUT;
324 }
325
326 static void saturated_variable_set_update(lmm_system_t sys)
327 {
328   lmm_constraint_t cnst = NULL;
329   xbt_swag_t cnst_list = NULL;
330   lmm_element_t elem = NULL;
331   xbt_swag_t elem_list = NULL;
332
333   cnst_list = &(sys->saturated_constraint_set);
334   while ((cnst = xbt_swag_getFirst(cnst_list))) {
335     elem_list = &(cnst->active_element_set);
336     xbt_swag_foreach(elem, elem_list) {
337       if (elem->variable->weight <= 0)
338         break;
339       if ((elem->value > 0))
340         xbt_swag_insert(elem->variable, &(sys->saturated_variable_set));
341     }
342     xbt_swag_remove(cnst, cnst_list);
343   }
344 }
345
346 void lmm_print(lmm_system_t sys)
347 {
348   lmm_constraint_t cnst = NULL;
349   lmm_element_t elem = NULL;
350   lmm_variable_t var = NULL;
351   xbt_swag_t cnst_list = NULL;
352   xbt_swag_t var_list = NULL;
353   xbt_swag_t elem_list = NULL;
354   char print_buf[1024];
355   char *trace_buf = xbt_malloc0(sizeof(char));
356   double sum = 0.0;
357
358   /* Printing Objective */
359   var_list = &(sys->variable_set);
360   sprintf(print_buf, "MAX-MIN ( ");
361   trace_buf =
362       xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
363   strcat(trace_buf, print_buf);
364   xbt_swag_foreach(var, var_list) {
365     sprintf(print_buf, "'%p'(%f) ", var, var->weight);
366     trace_buf =
367         xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
368     strcat(trace_buf, print_buf);
369   }
370   sprintf(print_buf, ")");
371   trace_buf =
372       xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
373   strcat(trace_buf, print_buf);
374   DEBUG1("%s", trace_buf);
375   trace_buf[0] = '\000';
376
377   /* Printing Constraints */
378   cnst_list = &(sys->active_constraint_set);
379   xbt_swag_foreach(cnst, cnst_list) {
380     sum = 0.0;
381     elem_list = &(cnst->element_set);
382     sprintf(print_buf, "\t");
383     trace_buf =
384         xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
385     strcat(trace_buf, print_buf);
386     xbt_swag_foreach(elem, elem_list) {
387       sprintf(print_buf, "%f.'%p'(%f) + ", elem->value,
388               elem->variable, elem->variable->value);
389       trace_buf =
390           xbt_realloc(trace_buf,
391                       strlen(trace_buf) + strlen(print_buf) + 1);
392       strcat(trace_buf, print_buf);
393       sum += elem->value * elem->variable->value;
394     }
395     sprintf(print_buf, "0 <= %f ('%p')", cnst->bound, cnst);
396     trace_buf =
397         xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
398     strcat(trace_buf, print_buf);
399
400     if (!cnst->shared) {
401       sprintf(print_buf, " [MAX-Constraint]");
402       trace_buf =
403           xbt_realloc(trace_buf,
404                       strlen(trace_buf) + strlen(print_buf) + 1);
405       strcat(trace_buf, print_buf);
406     }
407     DEBUG1("%s", trace_buf);
408     trace_buf[0] = '\000';
409     if (double_positive(sum - cnst->bound))
410       WARN3("Incorrect value (%f is not smaller than %f): %g",
411             sum, cnst->bound, sum - cnst->bound);
412   }
413
414   /* Printing Result */
415   xbt_swag_foreach(var, var_list) {
416     if (var->bound > 0) {
417       DEBUG4("'%p'(%f) : %f (<=%f)", var, var->weight, var->value,
418              var->bound);
419       if (double_positive(var->value - var->bound))
420         WARN2("Incorrect value (%f is not smaller than %f",
421               var->value, var->bound);
422     } else
423       DEBUG3("'%p'(%f) : %f", var, var->weight, var->value);
424   }
425
426   free(trace_buf);
427 }
428
429 void lmm_solve(lmm_system_t sys)
430 {
431   lmm_variable_t var = NULL;
432   lmm_constraint_t cnst = NULL;
433   lmm_element_t elem = NULL;
434   xbt_swag_t cnst_list = NULL;
435   xbt_swag_t var_list = NULL;
436   xbt_swag_t elem_list = NULL;
437   double min_usage = -1;
438
439   if (!(sys->modified))
440     return;
441
442   /* Init */
443   var_list = &(sys->variable_set);
444   DEBUG1("Variable set : %d", xbt_swag_size(var_list));
445   xbt_swag_foreach(var, var_list) {
446     int nb=0;
447     int i;
448     var->value = 0.0;
449     for (i = 0; i < var->cnsts_number; i++) {
450       if(var->cnsts[i].value==0.0) nb++;
451     }
452     if((nb==var->cnsts_number) && (var->weight>0.0))
453       var->value = 1.0;
454   }
455
456   /* 
457    * Compute Usage and store the variables that reach the maximum.
458    */
459   cnst_list = &(sys->active_constraint_set);
460   DEBUG1("Active constraints : %d", xbt_swag_size(cnst_list));
461   xbt_swag_foreach(cnst, cnst_list) {
462     /* INIT */
463     cnst->remaining = cnst->bound;
464     cnst->usage = 0;
465     elem_list = &(cnst->element_set);
466     cnst->usage = 0.0;
467     xbt_swag_foreach(elem, elem_list) {
468       if (elem->variable->weight <= 0)
469         break;
470       if ((elem->value > 0)) {
471         if (cnst->shared)
472           cnst->usage += elem->value / elem->variable->weight;
473         else if (cnst->usage < elem->value / elem->variable->weight)
474           cnst->usage = elem->value / elem->variable->weight;
475         DEBUG2("Constraint Usage %p : %f", cnst, cnst->usage);
476         make_elem_active(elem);
477       }
478     }
479     /* Saturated constraints update */
480     saturated_constraint_set_update(sys, cnst, &min_usage);
481   }
482   saturated_variable_set_update(sys);
483
484   /* Saturated variables update */
485
486   do {
487     /* Fix the variables that have to be */
488     var_list = &(sys->saturated_variable_set);
489
490     xbt_swag_foreach(var, var_list) {
491       /* First check if some of these variables have reach their upper
492          bound and update min_usage accordingly. */
493       DEBUG5
494           ("var=%p, var->bound=%f, var->weight=%f, min_usage=%f, var->bound*var->weight=%f",
495            var, var->bound, var->weight, min_usage,
496            var->bound * var->weight);
497       if ((var->bound > 0) && (var->bound * var->weight < min_usage)) {
498         min_usage = var->bound * var->weight;
499         DEBUG1("Updated min_usage=%f", min_usage);
500       }
501     }
502
503
504     while ((var = xbt_swag_getFirst(var_list))) {
505       int i;
506
507       var->value = min_usage / var->weight;
508       DEBUG5("Min usage: %f, Var(%p)->weight: %f, Var(%p)->value: %f ",
509              min_usage, var, var->weight, var, var->value);
510
511
512       /* Update usage */
513
514       for (i = 0; i < var->cnsts_number; i++) {
515         elem = &var->cnsts[i];
516         cnst = elem->constraint;
517         if (cnst->shared) {
518           double_update(&(cnst->remaining), elem->value * var->value);
519           double_update(&(cnst->usage), elem->value / var->weight);
520           make_elem_inactive(elem);
521         } else {                /* FIXME one day: We recompute usage.... :( */
522           cnst->usage = 0.0;
523           make_elem_inactive(elem);
524           xbt_swag_foreach(elem, elem_list) {
525             if (elem->variable->weight <= 0)
526               break;
527             if (elem->variable->value > 0)
528               break;
529             if ((elem->value > 0)) {
530               if (cnst->usage < elem->value / elem->variable->weight)
531                 cnst->usage = elem->value / elem->variable->weight;
532               DEBUG2("Constraint Usage %p : %f", cnst, cnst->usage);
533               make_elem_active(elem);
534             }
535           }
536         }
537       }
538       xbt_swag_remove(var, var_list);
539     }
540
541     /* Find out which variables reach the maximum */
542     cnst_list = &(sys->active_constraint_set);
543     min_usage = -1;
544     xbt_swag_foreach(cnst, cnst_list) {
545       saturated_constraint_set_update(sys, cnst, &min_usage);
546     }
547     saturated_variable_set_update(sys);
548
549   } while (xbt_swag_size(&(sys->saturated_variable_set)));
550
551   sys->modified = 0;
552   if (XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug)) {
553     lmm_print(sys);
554   }
555 }
556
557 /* Not a O(1) function */
558
559 void lmm_update(lmm_system_t sys, lmm_constraint_t cnst,
560                 lmm_variable_t var, double value)
561 {
562   int i;
563
564   sys->modified = 1;
565   for (i = 0; i < var->cnsts_number; i++)
566     if (var->cnsts[i].constraint == cnst) {
567       var->cnsts[i].value = value;
568       return;
569     }
570 }
571
572 /** \brief Attribute the value bound to var->bound.
573  * 
574  *  \param sys the lmm_system_t
575  *  \param var the lmm_variable_t
576  *  \param bound the new bound to associate with var
577  * 
578  *  Makes var->bound equal to bound. Whenever this function is called 
579  *  a change is  signed in the system. To
580  *  avoid false system changing detection it is a good idea to test 
581  *  (bound != 0) before calling it.
582  *
583  */
584 void lmm_update_variable_bound(lmm_system_t sys, lmm_variable_t var,
585                                double bound)
586 {
587   sys->modified = 1;
588   var->bound = bound;
589 }
590
591 /** \brief Add the value delta to var->df (the sum of latencies).
592  * 
593  *  \param sys the lmm_system_t associated
594  *  \param var the lmm_variable_t which need to updated
595  *  \param delta the variation of the latency
596  * 
597  *  Add the value delta to var->df (the sum of latencys associated to the
598  *  flow). Whenever this function is called a change is  signed in the system. To
599  *  avoid false system changing detection it is a good idea to test 
600  *  (delta != 0) before calling it.
601  *
602  */
603 void lmm_update_variable_latency(lmm_system_t sys, lmm_variable_t var,
604                                  double delta)
605 {
606   sys->modified = 1;
607   var->df += delta;
608 }
609
610 void lmm_update_variable_weight(lmm_system_t sys, lmm_variable_t var,
611                                 double weight)
612 {
613   int i;
614   lmm_element_t elem;
615
616   XBT_IN3("(sys=%p, var=%p, weight=%f)", sys, var, weight);
617   sys->modified = 1;
618   var->weight = weight;
619   xbt_swag_remove(var, &(sys->variable_set));
620   if (weight)
621     xbt_swag_insert_at_head(var, &(sys->variable_set));
622   else
623     xbt_swag_insert_at_tail(var, &(sys->variable_set));
624
625   for (i = 0; i < var->cnsts_number; i++) {
626     elem = &var->cnsts[i];
627     xbt_swag_remove(elem, &(elem->constraint->element_set));
628     if (weight)
629       xbt_swag_insert_at_head(elem, &(elem->constraint->element_set));
630     else
631       xbt_swag_insert_at_tail(elem, &(elem->constraint->element_set));
632   }
633   XBT_OUT;
634 }
635
636 double lmm_get_variable_weight(lmm_variable_t var)
637 {
638   return var->weight;
639 }
640
641 void lmm_update_constraint_bound(lmm_system_t sys, lmm_constraint_t cnst,
642                                  double bound)
643 {
644   sys->modified = 1;
645   cnst->bound = bound;
646 }
647
648 int lmm_constraint_used(lmm_system_t sys, lmm_constraint_t cnst)
649 {
650   return xbt_swag_belongs(cnst, &(sys->active_constraint_set));
651 }
652
653 lmm_constraint_t lmm_get_first_active_constraint(lmm_system_t sys)
654 {
655   return xbt_swag_getFirst(&(sys->active_constraint_set));
656 }
657
658 lmm_constraint_t lmm_get_next_active_constraint(lmm_system_t sys,
659                                                 lmm_constraint_t cnst)
660 {
661   return xbt_swag_getNext(cnst, (sys->active_constraint_set).offset);
662 }