Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
call updateRemaining when the action is suspended (fix #123)
[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   routing_exit();
348
349   simgrid::surf::surfExitCallbacks();
350
351   if (future_evt_set) {
352     delete future_evt_set;
353     future_evt_set = nullptr;
354   }
355
356 #if HAVE_THREAD_CONTEXTS
357   xbt_parmap_destroy(surf_parmap);
358 #endif
359
360   tmgr_finalize();
361   sg_platf_exit();
362   simgrid::s4u::Engine::shutdown();
363
364   NOW = 0;                      /* Just in case the user plans to restart the simulation afterward */
365 }
366
367 /*********
368  * Model *
369  *********/
370
371 namespace simgrid {
372 namespace surf {
373
374 Model::Model()
375   : maxminSystem_(nullptr)
376 {
377   readyActionSet_ = new ActionList();
378   runningActionSet_ = new ActionList();
379   failedActionSet_ = new ActionList();
380   doneActionSet_ = new ActionList();
381
382   modifiedSet_ = nullptr;
383   actionHeap_ = nullptr;
384   updateMechanism_ = UM_UNDEFINED;
385   selectiveUpdate_ = 0;
386 }
387
388 Model::~Model(){
389   delete readyActionSet_;
390   delete runningActionSet_;
391   delete failedActionSet_;
392   delete doneActionSet_;
393 }
394
395 double Model::nextOccuringEvent(double now)
396 {
397   //FIXME: set the good function once and for all
398   if (updateMechanism_ == UM_LAZY)
399     return nextOccuringEventLazy(now);
400   else if (updateMechanism_ == UM_FULL)
401     return nextOccuringEventFull(now);
402   else
403     xbt_die("Invalid cpu update mechanism!");
404 }
405
406 double Model::nextOccuringEventLazy(double now)
407 {
408   XBT_DEBUG("Before share resources, the size of modified actions set is %zd", modifiedSet_->size());
409   lmm_solve(maxminSystem_);
410   XBT_DEBUG("After share resources, The size of modified actions set is %zd", modifiedSet_->size());
411
412   while(!modifiedSet_->empty()) {
413     Action *action = &(modifiedSet_->front());
414     modifiedSet_->pop_front();
415     int max_dur_flag = 0;
416
417     if (action->getStateSet() != runningActionSet_)
418       continue;
419
420     /* bogus priority, skip it */
421     if (action->getPriority() <= 0 || action->getHat()==LATENCY)
422       continue;
423
424     action->updateRemainingLazy(now);
425
426     double min = -1;
427     double share = lmm_variable_getvalue(action->getVariable());
428
429     if (share > 0) {
430       double time_to_completion;
431       if (action->getRemains() > 0) {
432         time_to_completion = action->getRemainsNoUpdate() / share;
433       } else {
434         time_to_completion = 0.0;
435       }
436       min = now + time_to_completion; // when the task will complete if nothing changes
437     }
438
439     if ((action->getMaxDuration() != NO_MAX_DURATION)
440         && (min == -1
441             || action->getStartTime() +
442             action->getMaxDuration() < min)) {
443       min = action->getStartTime() +
444           action->getMaxDuration();  // when the task will complete anyway because of the deadline if any
445       max_dur_flag = 1;
446     }
447
448
449     XBT_DEBUG("Action(%p) corresponds to variable %d", action, action->getVariable()->id_int);
450
451     XBT_DEBUG("Action(%p) Start %f. May finish at %f (got a share of %f). Max_duration %f", action,
452         action->getStartTime(), min, share,
453         action->getMaxDuration());
454
455     if (min != -1) {
456       action->heapUpdate(actionHeap_, min, max_dur_flag ? MAX_DURATION : NORMAL);
457       XBT_DEBUG("Insert at heap action(%p) min %f now %f", action, min,
458                 now);
459     } else DIE_IMPOSSIBLE;
460   }
461
462   //hereafter must have already the min value for this resource model
463   if (xbt_heap_size(actionHeap_) > 0) {
464     double min = xbt_heap_maxkey(actionHeap_) - now;
465     XBT_DEBUG("minimum with the HEAP %f", min);
466     return min;
467   } else {
468     XBT_DEBUG("The HEAP is empty, thus returning -1");
469     return -1;
470   }
471 }
472
473 double Model::nextOccuringEventFull(double /*now*/) {
474   maxminSystem_->solve_fun(maxminSystem_);
475
476   double min = -1;
477   for (auto it(getRunningActionSet()->begin()), itend(getRunningActionSet()->end()); it != itend ; ++it) {
478     Action *action = &*it;
479     double value = lmm_variable_getvalue(action->getVariable());
480     if (value > 0) {
481       if (action->getRemains() > 0)
482         value = action->getRemainsNoUpdate() / value;
483       else
484         value = 0.0;
485       if (min < 0 || value < min) {
486         min = value;
487         XBT_DEBUG("Updating min (value) with %p: %f", action, min);
488       }
489     }
490     if ((action->getMaxDuration() >= 0) && (min<0 || action->getMaxDuration() < min)) {
491       min = action->getMaxDuration();
492       XBT_DEBUG("Updating min (duration) with %p: %f", action, min);
493     }
494   }
495   XBT_DEBUG("min value : %f", min);
496
497   return min;
498 }
499
500 void Model::updateActionsState(double now, double delta)
501 {
502   if (updateMechanism_ == UM_FULL)
503     updateActionsStateFull(now, delta);
504   else if (updateMechanism_ == UM_LAZY)
505     updateActionsStateLazy(now, delta);
506   else
507     xbt_die("Invalid cpu update mechanism!");
508 }
509
510 void Model::updateActionsStateLazy(double /*now*/, double /*delta*/)
511 {
512   THROW_UNIMPLEMENTED;
513 }
514
515 void Model::updateActionsStateFull(double /*now*/, double /*delta*/)
516 {
517   THROW_UNIMPLEMENTED;
518 }
519
520 }
521 }
522
523 /************
524  * Resource *
525  ************/
526
527 namespace simgrid {
528 namespace surf {
529
530 Resource::Resource(Model* model, const char* name, lmm_constraint_t constraint)
531     : name_(name), model_(model), constraint_(constraint)
532 {}
533
534 Resource::~Resource() = default;
535
536 bool Resource::isOn() const {
537   return isOn_;
538 }
539 bool Resource::isOff() const {
540   return ! isOn_;
541 }
542
543 void Resource::turnOn()
544 {
545   isOn_ = true;
546 }
547
548 void Resource::turnOff()
549 {
550   isOn_ = false;
551 }
552
553 Model *Resource::getModel() const {
554   return model_;
555 }
556
557 const char *Resource::getName() const {
558   return name_.c_str();
559 }
560
561 bool Resource::operator==(const Resource &other) const {
562   return name_ == other.name_;
563 }
564
565 lmm_constraint_t Resource::getConstraint() const {
566   return constraint_;
567 }
568
569 }
570 }
571
572 /**********
573  * Action *
574  **********/
575
576 const char *surf_action_state_names[6] = {
577   "SURF_ACTION_READY",
578   "SURF_ACTION_RUNNING",
579   "SURF_ACTION_FAILED",
580   "SURF_ACTION_DONE",
581   "SURF_ACTION_TO_FREE",
582   "SURF_ACTION_NOT_IN_THE_SYSTEM"
583 };
584
585 /* added to manage the communication action's heap */
586 void surf_action_lmm_update_index_heap(void *action, int i) {
587   static_cast<simgrid::surf::Action*>(action)->updateIndexHeap(i);
588 }
589
590 namespace simgrid {
591 namespace surf {
592
593 Action::Action(simgrid::surf::Model* model, double cost, bool failed) : Action(model, cost, failed, nullptr)
594 {
595 }
596
597 Action::Action(simgrid::surf::Model* model, double cost, bool failed, lmm_variable_t var)
598     : remains_(cost), start_(surf_get_clock()), cost_(cost), model_(model), variable_(var)
599 {
600   if (failed)
601     stateSet_ = getModel()->getFailedActionSet();
602   else
603     stateSet_ = getModel()->getRunningActionSet();
604
605   stateSet_->push_back(*this);
606 }
607
608 Action::~Action() {
609   xbt_free(category_);
610 }
611
612 void Action::finish() {
613     finishTime_ = surf_get_clock();
614 }
615
616 Action::State Action::getState()
617 {
618   if (stateSet_ ==  getModel()->getReadyActionSet())
619     return Action::State::ready;
620   if (stateSet_ ==  getModel()->getRunningActionSet())
621     return Action::State::running;
622   if (stateSet_ ==  getModel()->getFailedActionSet())
623     return Action::State::failed;
624   if (stateSet_ ==  getModel()->getDoneActionSet())
625     return Action::State::done;
626   return Action::State::not_in_the_system;
627 }
628
629 void Action::setState(Action::State state)
630 {
631   stateSet_->erase(stateSet_->iterator_to(*this));
632   switch (state) {
633   case Action::State::ready:
634     stateSet_ = getModel()->getReadyActionSet();
635     break;
636   case Action::State::running:
637     stateSet_ = getModel()->getRunningActionSet();
638     break;
639   case Action::State::failed:
640     stateSet_ = getModel()->getFailedActionSet();
641     break;
642   case Action::State::done:
643     stateSet_ = getModel()->getDoneActionSet();
644     break;
645   default:
646     stateSet_ = nullptr;
647     break;
648   }
649   if (stateSet_)
650     stateSet_->push_back(*this);
651 }
652
653 double Action::getBound()
654 {
655   return (variable_) ? lmm_variable_getbound(variable_) : 0;
656 }
657
658 void Action::setBound(double bound)
659 {
660   XBT_IN("(%p,%g)", this, bound);
661   if (variable_)
662     lmm_update_variable_bound(getModel()->getMaxminSystem(), variable_, bound);
663
664   if (getModel()->getUpdateMechanism() == UM_LAZY && getLastUpdate()!=surf_get_clock())
665     heapRemove(getModel()->getActionHeap());
666   XBT_OUT();
667 }
668
669 double Action::getStartTime()
670 {
671   return start_;
672 }
673
674 double Action::getFinishTime()
675 {
676   /* keep the function behavior, some models (cpu_ti) change the finish time before the action end */
677   return remains_ == 0 ? finishTime_ : -1;
678 }
679
680 void Action::setData(void* data)
681 {
682   data_ = data;
683 }
684
685 void Action::setCategory(const char *category)
686 {
687   category_ = xbt_strdup(category);
688 }
689
690 void Action::ref(){
691   refcount_++;
692 }
693
694 void Action::setMaxDuration(double duration)
695 {
696   maxDuration_ = duration;
697   if (getModel()->getUpdateMechanism() == UM_LAZY)      // remove action from the heap
698     heapRemove(getModel()->getActionHeap());
699 }
700
701 void Action::gapRemove() {}
702
703 void Action::setPriority(double priority)
704 {
705   XBT_IN("(%p,%g)", this, priority);
706   priority_ = priority;
707   lmm_update_variable_weight(getModel()->getMaxminSystem(), getVariable(), priority);
708
709   if (getModel()->getUpdateMechanism() == UM_LAZY)
710     heapRemove(getModel()->getActionHeap());
711   XBT_OUT();
712 }
713
714 void Action::cancel(){
715   setState(Action::State::failed);
716   if (getModel()->getUpdateMechanism() == UM_LAZY) {
717     if (action_lmm_hook.is_linked())
718       getModel()->getModifiedSet()->erase(getModel()->getModifiedSet()->iterator_to(*this));
719     heapRemove(getModel()->getActionHeap());
720   }
721 }
722
723 int Action::unref(){
724   refcount_--;
725   if (!refcount_) {
726     if (action_hook.is_linked())
727       stateSet_->erase(stateSet_->iterator_to(*this));
728     if (getVariable())
729       lmm_variable_free(getModel()->getMaxminSystem(), getVariable());
730     if (getModel()->getUpdateMechanism() == UM_LAZY) {
731       /* remove from heap */
732       heapRemove(getModel()->getActionHeap());
733       if (action_lmm_hook.is_linked())
734         getModel()->getModifiedSet()->erase(getModel()->getModifiedSet()->iterator_to(*this));
735     }
736     delete this;
737     return 1;
738   }
739   return 0;
740 }
741
742 void Action::suspend()
743 {
744   XBT_IN("(%p)", this);
745   if (suspended_ != 2) {
746     lmm_update_variable_weight(getModel()->getMaxminSystem(), getVariable(), 0.0);
747     if (getModel()->getUpdateMechanism() == UM_LAZY){
748       heapRemove(getModel()->getActionHeap());
749       if (getModel()->getUpdateMechanism() == UM_LAZY  && stateSet_ == getModel()->getRunningActionSet() && priority_ > 0){
750         //If we have a lazy model, we need to update the remaining value accordingly
751         updateRemainingLazy(surf_get_clock());
752       }
753     }
754     suspended_ = 1;
755   }
756   XBT_OUT();
757 }
758
759 void Action::resume()
760 {
761   XBT_IN("(%p)", this);
762   if (suspended_ != 2) {
763     lmm_update_variable_weight(getModel()->getMaxminSystem(), getVariable(), priority_);
764     suspended_ = 0;
765     if (getModel()->getUpdateMechanism() == UM_LAZY)
766       heapRemove(getModel()->getActionHeap());
767   }
768   XBT_OUT();
769 }
770
771 bool Action::isSuspended()
772 {
773   return suspended_ == 1;
774 }
775 /* insert action on heap using a given key and a hat (heap_action_type)
776  * a hat can be of three types for communications:
777  *
778  * NORMAL = this is a normal heap entry stating the date to finish transmitting
779  * LATENCY = this is a heap entry to warn us when the latency is payed
780  * MAX_DURATION =this is a heap entry to warn us when the max_duration limit is reached
781  */
782 void Action::heapInsert(xbt_heap_t heap, double key, enum heap_action_type hat)
783 {
784   hat_ = hat;
785   xbt_heap_push(heap, this, key);
786 }
787
788 void Action::heapRemove(xbt_heap_t heap)
789 {
790   hat_ = NOTSET;
791   if (indexHeap_ >= 0) {
792     xbt_heap_remove(heap, indexHeap_);
793   }
794 }
795
796 void Action::heapUpdate(xbt_heap_t heap, double key, enum heap_action_type hat)
797 {
798   hat_ = hat;
799   if (indexHeap_ >= 0) {
800     xbt_heap_update(heap, indexHeap_, key);
801   }else{
802     xbt_heap_push(heap, this, key);
803   }
804 }
805
806 void Action::updateIndexHeap(int i) {
807   indexHeap_ = i;
808 }
809
810 double Action::getRemains()
811 {
812   XBT_IN("(%p)", this);
813   /* update remains before return it */
814   if (getModel()->getUpdateMechanism() == UM_LAZY)      /* update remains before return it */
815     updateRemainingLazy(surf_get_clock());
816   XBT_OUT();
817   return remains_;
818 }
819
820 double Action::getRemainsNoUpdate()
821 {
822   return remains_;
823 }
824
825 //FIXME split code in the right places
826 void Action::updateRemainingLazy(double now)
827 {
828   double delta = 0.0;
829
830   if(getModel() == surf_network_model)
831   {
832     if (suspended_ != 0)
833       return;
834   }
835   else
836   {
837     xbt_assert(stateSet_ == getModel()->getRunningActionSet(), "You're updating an action that is not running.");
838     xbt_assert(priority_ > 0, "You're updating an action that seems suspended.");
839   }
840
841   delta = now - lastUpdate_;
842
843   if (remains_ > 0) {
844     XBT_DEBUG("Updating action(%p): remains was %f, last_update was: %f", this, remains_, lastUpdate_);
845     double_update(&remains_, lastValue_ * delta, sg_surf_precision*sg_maxmin_precision);
846
847     if (getModel() == surf_cpu_model_pm && TRACE_is_enabled()) {
848       simgrid::surf::Resource *cpu = static_cast<simgrid::surf::Resource*>(
849         lmm_constraint_id(lmm_get_cnst_from_var(getModel()->getMaxminSystem(), getVariable(), 0)));
850       TRACE_surf_host_set_utilization(cpu->getName(), getCategory(), lastValue_, lastUpdate_, now - lastUpdate_);
851     }
852     XBT_DEBUG("Updating action(%p): remains is now %f", this, remains_);
853   }
854
855   if(getModel() == surf_network_model)
856   {
857     if (maxDuration_ != NO_MAX_DURATION)
858       double_update(&maxDuration_, delta, sg_surf_precision);
859
860     //FIXME: duplicated code
861     if ((remains_ <= 0) &&
862         (lmm_get_variable_weight(getVariable()) > 0)) {
863       finish();
864       setState(Action::State::done);
865       heapRemove(getModel()->getActionHeap());
866     } else if (((maxDuration_ != NO_MAX_DURATION)
867         && (maxDuration_ <= 0))) {
868       finish();
869       setState(Action::State::done);
870       heapRemove(getModel()->getActionHeap());
871     }
872   }
873
874   lastUpdate_ = now;
875   lastValue_ = lmm_variable_getvalue(getVariable());
876 }
877
878 }
879 }