Logo AND Algorithmique Numérique Distribuée

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