Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
63a95bce74f2c34fac27cd2ae1bed012f7dc7451
[simgrid.git] / src / simdag / sd_task.c
1 #include "private.h"
2 #include "simdag/simdag.h"
3 #include "xbt/sysdep.h"
4 #include "xbt/dynar.h"
5
6 /* Creates a task.
7  */
8 SD_task_t SD_task_create(const char *name, void *data, double amount) {
9   SD_CHECK_INIT_DONE();
10   xbt_assert0(amount > 0, "amount must be positive");
11
12   SD_task_data_t sd_data = xbt_new0(s_SD_task_data_t, 1); /* task private data */
13
14   /* general information */
15   if (name != NULL)
16     sd_data->name = xbt_strdup(name);
17   else
18     sd_data->name = NULL;
19
20   sd_data->state = SD_NOT_SCHEDULED;
21   sd_data->amount = amount;
22   sd_data->surf_action = NULL;
23   sd_data->watch_points = 0;
24
25   /* dependencies */
26   sd_data->tasks_before = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
27   sd_data->tasks_after = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
28
29   /* scheduling parameters */
30   sd_data->workstation_nb = 0;
31   sd_data->workstation_list = NULL;
32   sd_data->computation_amount = NULL;
33   sd_data->communication_amount = NULL;
34   sd_data->rate = 0;
35
36   SD_task_t task = xbt_new0(s_SD_task_t, 1);
37   task->sd_data = sd_data; /* private data */
38   task->data = data; /* user data */
39
40   return task;
41 }
42
43 /* Schedules a task.
44  * task: the task to schedule
45  * workstation_nb: number of workstations where the task will be executed
46  * workstation_list: workstations where the task will be executed
47  * computation_amount: computation amount for each workstation
48  * communication_amount: communication amount between each pair of workstations
49  * rate: task execution speed rate
50  */
51 void SD_task_schedule(SD_task_t task, int workstation_nb,
52                      const SD_workstation_t *workstation_list, double *computation_amount,
53                      double *communication_amount, double rate) {
54   SD_CHECK_INIT_DONE();
55   xbt_assert0(task, "Invalid parameter");
56   xbt_assert1(SD_task_get_state(task) == SD_NOT_SCHEDULED, "Task '%s' has already been scheduled.", SD_task_get_name(task));
57   xbt_assert0(workstation_nb > 0, "workstation_nb must be positive");
58
59   SD_task_data_t sd_data = task->sd_data;
60   sd_data->workstation_nb = workstation_nb;
61   sd_data->rate = rate;
62
63   sd_data->computation_amount = xbt_new0(double, workstation_nb);
64   memcpy(sd_data->computation_amount, computation_amount, sizeof(double) * workstation_nb);
65
66   int communication_nb = workstation_nb * workstation_nb;
67   sd_data->communication_amount = xbt_new0(double, communication_nb);
68   memcpy(sd_data->communication_amount, communication_amount, sizeof(double) * communication_nb);
69
70   /* we have to create a Surf workstation array instead of the SimDag workstation array */
71   sd_data->workstation_list = xbt_new0(void*, workstation_nb);
72   int i;
73   for (i = 0; i < workstation_nb; i++) {
74     sd_data->workstation_list[i] = workstation_list[i]->sd_data->surf_workstation;
75   }
76
77   sd_data->state = SD_SCHEDULED;
78 }
79
80 /* Returns the data of a task.
81  */
82 void* SD_task_get_data(SD_task_t task) {
83   SD_CHECK_INIT_DONE();
84   xbt_assert0(task != NULL, "Invalid parameter");
85   return task->data;
86 }
87
88 /* Sets the data of a task.
89  */
90 void SD_task_set_data(SD_task_t task, void *data) {
91   SD_CHECK_INIT_DONE();
92   xbt_assert0(task != NULL, "Invalid parameter");
93   task->data = data;
94 }
95
96 /* Returns the name of a task. The name can be NULL.
97  */
98 const char* SD_task_get_name(SD_task_t task) {
99   SD_CHECK_INIT_DONE();
100   xbt_assert0(task != NULL, "Invalid parameter");
101   return task->sd_data->name;
102 }
103
104 /* Returns the computing amount of a task.
105  */
106 double SD_task_get_amount(SD_task_t task) {
107   SD_CHECK_INIT_DONE();
108   xbt_assert0(task != NULL, "Invalid parameter");
109   return task->sd_data->amount;
110 }
111
112 /* Returns the remaining computing amount of a task.
113  */
114 double SD_task_get_remaining_amount(SD_task_t task) {
115   SD_CHECK_INIT_DONE();
116   xbt_assert0(task != NULL, "Invalid parameter");
117   SD_task_data_t sd_data = task->sd_data;
118   if (sd_data->surf_action)
119     return sd_data->amount;
120   else
121     return sd_data->surf_action->remains;
122 }
123
124 /* temporary function for debbuging */
125 void __SD_print_dependencies(SD_task_t task) {
126   printf("The following tasks must be executed before %s:", SD_task_get_name(task));
127   xbt_dynar_t dynar = task->sd_data->tasks_before;
128   int length = xbt_dynar_length(dynar);
129   int i;
130   SD_dependency_t dependency;
131   for (i = 0; i < length; i++) {
132     xbt_dynar_get_cpy(dynar, i, &dependency);
133     printf(" %s", SD_task_get_name(dependency->src));
134   }
135
136   printf("\nThe following tasks must be executed after %s:", SD_task_get_name(task));
137
138   dynar = task->sd_data->tasks_after;
139   length = xbt_dynar_length(dynar);
140   for (i = 0; i < length; i++) {
141     xbt_dynar_get_ptr(dynar, i, &dependency);
142     printf(" %s", SD_task_get_name(dependency->dst));
143   }
144   printf("\n----------------------------\n");
145 }
146
147 /* Adds a dependency between two tasks.
148  */
149 void SD_task_dependency_add(const char *name, void *data, SD_task_t src, SD_task_t dst) {
150   SD_CHECK_INIT_DONE();
151   xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
152   xbt_assert1(src != dst, "Cannot add a dependency between task '%s' and itself", SD_task_get_name(src));
153
154   xbt_dynar_t dynar = src->sd_data->tasks_after;
155   int length = xbt_dynar_length(dynar);
156   int found = 0;
157   int i;
158   SD_dependency_t dependency;
159   for (i = 0; i < length && !found; i++) {
160     xbt_dynar_get_cpy(dynar, i, &dependency);
161     if (dependency->src == src && dependency->dst == dst) {
162       found = 1;
163     }
164   }
165   xbt_assert2(!found, "A dependency already exists between task '%s' and task '%s'", src->sd_data->name, dst->sd_data->name);
166
167   dependency = xbt_new0(s_SD_dependency_t, 1);
168
169   if (name != NULL)
170     dependency->name = xbt_strdup(name);
171   dependency->data = data;
172   dependency->src = src;
173   dependency->dst = dst;
174
175   /* src must be executed before dst */
176   xbt_dynar_push(src->sd_data->tasks_after, &dependency);
177   xbt_dynar_push(dst->sd_data->tasks_before, &dependency);
178
179   /*  __SD_print_dependencies(src);
180       __SD_print_dependencies(dst);*/
181 }
182
183 /* Removes a dependency between two tasks.
184  */
185 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst) {
186   SD_CHECK_INIT_DONE();
187   xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
188   xbt_assert1(src != dst, "Cannot remove a dependency between task '%s' and itself", SD_task_get_name(src));
189
190   xbt_dynar_t dynar = src->sd_data->tasks_after;
191   int length = xbt_dynar_length(dynar);
192   int found = 0;
193   int i;
194   SD_dependency_t dependency;
195   for (i = 0; i < length && !found; i++) {
196     xbt_dynar_get_cpy(dynar, i, &dependency);
197     if (dependency->src == src && dependency->dst == dst) {
198       xbt_dynar_remove_at(dynar, i, NULL);
199       found = 1;
200     }
201   }
202   xbt_assert4(found, "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
203               src->sd_data->name, dst->sd_data->name, dst->sd_data->name, src->sd_data->name);
204
205   dynar = dst->sd_data->tasks_before;
206   length = xbt_dynar_length(dynar);
207   found = 0;
208   
209   for (i = 0; i < length && !found; i++) {
210     xbt_dynar_get_cpy(dynar, i, &dependency);
211     if (dependency->src == src && dependency->dst == dst) {
212       xbt_dynar_remove_at(dynar, i, NULL);
213       __SD_task_destroy_dependency(dependency);
214       found = 1;
215     }
216   }
217   xbt_assert4(found, "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
218               dst->sd_data->name, src->sd_data->name, src->sd_data->name, dst->sd_data->name); /* should never happen... */
219
220   /*  __SD_print_dependencies(src);
221       __SD_print_dependencies(dst);*/
222 }
223
224 /* Returns the state of a task: SD_NOT_SCHEDULED, SD_SCHEDULED, SD_RUNNING, SD_DONE or SD_FAILED.
225  */
226 SD_task_state_t SD_task_get_state(SD_task_t task) {
227   SD_CHECK_INIT_DONE();
228   xbt_assert0(task != NULL, "Invalid parameter");
229   return task->sd_data->state;
230 }
231
232 /* temporary function for debugging */
233 void __SD_print_watch_points(SD_task_t task) {
234   static const int state_masks[] = {SD_SCHEDULED, SD_RUNNING, SD_DONE, SD_FAILED};
235   static const char* state_names[] = {"scheduled", "running", "done", "failed"};
236
237   printf("Task '%s' watch points (%x): ", task->sd_data->name, task->sd_data->watch_points);
238
239   int i;
240   for (i = 0; i < 4; i++) {
241     if (task->sd_data->watch_points & state_masks[i])
242       printf("%s ", state_names[i]);
243   }
244   printf("\n");
245 }
246
247 /* Adds a watch point to a task.
248    SD_simulate will stop as soon as the state of this task is the one given in argument.
249    Watch point is then automatically removed.
250  */
251 void SD_task_watch(SD_task_t task, SD_task_state_t state) {
252   SD_CHECK_INIT_DONE();
253   xbt_assert0(task != NULL, "Invalid parameter");
254
255   task->sd_data->watch_points = task->sd_data->watch_points | state;
256   __SD_print_watch_points(task);
257 }
258
259 /* Removes a watch point from a task.
260  */
261 void SD_task_unwatch(SD_task_t task, SD_task_state_t state) {
262   SD_CHECK_INIT_DONE();
263   xbt_assert0(task != NULL, "Invalid parameter");
264   
265   task->sd_data->watch_points = task->sd_data->watch_points & ~state;
266   __SD_print_watch_points(task);
267 }
268
269 /* Unschedules a task. The state must be SD_SCHEDULED, SD_RUNNING or SD_FAILED.
270  * The task is reinitialised and its state becomes SD_NOT_SCHEDULED.
271  * Call SD_task_schedule to schedule it again.
272  */
273 void SD_task_unschedule(SD_task_t task) {
274   SD_CHECK_INIT_DONE();
275   xbt_assert0(task != NULL, "Invalid parameter");
276   xbt_assert1(task->sd_data->state == SD_SCHEDULED ||
277               task->sd_data->state == SD_RUNNING ||
278               task->sd_data->state == SD_FAILED,
279               "Task %s: the state must be SD_SCHEDULED, SD_RUNNING or SD_FAILED", task->sd_data->name);
280
281   if (task->sd_data->state == SD_SCHEDULED)
282     __SD_task_destroy_scheduling_data(task);
283
284   task->sd_data->state = SD_NOT_SCHEDULED;
285 }
286
287 /* Runs a task. This function is called by SD_simulate when a scheduled task can start
288  * (ie when its dependencies are satisfied).
289  */
290 void __SD_task_run(SD_task_t task) {
291   SD_CHECK_INIT_DONE();
292   xbt_assert0(task != NULL, "Invalid parameter");
293
294   SD_task_data_t sd_data = task->sd_data;
295   surf_workstation_resource->extension_public->
296     execute_parallel_task(sd_data->workstation_nb,
297                           sd_data->workstation_list,
298                           sd_data->computation_amount,
299                           sd_data->communication_amount,
300                           sd_data->amount,
301                           sd_data->rate);
302   task->sd_data->state = SD_RUNNING;
303
304   __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
305 }
306
307
308 /* Destroys a task. The user data (if any) should have been destroyed first.
309  */
310 void SD_task_destroy(SD_task_t task) {
311   SD_CHECK_INIT_DONE();
312   xbt_assert0(task != NULL, "Invalid parameter");
313
314   /*  printf("Destroying task %s...\n", SD_task_get_name(task));*/
315
316   /* we must destroy the dependencies carefuly (with SD_dependency_remove)
317      because each one is stored twice */
318   SD_dependency_t dependency;
319   while (xbt_dynar_length(task->sd_data->tasks_before) > 0) {
320     xbt_dynar_get_cpy(task->sd_data->tasks_before, 0, &dependency);
321     SD_task_dependency_remove(dependency->src, dependency->dst);
322   }
323
324   while (xbt_dynar_length(task->sd_data->tasks_after) > 0) {
325     xbt_dynar_get_cpy(task->sd_data->tasks_after, 0, &dependency);
326     SD_task_dependency_remove(dependency->src, dependency->dst);
327   }
328
329   if (task->sd_data->state == SD_SCHEDULED)
330     __SD_task_destroy_scheduling_data(task);
331
332   if (task->sd_data->name != NULL)
333     xbt_free(task->sd_data->name);
334
335   xbt_dynar_free(&task->sd_data->tasks_before);
336   xbt_dynar_free(&task->sd_data->tasks_after);
337   xbt_free(task->sd_data);
338   xbt_free(task);
339
340   /*printf("Task destroyed.\n");*/
341
342 }
343
344 /* Destroys the data memorised by SD_task_schedule. Task state must be SD_SCHEDULED.
345  */
346 void __SD_task_destroy_scheduling_data(SD_task_t task) {
347   xbt_free(task->sd_data->workstation_list);
348   xbt_free(task->sd_data->computation_amount);
349   xbt_free(task->sd_data->communication_amount);
350 }
351
352 /* Destroys a dependency between two tasks.
353  */
354 void __SD_task_destroy_dependency(void *dependency) {
355   if (((SD_dependency_t) dependency)->name != NULL)
356     xbt_free(((SD_dependency_t) dependency)->name);
357   /*printf("destroying dependency between %s and %s\n", ((SD_dependency_t) dependency)->src->sd_data->name, ((SD_dependency_t) dependency)->dst->sd_data->name);*/
358   xbt_free(dependency);
359   /*printf("destroyed.\n");*/
360 }