Logo AND Algorithmique Numérique Distribuée

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