Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
d5b631951077acab0ca7ec8a59f3dfc2a89669ab
[simgrid.git] / src / surf / surf_interface.cpp
1 /* Copyright (c) 2004-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 "surf_interface.hpp"
8 #include "cpu_interface.hpp"
9 #include "mc/mc.h"
10 #include "network_interface.hpp"
11 #include "simgrid/s4u/engine.hpp"
12 #include "simgrid/sg_config.h"
13 #include "src/instr/instr_private.h" // TRACE_is_enabled(). FIXME: remove by subscribing tracing to the surf signals
14 #include "src/internal_config.h"
15 #include "src/simix/smx_host_private.h"
16 #include "src/surf/HostImpl.hpp"
17 #include "surf_private.h"
18 #include "surf_routing.hpp"
19 #include <vector>
20
21 XBT_LOG_NEW_CATEGORY(surf, "All SURF categories");
22 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_kernel, surf, "Logging specific to SURF (kernel)");
23
24 /*********
25  * Utils *
26  *********/
27
28 /* model_list_invoke contains only surf_host and surf_vm.
29  * The callback functions of cpu_model and network_model will be called from those of these host models. */
30 std::vector<surf_model_t> * all_existing_models = nullptr; /* to destroy models correctly */
31 xbt_dynar_t model_list_invoke = nullptr;  /* to invoke callbacks */
32
33 simgrid::trace_mgr::future_evt_set *future_evt_set = nullptr;
34 xbt_dynar_t surf_path = nullptr;
35 std::vector<simgrid::s4u::Host*> host_that_restart;
36 xbt_dict_t watched_hosts_lib;
37
38 namespace simgrid {
39 namespace surf {
40
41 simgrid::xbt::signal<void(void)> surfExitCallbacks;
42
43 }
44 }
45
46 #include <simgrid/plugins/energy.h> // FIXME: this plugin should not be linked to the core
47
48 s_surf_model_description_t surf_plugin_description[] = {
49     {"Energy", "Cpu energy consumption.", &sg_energy_plugin_init},
50      {nullptr, nullptr,  nullptr}      /* this array must be nullptr terminated */
51 };
52
53 /* Don't forget to update the option description in smx_config when you change this */
54 s_surf_model_description_t surf_network_model_description[] = {
55   {"LV08", "Realistic network analytic model (slow-start modeled by multiplying latency by 10.4, bandwidth by .92; bottleneck sharing uses a payload of S=8775 for evaluating RTT). ",
56    &surf_network_model_init_LegrandVelho},
57   {"Constant",
58    "Simplistic network model where all communication take a constant time (one second). This model provides the lowest realism, but is (marginally) faster.",
59    &surf_network_model_init_Constant},
60   {"SMPI", "Realistic network model specifically tailored for HPC settings (accurate modeling of slow start with correction factors on three intervals: < 1KiB, < 64 KiB, >= 64 KiB)",
61    &surf_network_model_init_SMPI},
62   {"IB", "Realistic network model specifically tailored for HPC settings, with Infiniband contention model",
63    &surf_network_model_init_IB},
64   {"CM02", "Legacy network analytic model (Very similar to LV08, but without corrective factors. The timings of small messages are thus poorly modeled).",
65    &surf_network_model_init_CM02},
66   {"NS3", "Network pseudo-model using the NS3 tcp model instead of an analytic model", &surf_network_model_init_NS3},
67   {"Reno",  "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
68    &surf_network_model_init_Reno},
69   {"Reno2", "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
70    &surf_network_model_init_Reno2},
71   {"Vegas", "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
72    &surf_network_model_init_Vegas},
73   {nullptr, nullptr, nullptr}      /* this array must be nullptr terminated */
74 };
75
76 #if ! HAVE_SMPI
77 void surf_network_model_init_SMPI() {
78   xbt_die("Please activate SMPI support in cmake to use the SMPI network model.");
79 }
80 void surf_network_model_init_IB() {
81   xbt_die("Please activate SMPI support in cmake to use the IB network model.");
82 }
83 #endif
84 #if !HAVE_NS3
85 void surf_network_model_init_NS3() {
86   xbt_die("Please activate NS3 support in cmake and install the dependencies to use the NS3 network model.");
87 }
88 #endif
89
90 s_surf_model_description_t surf_cpu_model_description[] = {
91   {"Cas01", "Simplistic CPU model (time=size/power).", &surf_cpu_model_init_Cas01},
92   {nullptr, nullptr,  nullptr}      /* this array must be nullptr terminated */
93 };
94
95 s_surf_model_description_t surf_host_model_description[] = {
96   {"default",   "Default host model. Currently, CPU:Cas01 and network:LV08 (with cross traffic enabled)", &surf_host_model_init_current_default},
97   {"compound",  "Host model that is automatically chosen if you change the network and CPU models", &surf_host_model_init_compound},
98   {"ptask_L07", "Host model somehow similar to Cas01+CM02 but allowing parallel tasks", &surf_host_model_init_ptask_L07},
99   {nullptr, nullptr, nullptr}      /* this array must be nullptr terminated */
100 };
101
102 s_surf_model_description_t surf_vm_model_description[] = {
103   {"default", "Default vm model.", &surf_vm_model_init_HL13},
104   {nullptr, nullptr, nullptr}      /* this array must be nullptr terminated */
105 };
106
107 s_surf_model_description_t surf_optimization_mode_description[] = {
108   {"Lazy", "Lazy action management (partial invalidation in lmm + heap in action remaining).", nullptr},
109   {"TI",   "Trace integration. Highly optimized mode when using availability traces (only available for the Cas01 CPU model for now).", nullptr},
110   {"Full", "Full update of remaining and variables. Slow but may be useful when debugging.", nullptr},
111   {nullptr, nullptr, nullptr}      /* this array must be nullptr terminated */
112 };
113
114 s_surf_model_description_t surf_storage_model_description[] = {
115   {"default", "Simplistic storage model.", &surf_storage_model_init_default},
116   {nullptr, nullptr,  nullptr}      /* this array must be nullptr terminated */
117 };
118
119 #if HAVE_THREAD_CONTEXTS
120 static xbt_parmap_t surf_parmap = nullptr; /* parallel map on models */
121 #endif
122
123 double NOW = 0;
124
125 double surf_get_clock()
126 {
127   return NOW;
128 }
129
130 #ifdef _WIN32
131 # define FILE_DELIM "\\"
132 #else
133 # define FILE_DELIM "/"         /* FIXME: move to better location */
134 #endif
135
136 FILE *surf_fopen(const char *name, const char *mode)
137 {
138   unsigned int cpt;
139   char *path_elm = nullptr;
140   char *buff;
141   FILE *file = nullptr;
142
143   xbt_assert(name);
144
145   if (__surf_is_absolute_file_path(name))       /* don't mess with absolute file names */
146     return fopen(name, mode);
147
148   /* search relative files in the path */
149   xbt_dynar_foreach(surf_path, cpt, path_elm) {
150     buff = bprintf("%s" FILE_DELIM "%s", path_elm, name);
151     file = fopen(buff, mode);
152     free(buff);
153
154     if (file)
155       return file;
156   }
157   return nullptr;
158 }
159
160 #ifdef _WIN32
161 #include <windows.h>
162 #define MAX_DRIVE 26
163 static const char *disk_drives_letter_table[MAX_DRIVE] = {
164   "A:\\","B:\\","C:\\","D:\\","E:\\","F:\\","G:\\","H:\\","I:\\","J:\\","K:\\","L:\\","M:\\",
165   "N:\\","O:\\","P:\\","Q:\\","R:\\","S:\\","T:\\","U:\\","V:\\","W:\\","X:\\","Y:\\","Z:\\"
166 };
167 #endif
168
169 /*
170  * Returns the initial path. On Windows the initial path is
171  * the current directory for the current process in the other
172  * case the function returns "./" that represents the current
173  * directory on Unix/Linux platforms.
174  */
175
176 const char *__surf_get_initial_path()
177 {
178
179 #ifdef _WIN32
180   unsigned i;
181   char current_directory[MAX_PATH + 1] = { 0 };
182   unsigned int len = GetCurrentDirectory(MAX_PATH + 1, current_directory);
183   char root[4] = { 0 };
184
185   if (!len)
186     return nullptr;
187
188   strncpy(root, current_directory, 3);
189
190   for (i = 0; i < MAX_DRIVE; i++) {
191     if (toupper(root[0]) == disk_drives_letter_table[i][0])
192       return disk_drives_letter_table[i];
193   }
194
195   return nullptr;
196 #else
197   return "./";
198 #endif
199 }
200
201 /* The __surf_is_absolute_file_path() returns 1 if
202  * file_path is a absolute file path, in the other
203  * case the function returns 0.
204  */
205 int __surf_is_absolute_file_path(const char *file_path)
206 {
207 #ifdef _WIN32
208   WIN32_FIND_DATA wfd = { 0 };
209   HANDLE hFile = FindFirstFile(file_path, &wfd);
210
211   if (INVALID_HANDLE_VALUE == hFile)
212     return 0;
213
214   FindClose(hFile);
215   return 1;
216 #else
217   return (file_path[0] == '/');
218 #endif
219 }
220
221 /** Displays the long description of all registered models, and quit */
222 void model_help(const char *category, s_surf_model_description_t * table)
223 {
224   printf("Long description of the %s models accepted by this simulator:\n", category);
225   for (int i = 0; table[i].name; i++)
226     printf("  %s: %s\n", table[i].name, table[i].description);
227 }
228
229 int find_model_description(s_surf_model_description_t * table,
230                            const char *name)
231 {
232   int i;
233   char *name_list = nullptr;
234
235   for (i = 0; table[i].name; i++)
236     if (!strcmp(name, table[i].name)) {
237       return i;
238     }
239   if (!table[0].name)
240     xbt_die("No model is valid! This is a bug.");
241   name_list = xbt_strdup(table[0].name);
242   for (i = 1; table[i].name; i++) {
243     name_list = (char *) xbt_realloc(name_list, strlen(name_list) + strlen(table[i].name) + 3);
244     strncat(name_list, ", ", 2);
245     strncat(name_list, table[i].name, strlen(table[i].name));
246   }
247   xbt_die("Model '%s' is invalid! Valid models are: %s.", name, name_list);
248   return -1;
249 }
250
251 static inline void surf_storage_free(void *r)
252 {
253   delete static_cast<simgrid::surf::Storage*>(r);
254 }
255
256 void sg_version_check(int lib_version_major,int lib_version_minor,int lib_version_patch) {
257     if ((lib_version_major != SIMGRID_VERSION_MAJOR) || (lib_version_minor != SIMGRID_VERSION_MINOR)) {
258       fprintf(stderr,
259           "FATAL ERROR: Your program was compiled with SimGrid version %d.%d.%d, "
260           "and then linked against SimGrid %d.%d.%d. Please fix this.\n",
261           lib_version_major,lib_version_minor,lib_version_patch,
262           SIMGRID_VERSION_MAJOR,SIMGRID_VERSION_MINOR,SIMGRID_VERSION_PATCH);
263       abort();
264     }
265     if (lib_version_patch != SIMGRID_VERSION_PATCH) {
266       if(SIMGRID_VERSION_PATCH >= 90 || lib_version_patch >=90){
267         fprintf(stderr,
268         "FATAL ERROR: Your program was compiled with SimGrid version %d.%d.%d, "
269         "and then linked against SimGrid %d.%d.%d. \n"
270         "One of them is a development version, and should not be mixed with the stable release. Please fix this.\n",
271         lib_version_major,lib_version_minor,lib_version_patch,
272         SIMGRID_VERSION_MAJOR,SIMGRID_VERSION_MINOR,SIMGRID_VERSION_PATCH);
273         abort();
274       }
275         fprintf(stderr,
276             "Warning: Your program was compiled with SimGrid version %d.%d.%d, "
277             "and then linked against SimGrid %d.%d.%d. Proceeding anyway.\n",
278             lib_version_major,lib_version_minor,lib_version_patch,
279             SIMGRID_VERSION_MAJOR,SIMGRID_VERSION_MINOR,SIMGRID_VERSION_PATCH);
280     }
281 }
282
283 void sg_version(int *ver_major,int *ver_minor,int *ver_patch) {
284   *ver_major = SIMGRID_VERSION_MAJOR;
285   *ver_minor = SIMGRID_VERSION_MINOR;
286   *ver_patch = SIMGRID_VERSION_PATCH;
287 }
288
289 void surf_init(int *argc, char **argv)
290 {
291   if (USER_HOST_LEVEL != -1) // Already initialized
292     return;
293
294   XBT_DEBUG("Create all Libs");
295   USER_HOST_LEVEL = simgrid::s4u::Host::extension_create(nullptr);
296
297   as_router_lib = xbt_lib_new();
298   storage_lib = xbt_lib_new();
299   storage_type_lib = xbt_lib_new();
300   file_lib = xbt_lib_new();
301   watched_hosts_lib = xbt_dict_new_homogeneous(nullptr);
302
303   XBT_DEBUG("Add routing levels");
304   ROUTING_PROP_ASR_LEVEL = xbt_lib_add_level(as_router_lib, nullptr);
305   ROUTING_ASR_LEVEL = xbt_lib_add_level(as_router_lib, [](void* p) {
306     delete static_cast<simgrid::kernel::routing::NetCard*>(p);
307   });
308
309   XBT_DEBUG("Add SURF levels");
310   SURF_STORAGE_LEVEL = xbt_lib_add_level(storage_lib,surf_storage_free);
311
312   xbt_init(argc, argv);
313   if (!all_existing_models)
314     all_existing_models = new std::vector<simgrid::surf::Model*>();
315   if (!model_list_invoke)
316     model_list_invoke = xbt_dynar_new(sizeof(simgrid::surf::Model*), nullptr);
317   if (!future_evt_set)
318     future_evt_set = new simgrid::trace_mgr::future_evt_set();
319
320   TRACE_add_start_function(TRACE_surf_alloc);
321   TRACE_add_end_function(TRACE_surf_release);
322
323   sg_config_init(argc, argv);
324
325   if (MC_is_active())
326     MC_memory_init();
327 }
328
329 void surf_exit()
330 {
331   TRACE_end();                  /* Just in case it was not called by the upper layer (or there is no upper layer) */
332
333   xbt_dynar_free(&surf_path);
334
335   sg_host_exit();
336   xbt_lib_free(&as_router_lib);
337   xbt_lib_free(&storage_lib);
338   sg_link_exit();
339   xbt_lib_free(&storage_type_lib);
340   xbt_lib_free(&file_lib);
341   xbt_dict_free(&watched_hosts_lib);
342
343   for (auto model : *all_existing_models)
344     delete model;
345   delete all_existing_models;
346   xbt_dynar_free(&model_list_invoke);
347
348   simgrid::surf::surfExitCallbacks();
349
350   if (future_evt_set) {
351     delete future_evt_set;
352     future_evt_set = nullptr;
353   }
354
355 #if HAVE_THREAD_CONTEXTS
356   xbt_parmap_destroy(surf_parmap);
357 #endif
358
359   tmgr_finalize();
360   sg_platf_exit();
361   simgrid::s4u::Engine::shutdown();
362
363   NOW = 0;                      /* Just in case the user plans to restart the simulation afterward */
364 }
365
366 /*********
367  * Model *
368  *********/
369
370 namespace simgrid {
371 namespace surf {
372
373 Model::Model()
374   : maxminSystem_(nullptr)
375 {
376   readyActionSet_ = new ActionList();
377   runningActionSet_ = new ActionList();
378   failedActionSet_ = new ActionList();
379   doneActionSet_ = new ActionList();
380
381   modifiedSet_ = nullptr;
382   actionHeap_ = nullptr;
383   updateMechanism_ = UM_UNDEFINED;
384   selectiveUpdate_ = 0;
385 }
386
387 Model::~Model(){
388   delete readyActionSet_;
389   delete runningActionSet_;
390   delete failedActionSet_;
391   delete doneActionSet_;
392 }
393
394 double Model::nextOccuringEvent(double now)
395 {
396   //FIXME: set the good function once and for all
397   if (updateMechanism_ == UM_LAZY)
398     return nextOccuringEventLazy(now);
399   else if (updateMechanism_ == UM_FULL)
400     return nextOccuringEventFull(now);
401   else
402     xbt_die("Invalid cpu update mechanism!");
403 }
404
405 double Model::nextOccuringEventLazy(double now)
406 {
407   XBT_DEBUG("Before share resources, the size of modified actions set is %zd", modifiedSet_->size());
408   lmm_solve(maxminSystem_);
409   XBT_DEBUG("After share resources, The size of modified actions set is %zd", modifiedSet_->size());
410
411   while(!modifiedSet_->empty()) {
412     Action *action = &(modifiedSet_->front());
413     modifiedSet_->pop_front();
414     int max_dur_flag = 0;
415
416     if (action->getStateSet() != runningActionSet_)
417       continue;
418
419     /* bogus priority, skip it */
420     if (action->getPriority() <= 0 || action->getHat()==LATENCY)
421       continue;
422
423     action->updateRemainingLazy(now);
424
425     double min = -1;
426     double share = lmm_variable_getvalue(action->getVariable());
427
428     if (share > 0) {
429       double time_to_completion;
430       if (action->getRemains() > 0) {
431         time_to_completion = action->getRemainsNoUpdate() / share;
432       } else {
433         time_to_completion = 0.0;
434       }
435       min = now + time_to_completion; // when the task will complete if nothing changes
436     }
437
438     if ((action->getMaxDuration() != NO_MAX_DURATION)
439         && (min == -1
440             || action->getStartTime() +
441             action->getMaxDuration() < min)) {
442       min = action->getStartTime() +
443           action->getMaxDuration();  // when the task will complete anyway because of the deadline if any
444       max_dur_flag = 1;
445     }
446
447
448     XBT_DEBUG("Action(%p) corresponds to variable %d", action, action->getVariable()->id_int);
449
450     XBT_DEBUG("Action(%p) Start %f. May finish at %f (got a share of %f). Max_duration %f", action,
451         action->getStartTime(), min, share,
452         action->getMaxDuration());
453
454     if (min != -1) {
455       action->heapUpdate(actionHeap_, min, max_dur_flag ? MAX_DURATION : NORMAL);
456       XBT_DEBUG("Insert at heap action(%p) min %f now %f", action, min,
457                 now);
458     } else DIE_IMPOSSIBLE;
459   }
460
461   //hereafter must have already the min value for this resource model
462   if (xbt_heap_size(actionHeap_) > 0) {
463     double min = xbt_heap_maxkey(actionHeap_) - now;
464     XBT_DEBUG("minimum with the HEAP %f", min);
465     return min;
466   } else {
467     XBT_DEBUG("The HEAP is empty, thus returning -1");
468     return -1;
469   }
470 }
471
472 double Model::nextOccuringEventFull(double /*now*/) {
473   maxminSystem_->solve_fun(maxminSystem_);
474
475   double min = -1;
476   for (auto it(getRunningActionSet()->begin()), itend(getRunningActionSet()->end()); it != itend ; ++it) {
477     Action *action = &*it;
478     double value = lmm_variable_getvalue(action->getVariable());
479     if (value > 0) {
480       if (action->getRemains() > 0)
481         value = action->getRemainsNoUpdate() / value;
482       else
483         value = 0.0;
484       if (min < 0 || value < min) {
485         min = value;
486         XBT_DEBUG("Updating min (value) with %p: %f", action, min);
487       }
488     }
489     if ((action->getMaxDuration() >= 0) && (min<0 || action->getMaxDuration() < min)) {
490       min = action->getMaxDuration();
491       XBT_DEBUG("Updating min (duration) with %p: %f", action, min);
492     }
493   }
494   XBT_DEBUG("min value : %f", min);
495
496   return min;
497 }
498
499 void Model::updateActionsState(double now, double delta)
500 {
501   if (updateMechanism_ == UM_FULL)
502     updateActionsStateFull(now, delta);
503   else if (updateMechanism_ == UM_LAZY)
504     updateActionsStateLazy(now, delta);
505   else
506     xbt_die("Invalid cpu update mechanism!");
507 }
508
509 void Model::updateActionsStateLazy(double /*now*/, double /*delta*/)
510 {
511   THROW_UNIMPLEMENTED;
512 }
513
514 void Model::updateActionsStateFull(double /*now*/, double /*delta*/)
515 {
516   THROW_UNIMPLEMENTED;
517 }
518
519 }
520 }
521
522 /************
523  * Resource *
524  ************/
525
526 namespace simgrid {
527 namespace surf {
528
529 Resource::Resource(Model* model, const char* name, lmm_constraint_t constraint)
530     : name_(name), model_(model), constraint_(constraint)
531 {}
532
533 Resource::~Resource() = default;
534
535 bool Resource::isOn() const {
536   return isOn_;
537 }
538 bool Resource::isOff() const {
539   return ! isOn_;
540 }
541
542 void Resource::turnOn()
543 {
544   isOn_ = true;
545 }
546
547 void Resource::turnOff()
548 {
549   isOn_ = false;
550 }
551
552 Model *Resource::getModel() const {
553   return model_;
554 }
555
556 const char *Resource::getName() const {
557   return name_.c_str();
558 }
559
560 bool Resource::operator==(const Resource &other) const {
561   return name_ == other.name_;
562 }
563
564 lmm_constraint_t Resource::getConstraint() const {
565   return constraint_;
566 }
567
568 }
569 }
570
571 /**********
572  * Action *
573  **********/
574
575 const char *surf_action_state_names[6] = {
576   "SURF_ACTION_READY",
577   "SURF_ACTION_RUNNING",
578   "SURF_ACTION_FAILED",
579   "SURF_ACTION_DONE",
580   "SURF_ACTION_TO_FREE",
581   "SURF_ACTION_NOT_IN_THE_SYSTEM"
582 };
583
584 /* added to manage the communication action's heap */
585 void surf_action_lmm_update_index_heap(void *action, int i) {
586   static_cast<simgrid::surf::Action*>(action)->updateIndexHeap(i);
587 }
588
589 namespace simgrid {
590 namespace surf {
591
592 Action::Action(simgrid::surf::Model* model, double cost, bool failed) : Action(model, cost, failed, nullptr)
593 {
594 }
595
596 Action::Action(simgrid::surf::Model* model, double cost, bool failed, lmm_variable_t var)
597     : remains_(cost), start_(surf_get_clock()), cost_(cost), model_(model), variable_(var)
598 {
599   if (failed)
600     stateSet_ = getModel()->getFailedActionSet();
601   else
602     stateSet_ = getModel()->getRunningActionSet();
603
604   stateSet_->push_back(*this);
605 }
606
607 Action::~Action() {
608   xbt_free(category_);
609 }
610
611 void Action::finish() {
612     finishTime_ = surf_get_clock();
613 }
614
615 Action::State Action::getState()
616 {
617   if (stateSet_ ==  getModel()->getReadyActionSet())
618     return Action::State::ready;
619   if (stateSet_ ==  getModel()->getRunningActionSet())
620     return Action::State::running;
621   if (stateSet_ ==  getModel()->getFailedActionSet())
622     return Action::State::failed;
623   if (stateSet_ ==  getModel()->getDoneActionSet())
624     return Action::State::done;
625   return Action::State::not_in_the_system;
626 }
627
628 void Action::setState(Action::State state)
629 {
630   stateSet_->erase(stateSet_->iterator_to(*this));
631   switch (state) {
632   case Action::State::ready:
633     stateSet_ = getModel()->getReadyActionSet();
634     break;
635   case Action::State::running:
636     stateSet_ = getModel()->getRunningActionSet();
637     break;
638   case Action::State::failed:
639     stateSet_ = getModel()->getFailedActionSet();
640     break;
641   case Action::State::done:
642     stateSet_ = getModel()->getDoneActionSet();
643     break;
644   default:
645     stateSet_ = nullptr;
646     break;
647   }
648   if (stateSet_)
649     stateSet_->push_back(*this);
650 }
651
652 double Action::getBound()
653 {
654   return (variable_) ? lmm_variable_getbound(variable_) : 0;
655 }
656
657 void Action::setBound(double bound)
658 {
659   XBT_IN("(%p,%g)", this, bound);
660   if (variable_)
661     lmm_update_variable_bound(getModel()->getMaxminSystem(), variable_, bound);
662
663   if (getModel()->getUpdateMechanism() == UM_LAZY && getLastUpdate()!=surf_get_clock())
664     heapRemove(getModel()->getActionHeap());
665   XBT_OUT();
666 }
667
668 double Action::getStartTime()
669 {
670   return start_;
671 }
672
673 double Action::getFinishTime()
674 {
675   /* keep the function behavior, some models (cpu_ti) change the finish time before the action end */
676   return remains_ == 0 ? finishTime_ : -1;
677 }
678
679 void Action::setData(void* data)
680 {
681   data_ = data;
682 }
683
684 void Action::setCategory(const char *category)
685 {
686   category_ = xbt_strdup(category);
687 }
688
689 void Action::ref(){
690   refcount_++;
691 }
692
693 void Action::setMaxDuration(double duration)
694 {
695   maxDuration_ = duration;
696   if (getModel()->getUpdateMechanism() == UM_LAZY)      // remove action from the heap
697     heapRemove(getModel()->getActionHeap());
698 }
699
700 void Action::gapRemove() {}
701
702 void Action::setPriority(double priority)
703 {
704   XBT_IN("(%p,%g)", this, priority);
705   priority_ = priority;
706   lmm_update_variable_weight(getModel()->getMaxminSystem(), getVariable(), priority);
707
708   if (getModel()->getUpdateMechanism() == UM_LAZY)
709     heapRemove(getModel()->getActionHeap());
710   XBT_OUT();
711 }
712
713 void Action::cancel(){
714   setState(Action::State::failed);
715   if (getModel()->getUpdateMechanism() == UM_LAZY) {
716     if (action_lmm_hook.is_linked())
717       getModel()->getModifiedSet()->erase(getModel()->getModifiedSet()->iterator_to(*this));
718     heapRemove(getModel()->getActionHeap());
719   }
720 }
721
722 int Action::unref(){
723   refcount_--;
724   if (!refcount_) {
725     if (action_hook.is_linked())
726       stateSet_->erase(stateSet_->iterator_to(*this));
727     if (getVariable())
728       lmm_variable_free(getModel()->getMaxminSystem(), getVariable());
729     if (getModel()->getUpdateMechanism() == UM_LAZY) {
730       /* remove from heap */
731       heapRemove(getModel()->getActionHeap());
732       if (action_lmm_hook.is_linked())
733         getModel()->getModifiedSet()->erase(getModel()->getModifiedSet()->iterator_to(*this));
734     }
735     delete this;
736     return 1;
737   }
738   return 0;
739 }
740
741 void Action::suspend()
742 {
743   XBT_IN("(%p)", this);
744   if (suspended_ != 2) {
745     lmm_update_variable_weight(getModel()->getMaxminSystem(), getVariable(), 0.0);
746     if (getModel()->getUpdateMechanism() == UM_LAZY){
747       heapRemove(getModel()->getActionHeap());
748       if (getModel()->getUpdateMechanism() == UM_LAZY  && stateSet_ == getModel()->getRunningActionSet() && priority_ > 0){
749         //If we have a lazy model, we need to update the remaining value accordingly
750         updateRemainingLazy(surf_get_clock());
751       }
752     }
753     suspended_ = 1;
754   }
755   XBT_OUT();
756 }
757
758 void Action::resume()
759 {
760   XBT_IN("(%p)", this);
761   if (suspended_ != 2) {
762     lmm_update_variable_weight(getModel()->getMaxminSystem(), getVariable(), priority_);
763     suspended_ = 0;
764     if (getModel()->getUpdateMechanism() == UM_LAZY)
765       heapRemove(getModel()->getActionHeap());
766   }
767   XBT_OUT();
768 }
769
770 bool Action::isSuspended()
771 {
772   return suspended_ == 1;
773 }
774 /* insert action on heap using a given key and a hat (heap_action_type)
775  * a hat can be of three types for communications:
776  *
777  * NORMAL = this is a normal heap entry stating the date to finish transmitting
778  * LATENCY = this is a heap entry to warn us when the latency is payed
779  * MAX_DURATION =this is a heap entry to warn us when the max_duration limit is reached
780  */
781 void Action::heapInsert(xbt_heap_t heap, double key, enum heap_action_type hat)
782 {
783   hat_ = hat;
784   xbt_heap_push(heap, this, key);
785 }
786
787 void Action::heapRemove(xbt_heap_t heap)
788 {
789   hat_ = NOTSET;
790   if (indexHeap_ >= 0) {
791     xbt_heap_remove(heap, indexHeap_);
792   }
793 }
794
795 void Action::heapUpdate(xbt_heap_t heap, double key, enum heap_action_type hat)
796 {
797   hat_ = hat;
798   if (indexHeap_ >= 0) {
799     xbt_heap_update(heap, indexHeap_, key);
800   }else{
801     xbt_heap_push(heap, this, key);
802   }
803 }
804
805 void Action::updateIndexHeap(int i) {
806   indexHeap_ = i;
807 }
808
809 double Action::getRemains()
810 {
811   XBT_IN("(%p)", this);
812   /* update remains before return it */
813   if (getModel()->getUpdateMechanism() == UM_LAZY)      /* update remains before return it */
814     updateRemainingLazy(surf_get_clock());
815   XBT_OUT();
816   return remains_;
817 }
818
819 double Action::getRemainsNoUpdate()
820 {
821   return remains_;
822 }
823
824 //FIXME split code in the right places
825 void Action::updateRemainingLazy(double now)
826 {
827   double delta = 0.0;
828
829   if(getModel() == surf_network_model)
830   {
831     if (suspended_ != 0)
832       return;
833   }
834   else
835   {
836     xbt_assert(stateSet_ == getModel()->getRunningActionSet(), "You're updating an action that is not running.");
837     xbt_assert(priority_ > 0, "You're updating an action that seems suspended.");
838   }
839
840   delta = now - lastUpdate_;
841
842   if (remains_ > 0) {
843     XBT_DEBUG("Updating action(%p): remains was %f, last_update was: %f", this, remains_, lastUpdate_);
844     double_update(&remains_, lastValue_ * delta, sg_surf_precision*sg_maxmin_precision);
845
846     if (getModel() == surf_cpu_model_pm && TRACE_is_enabled()) {
847       simgrid::surf::Resource *cpu = static_cast<simgrid::surf::Resource*>(
848         lmm_constraint_id(lmm_get_cnst_from_var(getModel()->getMaxminSystem(), getVariable(), 0)));
849       TRACE_surf_host_set_utilization(cpu->getName(), getCategory(), lastValue_, lastUpdate_, now - lastUpdate_);
850     }
851     XBT_DEBUG("Updating action(%p): remains is now %f", this, remains_);
852   }
853
854   if(getModel() == surf_network_model)
855   {
856     if (maxDuration_ != NO_MAX_DURATION)
857       double_update(&maxDuration_, delta, sg_surf_precision);
858
859     //FIXME: duplicated code
860     if ((remains_ <= 0) &&
861         (lmm_get_variable_weight(getVariable()) > 0)) {
862       finish();
863       setState(Action::State::done);
864       heapRemove(getModel()->getActionHeap());
865     } else if (((maxDuration_ != NO_MAX_DURATION)
866         && (maxDuration_ <= 0))) {
867       finish();
868       setState(Action::State::done);
869       heapRemove(getModel()->getActionHeap());
870     }
871   }
872
873   lastUpdate_ = now;
874   lastValue_ = lmm_variable_getvalue(getVariable());
875 }
876
877 }
878 }