Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
SimDag instrumentation for categorized resource utilization
[simgrid.git] / src / simdag / sd_global.c
1 /* Copyright (c) 2006, 2007, 2008, 2009, 2010. 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 "private.h"
8 #include "xbt/sysdep.h"
9 #include "xbt/dynar.h"
10 #include "surf/surf.h"
11 #include "xbt/ex.h"
12 #include "xbt/log.h"
13 #include "xbt/str.h"
14 #include "xbt/config.h"
15 #include "instr/private.h"
16 #ifdef HAVE_LUA
17 #include <lua.h>
18 #include <lauxlib.h>
19 #include <lualib.h>
20 #endif
21
22 XBT_LOG_NEW_CATEGORY(sd, "Logging specific to SimDag");
23 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_kernel, sd,
24                                 "Logging specific to SimDag (kernel)");
25
26 SD_global_t sd_global = NULL;
27
28 XBT_LOG_EXTERNAL_CATEGORY(sd_kernel);
29 XBT_LOG_EXTERNAL_CATEGORY(sd_task);
30 XBT_LOG_EXTERNAL_CATEGORY(sd_workstation);
31
32 /**
33  * \brief Initialises SD internal data
34  *
35  * This function must be called before any other SD function. Then you
36  * should call SD_create_environment().
37  *
38  * \param argc argument number
39  * \param argv argument list
40  * \see SD_create_environment(), SD_exit()
41  */
42 void SD_init(int *argc, char **argv)
43 {
44 #ifdef HAVE_TRACING
45   TRACE_global_init (argc, argv);
46 #endif
47
48   s_SD_task_t task;
49
50   xbt_assert0(!SD_INITIALISED(), "SD_init() already called");
51
52   /* Connect our log channels: that must be done manually under windows */
53   XBT_LOG_CONNECT(sd_kernel, sd);
54   XBT_LOG_CONNECT(sd_task, sd);
55   XBT_LOG_CONNECT(sd_workstation, sd);
56
57
58   sd_global = xbt_new(s_SD_global_t, 1);
59   sd_global->workstations = xbt_dict_new();
60   sd_global->workstation_count = 0;
61   sd_global->workstation_list = NULL;
62   sd_global->links = xbt_dict_new();
63   sd_global->link_count = 0;
64   sd_global->link_list = NULL;
65   sd_global->recyclable_route = NULL;
66   sd_global->watch_point_reached = 0;
67
68   sd_global->not_scheduled_task_set =
69     xbt_swag_new(xbt_swag_offset(task, state_hookup));
70   sd_global->schedulable_task_set =
71     xbt_swag_new(xbt_swag_offset(task, state_hookup));
72   sd_global->scheduled_task_set =
73       xbt_swag_new(xbt_swag_offset(task, state_hookup));
74   sd_global->runnable_task_set =
75     xbt_swag_new(xbt_swag_offset(task, state_hookup));
76   sd_global->in_fifo_task_set =
77     xbt_swag_new(xbt_swag_offset(task, state_hookup));
78   sd_global->running_task_set =
79     xbt_swag_new(xbt_swag_offset(task, state_hookup));
80   sd_global->done_task_set =
81     xbt_swag_new(xbt_swag_offset(task, state_hookup));
82   sd_global->failed_task_set =
83     xbt_swag_new(xbt_swag_offset(task, state_hookup));
84   sd_global->task_number = 0;
85
86   surf_init(argc, argv);
87   xbt_cfg_setdefault_string(_surf_cfg_set, "workstation/model", "ptask_L07");
88 }
89
90 /**
91  * \brief Reinits the application part of the simulation (experimental feature)
92  *
93  * This function allows you to run several simulations on the same platform
94  * by resetting the part describing the application.
95  *
96  * @warning: this function is still experimental and not perfect. For example,
97  * the simulation clock (and traces usage) is not reset. So, do not use it if
98  * you use traces in your simulation, and do not use absolute timing after using it.
99  * That being said, this function is still precious if you want to compare a bunch of
100  * heuristics on the same platforms.
101  */
102 void SD_application_reinit(void)
103 {
104
105   s_SD_task_t task;
106
107   if (SD_INITIALISED()) {
108     DEBUG0("Recreating the swags...");
109     xbt_swag_free(sd_global->not_scheduled_task_set);
110     xbt_swag_free(sd_global->schedulable_task_set);
111     xbt_swag_free(sd_global->scheduled_task_set);
112     xbt_swag_free(sd_global->runnable_task_set);
113     xbt_swag_free(sd_global->in_fifo_task_set);
114     xbt_swag_free(sd_global->running_task_set);
115     xbt_swag_free(sd_global->done_task_set);
116     xbt_swag_free(sd_global->failed_task_set);
117
118     sd_global->not_scheduled_task_set =
119       xbt_swag_new(xbt_swag_offset(task, state_hookup));
120     sd_global->schedulable_task_set =
121       xbt_swag_new(xbt_swag_offset(task, state_hookup));
122     sd_global->scheduled_task_set =
123       xbt_swag_new(xbt_swag_offset(task, state_hookup));
124     sd_global->runnable_task_set =
125       xbt_swag_new(xbt_swag_offset(task, state_hookup));
126     sd_global->in_fifo_task_set =
127       xbt_swag_new(xbt_swag_offset(task, state_hookup));
128     sd_global->running_task_set =
129       xbt_swag_new(xbt_swag_offset(task, state_hookup));
130     sd_global->done_task_set =
131       xbt_swag_new(xbt_swag_offset(task, state_hookup));
132     sd_global->failed_task_set =
133       xbt_swag_new(xbt_swag_offset(task, state_hookup));
134     sd_global->task_number = 0;
135   } else {
136     WARN0("SD_application_reinit called before initialization of SimDag");
137     /* we cannot use exceptions here because xbt is not running! */
138   }
139
140 }
141
142 /**
143  * \brief Creates the environment
144  *
145  * The environment (i.e. the \ref SD_workstation_management "workstations" and the
146  * \ref SD_link_management "links") is created with the data stored in the given XML
147  * platform file.
148  *
149  * \param platform_file name of an XML file describing the environment to create
150  * \see SD_workstation_management, SD_link_management
151  *
152  * The XML file follows this DTD:
153  *
154  *     \include simgrid.dtd
155  *
156  * Here is a small example of such a platform:
157  *
158  *     \include small_platform.xml
159  */
160 void SD_create_environment(const char *platform_file)
161 {
162   xbt_dict_cursor_t cursor = NULL;
163   char *name = NULL;
164   void *surf_workstation = NULL;
165   void *surf_link = NULL;
166
167   SD_CHECK_INIT_DONE();
168
169   DEBUG0("SD_create_environment");
170
171   surf_config_models_setup(platform_file);
172   parse_platform_file(platform_file);
173   surf_config_models_create_elms();
174
175   /* now let's create the SD wrappers for workstations and links */
176   xbt_dict_foreach(surf_model_resource_set(surf_workstation_model), cursor,
177                    name, surf_workstation) {
178     __SD_workstation_create(surf_workstation, NULL);
179   }
180
181   xbt_dict_foreach(surf_model_resource_set(surf_network_model), cursor, name, surf_link) {
182     __SD_link_create(surf_link, NULL);
183   }
184
185   DEBUG2("Workstation number: %d, link number: %d",
186          SD_workstation_get_number(), SD_link_get_number());
187
188 #ifdef HAVE_TRACING
189   TRACE_surf_save_onelink ();
190 #endif
191 }
192
193 /**
194  * \brief Launches the simulation.
195  *
196  * The function will execute the \ref SD_RUNNABLE runnable tasks.
197  * The simulation will be stopped when its time reaches \a how_long,
198  * when a watch point is reached, or when no more task can be executed.
199  * Then you can call SD_simulate() again.
200  *
201  * \param how_long maximum duration of the simulation (a negative value means no time limit)
202  * \return a NULL-terminated array of \ref SD_task_t whose state has changed.
203  * \see SD_task_schedule(), SD_task_watch()
204  */
205 xbt_dynar_t SD_simulate(double how_long)
206 {
207   double total_time = 0.0;      /* we stop the simulation when total_time >= how_long */
208   double elapsed_time = 0.0;
209   SD_task_t task, task_safe, dst;
210   SD_dependency_t dependency;
211   surf_action_t action;
212   xbt_dynar_t changed_tasks = xbt_dynar_new(sizeof(SD_task_t), NULL);
213   unsigned int iter, depcnt;
214   static int first_time = 1;
215
216   SD_CHECK_INIT_DONE();
217
218   VERB0("Starting simulation...");
219
220   if (first_time) {
221     surf_presolve();            /* Takes traces into account */
222     first_time = 0;
223   }
224
225   if (how_long > 0) {
226     surf_timer_model->extension.timer.set(surf_get_clock() + how_long,
227                                           NULL, NULL);
228   }
229   sd_global->watch_point_reached = 0;
230
231   /* explore the runnable tasks */
232   xbt_swag_foreach_safe(task, task_safe, sd_global->runnable_task_set) {
233     VERB1("Executing task '%s'", SD_task_get_name(task));
234     if (__SD_task_try_to_run(task) && !xbt_dynar_member(changed_tasks, &task))
235       xbt_dynar_push(changed_tasks, &task);
236   }
237
238   /* main loop */
239   elapsed_time = 0.0;
240   while (elapsed_time >= 0.0 &&
241          (how_long < 0.0 || total_time < how_long) &&
242          !sd_global->watch_point_reached) {
243     surf_model_t model = NULL;
244     /* dumb variables */
245     void *fun = NULL;
246     void *arg = NULL;
247
248
249     DEBUG1("Total time: %f", total_time);
250
251     elapsed_time = surf_solve();
252     DEBUG1("surf_solve() returns %f", elapsed_time);
253     if (elapsed_time > 0.0)
254       total_time += elapsed_time;
255
256     /* let's see which tasks are done */
257     xbt_dynar_foreach(model_list, iter, model) {
258       while ((action = xbt_swag_extract(model->states.done_action_set))) {
259         task = action->data;
260         task->start_time = surf_workstation_model->action_get_start_time(task->surf_action);
261         task->finish_time = surf_get_clock();
262         VERB1("Task '%s' done", SD_task_get_name(task));
263         DEBUG0("Calling __SD_task_just_done");
264         __SD_task_just_done(task);
265         DEBUG1("__SD_task_just_done called on task '%s'",
266                SD_task_get_name(task));
267
268         /* the state has changed */
269         if (!xbt_dynar_member(changed_tasks, &task))
270           xbt_dynar_push(changed_tasks, &task);
271
272         /* remove the dependencies after this task */
273         xbt_dynar_foreach(task->tasks_after, depcnt, dependency){
274                         dst = dependency->dst;
275           if (dst->unsatisfied_dependencies>0)
276                   dst->unsatisfied_dependencies--;
277           if (dst->is_not_ready>0)
278                   dst->is_not_ready--;
279
280           if (!(dst->unsatisfied_dependencies)){
281                   if (__SD_task_is_scheduled(dst))
282                           __SD_task_set_state(dst, SD_RUNNABLE);
283                   else
284                           __SD_task_set_state(dst, SD_SCHEDULABLE);
285           }
286
287           if (SD_task_get_kind(dst) == SD_TASK_COMM_E2E){
288                   SD_dependency_t comm_dep;
289                   SD_task_t comm_dst;
290                   xbt_dynar_get_cpy(dst->tasks_after, 0, &comm_dep);
291                   comm_dst = comm_dep->dst;
292                   if (__SD_task_is_not_scheduled(comm_dst) &&
293                           comm_dst->is_not_ready>0){
294                           comm_dst->is_not_ready--;
295
296                           if (!(comm_dst->is_not_ready)){
297                                   __SD_task_set_state(comm_dst, SD_SCHEDULABLE);
298                           }
299                   }
300           }
301
302           /* is dst runnable now? */
303           if (__SD_task_is_runnable(dst) && !sd_global->watch_point_reached) {
304             VERB1("Executing task '%s'", SD_task_get_name(dst));
305             if (__SD_task_try_to_run(dst) &&
306                 !xbt_dynar_member(changed_tasks, &task))
307               xbt_dynar_push(changed_tasks, &task);
308           }
309         }
310       }
311
312       /* let's see which tasks have just failed */
313       while ((action = xbt_swag_extract(model->states.failed_action_set))) {
314         task = action->data;
315         task->start_time = surf_workstation_model->action_get_start_time(task->surf_action);
316         task->finish_time = surf_get_clock();
317         VERB1("Task '%s' failed", SD_task_get_name(task));
318         __SD_task_set_state(task, SD_FAILED);
319         surf_workstation_model->action_unref(action);
320         task->surf_action = NULL;
321
322         if (!xbt_dynar_member(changed_tasks, &task))
323           xbt_dynar_push(changed_tasks, &task);
324       }
325     }
326
327     while (surf_timer_model->extension.timer.get(&fun, (void *) &arg)) {
328     }
329   }
330
331   VERB0("Simulation finished");
332   DEBUG3("elapsed_time = %f, total_time = %f, watch_point_reached = %d",
333          elapsed_time, total_time, sd_global->watch_point_reached);
334   DEBUG1("current time = %f", surf_get_clock());
335
336   return changed_tasks;
337 }
338
339 /**
340  * \brief Returns the current clock
341  *
342  * \return the current clock, in second
343  */
344 double SD_get_clock(void)
345 {
346   SD_CHECK_INIT_DONE();
347
348   return surf_get_clock();
349 }
350
351 /**
352  * \brief Destroys all SD internal data
353  *
354  * This function should be called when the simulation is over. Don't forget also to destroy
355  * the tasks.
356  *
357  * \see SD_init(), SD_task_destroy()
358  */
359 void SD_exit(void)
360 {
361 #ifdef HAVE_TRACING
362   TRACE_surf_release ();
363 #endif
364   if (SD_INITIALISED()) {
365     DEBUG0("Destroying workstation and link dictionaries...");
366     xbt_dict_free(&sd_global->workstations);
367     xbt_dict_free(&sd_global->links);
368
369     DEBUG0("Destroying workstation and link arrays if necessary...");
370     if (sd_global->workstation_list != NULL)
371       xbt_free(sd_global->workstation_list);
372
373     if (sd_global->link_list != NULL)
374       xbt_free(sd_global->link_list);
375
376     if (sd_global->recyclable_route != NULL)
377       xbt_free(sd_global->recyclable_route);
378
379     DEBUG0("Destroying the swags...");
380     xbt_swag_free(sd_global->not_scheduled_task_set);
381     xbt_swag_free(sd_global->schedulable_task_set);
382     xbt_swag_free(sd_global->scheduled_task_set);
383     xbt_swag_free(sd_global->runnable_task_set);
384     xbt_swag_free(sd_global->in_fifo_task_set);
385     xbt_swag_free(sd_global->running_task_set);
386     xbt_swag_free(sd_global->done_task_set);
387     xbt_swag_free(sd_global->failed_task_set);
388
389     xbt_free(sd_global);
390     sd_global = NULL;
391
392     DEBUG0("Exiting Surf...");
393     surf_exit();
394   } else {
395     WARN0("SD_exit() called, but SimDag is not running");
396     /* we cannot use exceptions here because xbt is not running! */
397   }
398 }
399
400 /**
401  * \bried load script file
402  */
403
404 void SD_load_environment_script(const char* script_file)
405 {
406 #ifdef HAVE_LUA
407     lua_State *L = lua_open();
408     luaL_openlibs(L);
409
410     if (luaL_loadfile(L, script_file) || lua_pcall(L, 0, 0, 0)) {
411          printf("error: %s\n", lua_tostring(L, -1));
412          return;
413        }
414 #else
415     xbt_die("Lua is not available!! to call SD_load_environment_script, lua should be available...");
416 #endif
417     return;
418 }