Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
stupid me!
[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     var->value = 0.0;
447   }
448
449   /* 
450    * Compute Usage and store the variables that reach the maximum.
451    */
452   cnst_list = &(sys->active_constraint_set);
453   DEBUG1("Active constraints : %d", xbt_swag_size(cnst_list));
454   xbt_swag_foreach(cnst, cnst_list) {
455     /* INIT */
456     cnst->remaining = cnst->bound;
457     cnst->usage = 0;
458     elem_list = &(cnst->element_set);
459     cnst->usage = 0.0;
460     xbt_swag_foreach(elem, elem_list) {
461       if (elem->variable->weight <= 0)
462         break;
463       if ((elem->value > 0)) {
464         if (cnst->shared)
465           cnst->usage += elem->value / elem->variable->weight;
466         else if (cnst->usage < elem->value / elem->variable->weight)
467           cnst->usage = elem->value / elem->variable->weight;
468         DEBUG2("Constraint Usage %p : %f", cnst, cnst->usage);
469         make_elem_active(elem);
470       }
471     }
472     /* Saturated constraints update */
473     saturated_constraint_set_update(sys, cnst, &min_usage);
474   }
475   saturated_variable_set_update(sys);
476
477   /* Saturated variables update */
478
479   do {
480     /* Fix the variables that have to be */
481     var_list = &(sys->saturated_variable_set);
482
483     xbt_swag_foreach(var, var_list) {
484       /* First check if some of these variables have reach their upper
485          bound and update min_usage accordingly. */
486       DEBUG5
487           ("var=%p, var->bound=%f, var->weight=%f, min_usage=%f, var->bound*var->weight=%f",
488            var, var->bound, var->weight, min_usage,
489            var->bound * var->weight);
490       if ((var->bound > 0) && (var->bound * var->weight < min_usage)) {
491         min_usage = var->bound * var->weight;
492         DEBUG1("Updated min_usage=%f", min_usage);
493       }
494     }
495
496
497     while ((var = xbt_swag_getFirst(var_list))) {
498       int i;
499
500       var->value = min_usage / var->weight;
501       DEBUG5("Min usage: %f, Var(%p)->weight: %f, Var(%p)->value: %f ",
502              min_usage, var, var->weight, var, var->value);
503
504
505       /* Update usage */
506
507       for (i = 0; i < var->cnsts_number; i++) {
508         elem = &var->cnsts[i];
509         cnst = elem->constraint;
510         if (cnst->shared) {
511           double_update(&(cnst->remaining), elem->value * var->value);
512           double_update(&(cnst->usage), elem->value / var->weight);
513           make_elem_inactive(elem);
514         } else {                /* FIXME one day: We recompute usage.... :( */
515           cnst->usage = 0.0;
516           make_elem_inactive(elem);
517           xbt_swag_foreach(elem, elem_list) {
518             if (elem->variable->weight <= 0)
519               break;
520             if (elem->variable->value > 0)
521               break;
522             if ((elem->value > 0)) {
523               if (cnst->usage < elem->value / elem->variable->weight)
524                 cnst->usage = elem->value / elem->variable->weight;
525               DEBUG2("Constraint Usage %p : %f", cnst, cnst->usage);
526               make_elem_active(elem);
527             }
528           }
529         }
530       }
531       xbt_swag_remove(var, var_list);
532     }
533
534     /* Find out which variables reach the maximum */
535     cnst_list = &(sys->active_constraint_set);
536     min_usage = -1;
537     xbt_swag_foreach(cnst, cnst_list) {
538       saturated_constraint_set_update(sys, cnst, &min_usage);
539     }
540     saturated_variable_set_update(sys);
541
542   } while (xbt_swag_size(&(sys->saturated_variable_set)));
543
544   sys->modified = 0;
545   if (XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug)) {
546     lmm_print(sys);
547   }
548 }
549
550 /* Not a O(1) function */
551
552 void lmm_update(lmm_system_t sys, lmm_constraint_t cnst,
553                 lmm_variable_t var, double value)
554 {
555   int i;
556
557   sys->modified = 1;
558   for (i = 0; i < var->cnsts_number; i++)
559     if (var->cnsts[i].constraint == cnst) {
560       var->cnsts[i].value = value;
561       return;
562     }
563 }
564
565 /** \brief Attribute the value bound to var->bound.
566  * 
567  *  \param sys the lmm_system_t
568  *  \param var the lmm_variable_t
569  *  \param bound the new bound to associate with var
570  * 
571  *  Makes var->bound equal to bound. Whenever this function is called 
572  *  a change is  signed in the system. To
573  *  avoid false system changing detection it is a good idea to test 
574  *  (bound != 0) before calling it.
575  *
576  */
577 void lmm_update_variable_bound(lmm_system_t sys, lmm_variable_t var,
578                                double bound)
579 {
580   sys->modified = 1;
581   var->bound = bound;
582 }
583
584 /** \brief Add the value delta to var->df (the sum of latencies).
585  * 
586  *  \param sys the lmm_system_t associated
587  *  \param var the lmm_variable_t which need to updated
588  *  \param delta the variation of the latency
589  * 
590  *  Add the value delta to var->df (the sum of latencys associated to the
591  *  flow). Whenever this function is called a change is  signed in the system. To
592  *  avoid false system changing detection it is a good idea to test 
593  *  (delta != 0) before calling it.
594  *
595  */
596 void lmm_update_variable_latency(lmm_system_t sys, lmm_variable_t var,
597                                  double delta)
598 {
599   sys->modified = 1;
600   var->df += delta;
601 }
602
603 void lmm_update_variable_weight(lmm_system_t sys, lmm_variable_t var,
604                                 double weight)
605 {
606   int i;
607   lmm_element_t elem;
608
609   XBT_IN3("(sys=%p, var=%p, weight=%f)", sys, var, weight);
610   sys->modified = 1;
611   var->weight = weight;
612   xbt_swag_remove(var, &(sys->variable_set));
613   if (weight)
614     xbt_swag_insert_at_head(var, &(sys->variable_set));
615   else
616     xbt_swag_insert_at_tail(var, &(sys->variable_set));
617
618   for (i = 0; i < var->cnsts_number; i++) {
619     elem = &var->cnsts[i];
620     xbt_swag_remove(elem, &(elem->constraint->element_set));
621     if (weight)
622       xbt_swag_insert_at_head(elem, &(elem->constraint->element_set));
623     else
624       xbt_swag_insert_at_tail(elem, &(elem->constraint->element_set));
625   }
626   XBT_OUT;
627 }
628
629 double lmm_get_variable_weight(lmm_variable_t var)
630 {
631   return var->weight;
632 }
633
634 void lmm_update_constraint_bound(lmm_system_t sys, lmm_constraint_t cnst,
635                                  double bound)
636 {
637   sys->modified = 1;
638   cnst->bound = bound;
639 }
640
641 int lmm_constraint_used(lmm_system_t sys, lmm_constraint_t cnst)
642 {
643   return xbt_swag_belongs(cnst, &(sys->active_constraint_set));
644 }
645
646 lmm_constraint_t lmm_get_first_active_constraint(lmm_system_t sys)
647 {
648   return xbt_swag_getFirst(&(sys->active_constraint_set));
649 }
650
651 lmm_constraint_t lmm_get_next_active_constraint(lmm_system_t sys,
652                                                 lmm_constraint_t cnst)
653 {
654   return xbt_swag_getNext(cnst, (sys->active_constraint_set).offset);
655 }