Logo AND Algorithmique Numérique Distribuée

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