Logo AND Algorithmique Numérique Distribuée

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