Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of scm.gforge.inria.fr:/gitroot/simgrid/simgrid
[simgrid.git] / src / surf / network_cm02.cpp
1 /* Copyright (c) 2013-2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
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. */
6
7 #include <algorithm>
8
9 #include "network_cm02.hpp"
10 #include "maxmin_private.hpp"
11 #include "simgrid/sg_config.h"
12
13 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(surf_network);
14
15 double sg_sender_gap = 0.0;
16 double sg_latency_factor = 1.0; /* default value; can be set by model or from command line */
17 double sg_bandwidth_factor = 1.0;       /* default value; can be set by model or from command line */
18 double sg_weight_S_parameter = 0.0;     /* default value; can be set by model or from command line */
19
20 double sg_tcp_gamma = 0.0;
21 int sg_network_crosstraffic = 0;
22
23 /************************************************************************/
24 /* New model based on optimizations discussed during Pedro Velho's thesis*/
25 /************************************************************************/
26 /* @techreport{VELHO:2011:HAL-00646896:1, */
27 /*      url = {http://hal.inria.fr/hal-00646896/en/}, */
28 /*      title = {{Flow-level network models: have we reached the limits?}}, */
29 /*      author = {Velho, Pedro and Schnorr, Lucas and Casanova, Henri and Legrand, Arnaud}, */
30 /*      type = {Rapport de recherche}, */
31 /*      institution = {INRIA}, */
32 /*      number = {RR-7821}, */
33 /*      year = {2011}, */
34 /*      month = Nov, */
35 /*      pdf = {http://hal.inria.fr/hal-00646896/PDF/rr-validity.pdf}, */
36 /*  } */
37 void surf_network_model_init_LegrandVelho(void)
38 {
39   if (surf_network_model)
40     return;
41
42   simgrid::surf::on_link.connect(netlink_parse_init);
43   surf_network_model = new simgrid::surf::NetworkCm02Model();
44   xbt_dynar_push(all_existing_models, &surf_network_model);
45
46   xbt_cfg_setdefault_double(_sg_cfg_set, "network/latency_factor",      13.01);
47   xbt_cfg_setdefault_double(_sg_cfg_set, "network/bandwidth_factor",     0.97);
48   xbt_cfg_setdefault_double(_sg_cfg_set, "network/weight_S",         20537);
49 }
50
51 /***************************************************************************/
52 /* The nice TCP sharing model designed by Loris Marchal and Henri Casanova */
53 /***************************************************************************/
54 /* @TechReport{      rr-lip2002-40, */
55 /*   author        = {Henri Casanova and Loris Marchal}, */
56 /*   institution   = {LIP}, */
57 /*   title         = {A Network Model for Simulation of Grid Application}, */
58 /*   number        = {2002-40}, */
59 /*   month         = {oct}, */
60 /*   year          = {2002} */
61 /* } */
62 void surf_network_model_init_CM02(void)
63 {
64
65   if (surf_network_model)
66     return;
67
68   simgrid::surf::on_link.connect(netlink_parse_init);
69   surf_network_model = new simgrid::surf::NetworkCm02Model();
70   xbt_dynar_push(all_existing_models, &surf_network_model);
71
72   xbt_cfg_setdefault_double(_sg_cfg_set, "network/latency_factor",   1.0);
73   xbt_cfg_setdefault_double(_sg_cfg_set, "network/bandwidth_factor", 1.0);
74   xbt_cfg_setdefault_double(_sg_cfg_set, "network/weight_S",         0.0);
75 }
76
77 /***************************************************************************/
78 /* The models from Steven H. Low                                           */
79 /***************************************************************************/
80 /* @article{Low03,                                                         */
81 /*   author={Steven H. Low},                                               */
82 /*   title={A Duality Model of {TCP} and Queue Management Algorithms},     */
83 /*   year={2003},                                                          */
84 /*   journal={{IEEE/ACM} Transactions on Networking},                      */
85 /*    volume={11}, number={4},                                             */
86 /*  }                                                                      */
87 void surf_network_model_init_Reno(void)
88 {
89   if (surf_network_model)
90     return;
91
92   simgrid::surf::on_link.connect(netlink_parse_init);
93   surf_network_model = new simgrid::surf::NetworkCm02Model();
94   xbt_dynar_push(all_existing_models, &surf_network_model);
95
96   lmm_set_default_protocol_function(func_reno_f, func_reno_fp, func_reno_fpi);
97   surf_network_model->f_networkSolve = lagrange_solve;
98
99   xbt_cfg_setdefault_double(_sg_cfg_set, "network/latency_factor",     10.4);
100   xbt_cfg_setdefault_double(_sg_cfg_set, "network/bandwidth_factor",    0.92);
101   xbt_cfg_setdefault_double(_sg_cfg_set, "network/weight_S",         8775);
102 }
103
104
105 void surf_network_model_init_Reno2(void)
106 {
107   if (surf_network_model)
108     return;
109
110   simgrid::surf::on_link.connect(netlink_parse_init);
111   surf_network_model = new simgrid::surf::NetworkCm02Model();
112   xbt_dynar_push(all_existing_models, &surf_network_model);
113
114   lmm_set_default_protocol_function(func_reno2_f, func_reno2_fp, func_reno2_fpi);
115   surf_network_model->f_networkSolve = lagrange_solve;
116
117   xbt_cfg_setdefault_double(_sg_cfg_set, "network/latency_factor",    10.4);
118   xbt_cfg_setdefault_double(_sg_cfg_set, "network/bandwidth_factor",   0.92);
119   xbt_cfg_setdefault_double(_sg_cfg_set, "network/weight_S",        8775);
120 }
121
122 void surf_network_model_init_Vegas(void)
123 {
124   if (surf_network_model)
125     return;
126
127   simgrid::surf::on_link.connect(netlink_parse_init);
128   surf_network_model = new simgrid::surf::NetworkCm02Model();
129   xbt_dynar_push(all_existing_models, &surf_network_model);
130
131   lmm_set_default_protocol_function(func_vegas_f, func_vegas_fp, func_vegas_fpi);
132   surf_network_model->f_networkSolve = lagrange_solve;
133
134   xbt_cfg_setdefault_double(_sg_cfg_set, "network/latency_factor",    10.4);
135   xbt_cfg_setdefault_double(_sg_cfg_set, "network/bandwidth_factor",   0.92);
136   xbt_cfg_setdefault_double(_sg_cfg_set, "network/weight_S",        8775);
137 }
138
139 namespace simgrid {
140 namespace surf {
141
142 NetworkCm02Model::NetworkCm02Model()
143   :NetworkModel()
144 {
145   char *optim = xbt_cfg_get_string(_sg_cfg_set, "network/optim");
146   int select = xbt_cfg_get_boolean(_sg_cfg_set, "network/maxmin_selective_update");
147
148   if (!strcmp(optim, "Full")) {
149     p_updateMechanism = UM_FULL;
150     m_selectiveUpdate = select;
151   } else if (!strcmp(optim, "Lazy")) {
152     p_updateMechanism = UM_LAZY;
153     m_selectiveUpdate = 1;
154     xbt_assert((select == 1) || (xbt_cfg_is_default_value(_sg_cfg_set, "network/maxmin_selective_update")),
155                "Disabling selective update while using the lazy update mechanism is dumb!");
156   } else {
157     xbt_die("Unsupported optimization (%s) for this model", optim);
158   }
159
160   if (!p_maxminSystem)
161     p_maxminSystem = lmm_system_new(m_selectiveUpdate);
162
163   routing_model_create(createLink("__loopback__",
164                                 498000000, NULL, 0.000015, NULL,
165                                 1 /*SURF_RESOURCE_ON*/, NULL,
166                                 SURF_LINK_FATPIPE, NULL));
167
168   if (p_updateMechanism == UM_LAZY) {
169   p_actionHeap = xbt_heap_new(8, NULL);
170   xbt_heap_set_update_callback(p_actionHeap, surf_action_lmm_update_index_heap);
171   p_modifiedSet = new ActionLmmList();
172   p_maxminSystem->keep_track = p_modifiedSet;
173   }
174 }
175
176 Link* NetworkCm02Model::createLink(const char *name,
177     double bw_initial, tmgr_trace_t bw_trace,
178     double lat_initial, tmgr_trace_t lat_trace,
179     int initiallyOn, tmgr_trace_t state_trace,
180     e_surf_link_sharing_policy_t policy, xbt_dict_t properties)
181 {
182   xbt_assert(NULL == Link::byName(name),
183              "Link '%s' declared several times in the platform",
184              name);
185
186   Link* link = new NetworkCm02Link(this, name, properties, p_maxminSystem, sg_bandwidth_factor * bw_initial,
187                      initiallyOn, state_trace, bw_initial, bw_trace, lat_initial, lat_trace, policy);
188   Link::onCreation(link);
189   return link;
190 }
191
192 void NetworkCm02Model::updateActionsStateLazy(double now, double /*delta*/)
193 {
194   NetworkCm02Action *action;
195   while ((xbt_heap_size(p_actionHeap) > 0)
196          && (double_equals(xbt_heap_maxkey(p_actionHeap), now, sg_surf_precision))) {
197     action = static_cast<NetworkCm02Action*> (xbt_heap_pop(p_actionHeap));
198     XBT_DEBUG("Something happened to action %p", action);
199     if (TRACE_is_enabled()) {
200       int n = lmm_get_number_of_cnst_from_var(p_maxminSystem, action->getVariable());
201
202       for (int i = 0; i < n; i++){
203         lmm_constraint_t constraint = lmm_get_cnst_from_var(p_maxminSystem, action->getVariable(), i);
204         NetworkCm02Link *link = static_cast<NetworkCm02Link*>(lmm_constraint_id(constraint));
205         TRACE_surf_link_set_utilization(link->getName(),
206                                         action->getCategory(),
207                                         (lmm_variable_getvalue(action->getVariable())*
208                                             lmm_get_cnst_weight_from_var(p_maxminSystem,
209                                                 action->getVariable(),
210                                                 i)),
211                                         action->getLastUpdate(),
212                                         now - action->getLastUpdate());
213       }
214     }
215
216     // if I am wearing a latency hat
217     if (action->getHat() == LATENCY) {
218       XBT_DEBUG("Latency paid for action %p. Activating", action);
219       lmm_update_variable_weight(p_maxminSystem, action->getVariable(), action->m_weight);
220       action->heapRemove(p_actionHeap);
221       action->refreshLastUpdate();
222
223         // if I am wearing a max_duration or normal hat
224     } else if (action->getHat() == MAX_DURATION ||
225         action->getHat() == NORMAL) {
226         // no need to communicate anymore
227         // assume that flows that reached max_duration have remaining of 0
228       XBT_DEBUG("Action %p finished", action);
229       action->setRemains(0);
230       action->finish();
231       action->setState(SURF_ACTION_DONE);
232       action->heapRemove(p_actionHeap);
233
234       action->gapRemove();
235     }
236   }
237   return;
238 }
239
240
241 void NetworkCm02Model::updateActionsStateFull(double now, double delta)
242 {
243   NetworkCm02Action *action;
244   ActionList *running_actions = getRunningActionSet();
245
246   for(ActionList::iterator it(running_actions->begin()), itNext=it, itend(running_actions->end())
247      ; it != itend ; it=itNext) {
248   ++itNext;
249
250     action = static_cast<NetworkCm02Action*> (&*it);
251     XBT_DEBUG("Something happened to action %p", action);
252       double deltap = delta;
253       if (action->m_latency > 0) {
254         if (action->m_latency > deltap) {
255           double_update(&(action->m_latency), deltap, sg_surf_precision);
256           deltap = 0.0;
257         } else {
258           double_update(&(deltap), action->m_latency, sg_surf_precision);
259           action->m_latency = 0.0;
260         }
261         if (action->m_latency == 0.0 && !(action->isSuspended()))
262           lmm_update_variable_weight(p_maxminSystem, action->getVariable(),
263               action->m_weight);
264       }
265       if (TRACE_is_enabled()) {
266         int n = lmm_get_number_of_cnst_from_var(p_maxminSystem, action->getVariable());
267         for (int i = 0; i < n; i++){
268           lmm_constraint_t constraint = lmm_get_cnst_from_var(p_maxminSystem, action->getVariable(), i);
269
270           NetworkCm02Link* link = static_cast<NetworkCm02Link*>(lmm_constraint_id(constraint));
271           TRACE_surf_link_set_utilization(link->getName(),
272                                         action->getCategory(),
273                                         (lmm_variable_getvalue(action->getVariable())*
274                                             lmm_get_cnst_weight_from_var(p_maxminSystem,
275                                                 action->getVariable(),
276                                                 i)),
277                                         action->getLastUpdate(),
278                                         now - action->getLastUpdate());
279         }
280       }
281       if (!lmm_get_number_of_cnst_from_var (p_maxminSystem, action->getVariable())) {
282         /* There is actually no link used, hence an infinite bandwidth.
283          * This happens often when using models like vivaldi.
284          * In such case, just make sure that the action completes immediately.
285          */
286         action->updateRemains(action->getRemains());
287       }
288     action->updateRemains(lmm_variable_getvalue(action->getVariable()) * delta);
289                   
290     if (action->getMaxDuration() != NO_MAX_DURATION)
291       action->updateMaxDuration(delta);
292       
293     if ((action->getRemains() <= 0) &&
294         (lmm_get_variable_weight(action->getVariable()) > 0)) {
295       action->finish();
296       action->setState(SURF_ACTION_DONE);
297       action->gapRemove();
298     } else if (((action->getMaxDuration() != NO_MAX_DURATION)
299         && (action->getMaxDuration() <= 0))) {
300       action->finish();
301       action->setState(SURF_ACTION_DONE);
302       action->gapRemove();
303     }
304   }
305 }
306
307 Action *NetworkCm02Model::communicate(NetCard *src, NetCard *dst,
308                                                 double size, double rate)
309 {
310   unsigned int i;
311   void *_link;
312   NetworkCm02Link *link;
313   int failed = 0;
314   NetworkCm02Action *action = NULL;
315   double bandwidth_bound;
316   double latency = 0.0;
317   xbt_dynar_t back_route = NULL;
318   int constraints_per_variable = 0;
319
320   xbt_dynar_t route = xbt_dynar_new(sizeof(NetCard*), NULL);
321
322   XBT_IN("(%s,%s,%g,%g)", src->name(), dst->name(), size, rate);
323
324   routing_platf->getRouteAndLatency(src, dst, &route, &latency);
325   xbt_assert(!xbt_dynar_is_empty(route) || latency,
326              "You're trying to send data from %s to %s but there is no connecting path between these two hosts.",
327              src->name(), dst->name());
328
329   xbt_dynar_foreach(route, i, _link) {
330   link = static_cast<NetworkCm02Link*>(_link);
331     if (link->isOff()) {
332       failed = 1;
333       break;
334     }
335   }
336   if (sg_network_crosstraffic == 1) {
337     routing_platf->getRouteAndLatency(dst, src, &back_route, NULL);
338     xbt_dynar_foreach(back_route, i, _link) {
339       link = static_cast<NetworkCm02Link*>(_link);
340       if (link->isOff()) {
341         failed = 1;
342         break;
343       }
344     }
345   }
346
347   action = new NetworkCm02Action(this, size, failed);
348
349 #ifdef HAVE_LATENCY_BOUND_TRACKING
350   action->m_latencyLimited = 0;
351 #endif
352   action->m_weight = action->m_latency = latency;
353
354   action->m_rate = rate;
355   if (p_updateMechanism == UM_LAZY) {
356     action->m_indexHeap = -1;
357     action->m_lastUpdate = surf_get_clock();
358   }
359
360   bandwidth_bound = -1.0;
361   if (sg_weight_S_parameter > 0) {
362     xbt_dynar_foreach(route, i, _link) {
363       link = static_cast<NetworkCm02Link*>(_link);
364       action->m_weight += sg_weight_S_parameter / link->getBandwidth();
365     }
366   }
367   xbt_dynar_foreach(route, i, _link) {
368     link = static_cast<NetworkCm02Link*>(_link);
369     double bb = bandwidthFactor(size) * link->getBandwidth();
370     bandwidth_bound =
371         (bandwidth_bound < 0.0) ? bb : std::min(bandwidth_bound, bb);
372   }
373
374   action->m_latCurrent = action->m_latency;
375   action->m_latency *= latencyFactor(size);
376   action->m_rate = bandwidthConstraint(action->m_rate, bandwidth_bound, size);
377   if (m_haveGap) {
378     xbt_assert(!xbt_dynar_is_empty(route),
379                "Using a model with a gap (e.g., SMPI) with a platform without links (e.g. vivaldi)!!!");
380
381     link = *static_cast<NetworkCm02Link **>(xbt_dynar_get_ptr(route, 0));
382     gapAppend(size, link, action);
383     XBT_DEBUG("Comm %p: %s -> %s gap=%f (lat=%f)",
384               action, src->name(), dst->name(), action->m_senderGap,
385               action->m_latency);
386   }
387
388   constraints_per_variable = xbt_dynar_length(route);
389   if (back_route != NULL)
390     constraints_per_variable += xbt_dynar_length(back_route);
391
392   if (action->m_latency > 0) {
393     action->p_variable = lmm_variable_new(p_maxminSystem, action, 0.0, -1.0,
394                          constraints_per_variable);
395     if (p_updateMechanism == UM_LAZY) {
396       // add to the heap the event when the latency is payed
397       XBT_DEBUG("Added action (%p) one latency event at date %f", action,
398                 action->m_latency + action->m_lastUpdate);
399       action->heapInsert(p_actionHeap, action->m_latency + action->m_lastUpdate, xbt_dynar_is_empty(route) ? NORMAL : LATENCY);
400     }
401   } else
402     action->p_variable = lmm_variable_new(p_maxminSystem, action, 1.0, -1.0, constraints_per_variable);
403
404   if (action->m_rate < 0) {
405     lmm_update_variable_bound(p_maxminSystem, action->getVariable(), (action->m_latCurrent > 0) ? sg_tcp_gamma / (2.0 * action->m_latCurrent) : -1.0);
406   } else {
407     lmm_update_variable_bound(p_maxminSystem, action->getVariable(), (action->m_latCurrent > 0) ? std::min(action->m_rate, sg_tcp_gamma / (2.0 * action->m_latCurrent)) : action->m_rate);
408   }
409
410   xbt_dynar_foreach(route, i, _link) {
411     link = static_cast<NetworkCm02Link*>(_link);
412     lmm_expand(p_maxminSystem, link->getConstraint(), action->getVariable(), 1.0);
413   }
414
415   if (sg_network_crosstraffic == 1) {
416     XBT_DEBUG("Fullduplex active adding backward flow using 5%%");
417     xbt_dynar_foreach(back_route, i, _link) {
418       link = static_cast<NetworkCm02Link*>(_link);
419       lmm_expand(p_maxminSystem, link->getConstraint(), action->getVariable(), .05);
420     }
421     lmm_variable_concurrency_share_set(action->getVariable(),2);
422   }
423
424   xbt_dynar_free(&route);
425   XBT_OUT();
426
427   networkCommunicateCallbacks(action, src, dst, size, rate);
428   return action;
429 }
430
431 /************
432  * Resource *
433  ************/
434 NetworkCm02Link::NetworkCm02Link(NetworkCm02Model *model, const char *name, xbt_dict_t props,
435     lmm_system_t system,
436     double constraint_value,
437     int initiallyOn, tmgr_trace_t state_trace,
438     double bw_peak, tmgr_trace_t bw_trace,
439     double lat_initial, tmgr_trace_t lat_trace,
440     e_surf_link_sharing_policy_t policy)
441 : Link(model, name, props, lmm_constraint_new(system, this, constraint_value), state_trace)
442 {
443   if (initiallyOn)
444     turnOn();
445   else
446     turnOff();
447
448   m_bandwidth.scale = 1.0;
449   m_bandwidth.peak = bw_peak;
450   if (bw_trace)
451     m_bandwidth.event = future_evt_set->add_trace(bw_trace, 0.0, this);
452   else
453     m_bandwidth.event = NULL;
454
455   m_latency.scale = 1.0;
456   m_latency.peak = lat_initial;
457   if (lat_trace)
458     m_latency.event = future_evt_set->add_trace(lat_trace, 0.0, this);
459
460   if (policy == SURF_LINK_FATPIPE)
461     lmm_constraint_shared(getConstraint());
462 }
463
464
465
466 void NetworkCm02Link::apply_event(tmgr_trace_iterator_t triggered, double value)
467 {
468
469   /* Find out which of my iterators was triggered, and react accordingly */
470   if (triggered == m_bandwidth.event) {
471     updateBandwidth(value);
472     tmgr_trace_event_unref(&m_bandwidth.event);
473
474   } else if (triggered == m_latency.event) {
475     updateLatency(value);
476     tmgr_trace_event_unref(&m_latency.event);
477
478   } else if (triggered == m_stateEvent) {
479     if (value > 0)
480       turnOn();
481     else {
482       lmm_variable_t var = NULL;
483       lmm_element_t elem = NULL;
484       double now = surf_get_clock();
485
486       turnOff();
487       while ((var = lmm_get_var_from_cnst(getModel()->getMaxminSystem(), getConstraint(), &elem))) {
488         Action *action = static_cast<Action*>( lmm_variable_id(var) );
489
490         if (action->getState() == SURF_ACTION_RUNNING ||
491             action->getState() == SURF_ACTION_READY) {
492           action->setFinishTime(now);
493           action->setState(SURF_ACTION_FAILED);
494         }
495       }
496     }
497     tmgr_trace_event_unref(&m_stateEvent);
498   } else {
499     xbt_die("Unknown event!\n");
500   }
501
502   XBT_DEBUG("There was a resource state event, need to update actions related to the constraint (%p)",
503        getConstraint());
504 }
505
506 void NetworkCm02Link::updateBandwidth(double value) {
507
508   m_bandwidth.peak = value;
509
510   lmm_update_constraint_bound(getModel()->getMaxminSystem(), getConstraint(),
511       sg_bandwidth_factor * (m_bandwidth.peak * m_bandwidth.scale));
512   TRACE_surf_link_set_bandwidth(surf_get_clock(), getName(), sg_bandwidth_factor * m_bandwidth.peak * m_bandwidth.scale);
513
514   if (sg_weight_S_parameter > 0) {
515     double delta = sg_weight_S_parameter / value - sg_weight_S_parameter / (m_bandwidth.peak * m_bandwidth.scale);
516
517     lmm_variable_t var;
518     lmm_element_t elem = NULL, nextelem = NULL;
519     int numelem = 0;
520     while ((var = lmm_get_var_from_cnst_safe(getModel()->getMaxminSystem(), getConstraint(), &elem, &nextelem, &numelem))) {
521       NetworkCm02Action *action = (NetworkCm02Action*) lmm_variable_id(var);
522       action->m_weight += delta;
523       if (!action->isSuspended())
524         lmm_update_variable_weight(getModel()->getMaxminSystem(), action->getVariable(), action->m_weight);
525     }
526   }
527 }
528
529 void NetworkCm02Link::updateLatency(double value){
530   double delta = value - m_latency.peak;
531   lmm_variable_t var = NULL;
532   lmm_element_t elem = NULL;
533   lmm_element_t nextelem = NULL;
534   int numelem = 0;
535
536   m_latency.peak = value;
537
538   while ((var = lmm_get_var_from_cnst_safe(getModel()->getMaxminSystem(), getConstraint(), &elem, &nextelem, &numelem))) {
539     NetworkCm02Action *action = (NetworkCm02Action*) lmm_variable_id(var);
540     action->m_latCurrent += delta;
541     action->m_weight += delta;
542     if (action->m_rate < 0)
543       lmm_update_variable_bound(getModel()->getMaxminSystem(), action->getVariable(), sg_tcp_gamma / (2.0 * action->m_latCurrent));
544     else {
545       lmm_update_variable_bound(getModel()->getMaxminSystem(), action->getVariable(),
546                                 std::min(action->m_rate, sg_tcp_gamma / (2.0 * action->m_latCurrent)));
547
548       if (action->m_rate < sg_tcp_gamma / (2.0 * action->m_latCurrent)) {
549         XBT_INFO("Flow is limited BYBANDWIDTH");
550       } else {
551         XBT_INFO("Flow is limited BYLATENCY, latency of flow is %f", action->m_latCurrent);
552       }
553     }
554     if (!action->isSuspended())
555       lmm_update_variable_weight(getModel()->getMaxminSystem(), action->getVariable(), action->m_weight);
556   }
557 }
558
559 /**********
560  * Action *
561  **********/
562 void NetworkCm02Action::updateRemainingLazy(double now)
563 {
564   double delta = 0.0;
565
566   if (m_suspended != 0)
567     return;
568
569   delta = now - m_lastUpdate;
570
571   if (m_remains > 0) {
572     XBT_DEBUG("Updating action(%p): remains was %f, last_update was: %f", this, m_remains, m_lastUpdate);
573     double_update(&(m_remains), m_lastValue * delta, sg_maxmin_precision*sg_surf_precision);
574
575     XBT_DEBUG("Updating action(%p): remains is now %f", this, m_remains);
576   }
577
578   if (m_maxDuration != NO_MAX_DURATION)
579     double_update(&m_maxDuration, delta, sg_surf_precision);
580
581   if (m_remains <= 0 &&
582       (lmm_get_variable_weight(getVariable()) > 0)) {
583     finish();
584     setState(SURF_ACTION_DONE);
585
586     heapRemove(getModel()->getActionHeap());
587   } else if (((m_maxDuration != NO_MAX_DURATION)
588       && (m_maxDuration <= 0))) {
589     finish();
590     setState(SURF_ACTION_DONE);
591     heapRemove(getModel()->getActionHeap());
592   }
593
594   m_lastUpdate = now;
595   m_lastValue = lmm_variable_getvalue(getVariable());
596 }
597
598 }
599 }