Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add a function SD_task_dependency_get_data and improve some code
[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_cpy(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     found = (dependency->dst == dst);
162   }
163   xbt_assert2(!found, "A dependency already exists between task '%s' and task '%s'", src->sd_data->name, dst->sd_data->name);
164
165   dependency = xbt_new0(s_SD_dependency_t, 1);
166
167   if (name != NULL)
168     dependency->name = xbt_strdup(name);
169   dependency->data = data;
170   dependency->src = src;
171   dependency->dst = dst;
172
173   /* src must be executed before dst */
174   xbt_dynar_push(src->sd_data->tasks_after, &dependency);
175   xbt_dynar_push(dst->sd_data->tasks_before, &dependency);
176
177   /*  __SD_print_dependencies(src);
178       __SD_print_dependencies(dst); */
179 }
180
181 /* Removes a dependency between two tasks.
182  */
183 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst) {
184   SD_CHECK_INIT_DONE();
185   xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
186   xbt_assert1(src != dst, "Cannot remove a dependency between task '%s' and itself", SD_task_get_name(src));
187
188   xbt_dynar_t dynar = src->sd_data->tasks_after;
189   int length = xbt_dynar_length(dynar);
190   int found = 0;
191   int i;
192   SD_dependency_t dependency;
193   for (i = 0; i < length && !found; i++) {
194     xbt_dynar_get_cpy(dynar, i, &dependency);
195     if (dependency->dst == dst) {
196       xbt_dynar_remove_at(dynar, i, NULL);
197       found = 1;
198     }
199   }
200   xbt_assert4(found, "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
201               src->sd_data->name, dst->sd_data->name, dst->sd_data->name, src->sd_data->name);
202
203   dynar = dst->sd_data->tasks_before;
204   length = xbt_dynar_length(dynar);
205   found = 0;
206   
207   for (i = 0; i < length && !found; i++) {
208     xbt_dynar_get_cpy(dynar, i, &dependency);
209     if (dependency->src == src) {
210       xbt_dynar_remove_at(dynar, i, NULL);
211       __SD_task_destroy_dependency(dependency);
212       found = 1;
213     }
214   }
215   xbt_assert4(found, "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
216               dst->sd_data->name, src->sd_data->name, src->sd_data->name, dst->sd_data->name); /* should never happen... */
217
218 /*   __SD_print_dependencies(src); 
219      __SD_print_dependencies(dst); */
220 }
221
222 /* Returns the data associated to a dependency between two tasks. This data can be NULL.
223  */
224 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst) {
225   SD_CHECK_INIT_DONE();
226   xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
227   xbt_assert1(src != dst, "Cannot have a dependency between task '%s' and itself", SD_task_get_name(src));
228
229   xbt_dynar_t dynar = src->sd_data->tasks_after;
230   int length = xbt_dynar_length(dynar);
231   int found = 0;
232   int i;
233   SD_dependency_t dependency;
234   for (i = 0; i < length && !found; i++) {
235     xbt_dynar_get_cpy(dynar, i, &dependency);
236     found = (dependency->dst == dst);
237   }
238   xbt_assert4(found, "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
239               src->sd_data->name, dst->sd_data->name, dst->sd_data->name, src->sd_data->name);
240   return dependency->data;
241 }
242
243 /* Returns the state of a task: SD_NOT_SCHEDULED, SD_SCHEDULED, SD_RUNNING, SD_DONE or SD_FAILED.
244  */
245 SD_task_state_t SD_task_get_state(SD_task_t task) {
246   SD_CHECK_INIT_DONE();
247   xbt_assert0(task != NULL, "Invalid parameter");
248   return task->sd_data->state;
249 }
250
251 /* temporary function for debugging */
252 void __SD_print_watch_points(SD_task_t task) {
253   static const int state_masks[] = {SD_SCHEDULED, SD_RUNNING, SD_DONE, SD_FAILED};
254   static const char* state_names[] = {"scheduled", "running", "done", "failed"};
255
256   printf("Task '%s' watch points (%x): ", task->sd_data->name, task->sd_data->watch_points);
257
258   int i;
259   for (i = 0; i < 4; i++) {
260     if (task->sd_data->watch_points & state_masks[i])
261       printf("%s ", state_names[i]);
262   }
263   printf("\n");
264 }
265
266 /* Adds a watch point to a task.
267    SD_simulate will stop as soon as the state of this task is the one given in argument.
268    Watch point is then automatically removed.
269  */
270 void SD_task_watch(SD_task_t task, SD_task_state_t state) {
271   SD_CHECK_INIT_DONE();
272   xbt_assert0(task != NULL, "Invalid parameter");
273
274   task->sd_data->watch_points = task->sd_data->watch_points | state;
275   __SD_print_watch_points(task);
276 }
277
278 /* Removes a watch point from a task.
279  */
280 void SD_task_unwatch(SD_task_t task, SD_task_state_t state) {
281   SD_CHECK_INIT_DONE();
282   xbt_assert0(task != NULL, "Invalid parameter");
283   
284   task->sd_data->watch_points = task->sd_data->watch_points & ~state;
285   __SD_print_watch_points(task);
286 }
287
288 /* Unschedules a task. The state must be SD_SCHEDULED, SD_RUNNING or SD_FAILED.
289  * The task is reinitialised and its state becomes SD_NOT_SCHEDULED.
290  * Call SD_task_schedule to schedule it again.
291  */
292 void SD_task_unschedule(SD_task_t task) {
293   SD_CHECK_INIT_DONE();
294   xbt_assert0(task != NULL, "Invalid parameter");
295   xbt_assert1(task->sd_data->state == SD_SCHEDULED ||
296               task->sd_data->state == SD_RUNNING ||
297               task->sd_data->state == SD_FAILED,
298               "Task %s: the state must be SD_SCHEDULED, SD_RUNNING or SD_FAILED", task->sd_data->name);
299
300   if (task->sd_data->state == SD_SCHEDULED)
301     __SD_task_destroy_scheduling_data(task);
302
303   task->sd_data->state = SD_NOT_SCHEDULED;
304 }
305
306 /* Runs a task. This function is called by SD_simulate when a scheduled task can start
307  * (ie when its dependencies are satisfied).
308  */
309 void __SD_task_run(SD_task_t task) {
310   SD_CHECK_INIT_DONE();
311   xbt_assert0(task != NULL, "Invalid parameter");
312
313   SD_task_data_t sd_data = task->sd_data;
314   surf_workstation_resource->extension_public->
315     execute_parallel_task(sd_data->workstation_nb,
316                           sd_data->workstation_list,
317                           sd_data->computation_amount,
318                           sd_data->communication_amount,
319                           sd_data->amount,
320                           sd_data->rate);
321   task->sd_data->state = SD_RUNNING;
322
323   __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
324 }
325
326
327 /* Destroys a task. The user data (if any) should have been destroyed first.
328  */
329 void SD_task_destroy(SD_task_t task) {
330   SD_CHECK_INIT_DONE();
331   xbt_assert0(task != NULL, "Invalid parameter");
332
333   /*  printf("Destroying task %s...\n", SD_task_get_name(task));*/
334
335   /* we must destroy the dependencies carefuly (with SD_dependency_remove)
336      because each one is stored twice */
337   SD_dependency_t dependency;
338   while (xbt_dynar_length(task->sd_data->tasks_before) > 0) {
339     xbt_dynar_get_cpy(task->sd_data->tasks_before, 0, &dependency);
340     SD_task_dependency_remove(dependency->src, dependency->dst);
341   }
342
343   while (xbt_dynar_length(task->sd_data->tasks_after) > 0) {
344     xbt_dynar_get_cpy(task->sd_data->tasks_after, 0, &dependency);
345     SD_task_dependency_remove(dependency->src, dependency->dst);
346   }
347
348   if (task->sd_data->state == SD_SCHEDULED)
349     __SD_task_destroy_scheduling_data(task);
350
351   if (task->sd_data->name != NULL)
352     xbt_free(task->sd_data->name);
353
354   xbt_dynar_free(&task->sd_data->tasks_before);
355   xbt_dynar_free(&task->sd_data->tasks_after);
356   xbt_free(task->sd_data);
357   xbt_free(task);
358
359   /*printf("Task destroyed.\n");*/
360
361 }
362
363 /* Destroys the data memorised by SD_task_schedule. Task state must be SD_SCHEDULED.
364  */
365 void __SD_task_destroy_scheduling_data(SD_task_t task) {
366   xbt_free(task->sd_data->workstation_list);
367   xbt_free(task->sd_data->computation_amount);
368   xbt_free(task->sd_data->communication_amount);
369 }
370
371 /* Destroys a dependency between two tasks.
372  */
373 void __SD_task_destroy_dependency(void *dependency) {
374   if (((SD_dependency_t) dependency)->name != NULL)
375     xbt_free(((SD_dependency_t) dependency)->name);
376   /*printf("destroying dependency between %s and %s\n", ((SD_dependency_t) dependency)->src->sd_data->name, ((SD_dependency_t) dependency)->dst->sd_data->name);*/
377   xbt_free(dependency);
378   /*printf("destroyed.\n");*/
379 }