Logo AND Algorithmique Numérique Distribuée

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