Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
xbt_swag_foreach_safe is actually needed here.
[simgrid.git] / src / simdag / sd_task.c
1 /* Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011. 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 "simdag/simdag.h"
9 #include "xbt/sysdep.h"
10 #include "xbt/dynar.h"
11 #include "instr/instr_private.h"
12
13 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_task, sd,
14                                 "Logging specific to SimDag (task)");
15
16 static void __SD_task_remove_dependencies(SD_task_t task);
17 static void __SD_task_destroy_scheduling_data(SD_task_t task);
18
19 void* SD_task_new_f(void) {
20   SD_task_t task = xbt_new0(s_SD_task_t, 1);
21   task->tasks_before = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
22   task->tasks_after = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
23
24   return task;
25 }
26 void SD_task_recycle_f(void *t) {
27   SD_task_t task = (SD_task_t)t;
28
29   __SD_task_remove_dependencies(task);
30   /* if the task was scheduled or runnable we have to free the scheduling parameters */
31   if (__SD_task_is_scheduled_or_runnable(task))
32     __SD_task_destroy_scheduling_data(task);
33   if (task->state_set != NULL) {/* would be null if just created */
34     xbt_swag_remove(task, task->state_set);
35   }
36   xbt_swag_remove(task, sd_global->return_set);
37
38   if (task->name != NULL)
39     xbt_free(task->name);
40
41   if (task->surf_action != NULL)
42     surf_workstation_model->action_unref(task->surf_action);
43
44   if (task->workstation_list != NULL)
45     xbt_free(task->workstation_list);
46
47   if (task->communication_amount)
48     xbt_free(task->communication_amount);
49
50   if (task->computation_amount)
51     xbt_free(task->computation_amount);
52
53   /* Reset the content */
54   task->kind = SD_TASK_NOT_TYPED;
55   task->state_hookup.prev = NULL;
56   task->state_hookup.next = NULL;
57   task->state_set = sd_global->not_scheduled_task_set;
58   xbt_swag_insert(task, task->state_set);
59   task->state = SD_NOT_SCHEDULED;
60   task->return_hookup.prev = NULL;
61   task->return_hookup.next = NULL;
62
63   task->marked = 0;
64
65   task->start_time = -1.0;
66   task->finish_time = -1.0;
67   task->surf_action = NULL;
68   task->watch_points = 0;
69
70   /* dependencies */
71   xbt_dynar_reset(task->tasks_before); // =  new(sizeof(SD_dependency_t), NULL);
72   xbt_dynar_reset(task->tasks_after);  // = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
73   task->unsatisfied_dependencies = 0;
74   task->is_not_ready = 0;
75
76   /* scheduling parameters */
77   task->workstation_nb = 0;
78   task->workstation_list = NULL;
79   task->computation_amount = NULL;
80   task->communication_amount = NULL;
81   task->rate = -1;
82
83 #ifdef HAVE_TRACING
84   TRACE_sd_task_create(task);
85 #endif
86 }
87 void SD_task_free_f(void *t) {
88   SD_task_t task = (SD_task_t)t;
89
90   __SD_task_remove_dependencies(task);
91   /* if the task was scheduled or runnable we have to free the scheduling parameters */
92   if (__SD_task_is_scheduled_or_runnable(task))
93     __SD_task_destroy_scheduling_data(task);
94   if (task->state_set != NULL) /* would be null if just created */
95     xbt_swag_remove(task, task->state_set);
96
97   xbt_swag_remove(task, sd_global->return_set);
98
99   if (task->name != NULL)
100     xbt_free(task->name);
101
102   if (task->surf_action != NULL)
103     surf_workstation_model->action_unref(task->surf_action);
104
105   if (task->workstation_list != NULL)
106     xbt_free(task->workstation_list);
107
108   if (task->communication_amount)
109     xbt_free(task->communication_amount);
110
111   if (task->computation_amount)
112     xbt_free(task->computation_amount);
113 #ifdef HAVE_TRACING
114   TRACE_sd_task_destroy(task);
115 #endif
116
117   xbt_dynar_free(&task->tasks_before);
118   xbt_dynar_free(&task->tasks_after);
119   xbt_free(task);
120 }
121
122
123 /**
124  * \brief Creates a new task.
125  *
126  * \param name the name of the task (can be \c NULL)
127  * \param data the user data you want to associate with the task (can be \c NULL)
128  * \param amount amount of the task
129  * \return the new task
130  * \see SD_task_destroy()
131  */
132 SD_task_t SD_task_create(const char *name, void *data, double amount)
133 {
134   SD_task_t task = xbt_mallocator_get(sd_global->task_mallocator);
135
136   /* general information */
137   task->data = data;            /* user data */
138   task->name = xbt_strdup(name);
139   task->amount = amount;
140   task->remains = amount;
141
142   sd_global->task_number++;
143
144   return task;
145 }
146 /**
147  * \brief Destroys a task.
148  *
149  * The user data (if any) should have been destroyed first.
150  *
151  * \param task the task you want to destroy
152  * \see SD_task_create()
153  */
154 void SD_task_destroy(SD_task_t task)
155 {
156   XBT_DEBUG("Destroying task %s...", SD_task_get_name(task));
157
158   xbt_mallocator_release(sd_global->task_mallocator,task);
159   sd_global->task_number--;
160
161   XBT_DEBUG("Task destroyed.");
162 }
163
164
165 /**
166  * \brief Returns the user data of a task
167  *
168  * \param task a task
169  * \return the user data associated with this task (can be \c NULL)
170  * \see SD_task_set_data()
171  */
172 void *SD_task_get_data(SD_task_t task)
173 {
174   return task->data;
175 }
176
177 /**
178  * \brief Sets the user data of a task
179  *
180  * The new data can be \c NULL. The old data should have been freed first
181  * if it was not \c NULL.
182  *
183  * \param task a task
184  * \param data the new data you want to associate with this task
185  * \see SD_task_get_data()
186  */
187 void SD_task_set_data(SD_task_t task, void *data)
188 {
189   task->data = data;
190 }
191
192 /**
193  * \brief Returns the state of a task
194  *
195  * \param task a task
196  * \return the current \ref e_SD_task_state_t "state" of this task:
197  * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING, #SD_DONE or #SD_FAILED
198  * \see e_SD_task_state_t
199  */
200 e_SD_task_state_t SD_task_get_state(SD_task_t task)
201 {
202   return task->state;
203 }
204
205 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
206  */
207 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
208 {
209   xbt_swag_remove(task, task->state_set);
210   switch (new_state) {
211   case SD_NOT_SCHEDULED:
212     task->state_set = sd_global->not_scheduled_task_set;
213     break;
214   case SD_SCHEDULABLE:
215     task->state_set = sd_global->schedulable_task_set;
216     break;
217   case SD_SCHEDULED:
218     task->state_set = sd_global->scheduled_task_set;
219     break;
220   case SD_RUNNABLE:
221     task->state_set = sd_global->runnable_task_set;
222     break;
223   case SD_IN_FIFO:
224     task->state_set = sd_global->in_fifo_task_set;
225     break;
226   case SD_RUNNING:
227     task->state_set = sd_global->running_task_set;
228     task->start_time =
229         surf_workstation_model->action_get_start_time(task->surf_action);
230     break;
231   case SD_DONE:
232     task->state_set = sd_global->done_task_set;
233     task->finish_time =
234         surf_workstation_model->action_get_finish_time(task->surf_action);
235     task->remains = 0;
236 #ifdef HAVE_JEDULE
237     jedule_log_sd_event(task);
238 #endif
239     break;
240   case SD_FAILED:
241     task->state_set = sd_global->failed_task_set;
242     break;
243   default:
244     xbt_die( "Invalid state");
245   }
246   xbt_swag_insert(task, task->state_set);
247   task->state = new_state;
248
249   if (task->watch_points & new_state) {
250     XBT_VERB("Watch point reached with task '%s'!", SD_task_get_name(task));
251     sd_global->watch_point_reached = 1;
252     SD_task_unwatch(task, new_state);   /* remove the watch point */
253   }
254 }
255
256 /**
257  * \brief Returns the name of a task
258  *
259  * \param task a task
260  * \return the name of this task (can be \c NULL)
261  */
262 const char *SD_task_get_name(SD_task_t task)
263 {
264   return task->name;
265 }
266
267 /** @brief Allows to change the name of a task */
268 void SD_task_set_name(SD_task_t task, const char *name)
269 {
270   xbt_free(task->name);
271   task->name = xbt_strdup(name);
272 }
273
274 /** @brief Returns the dynar of the parents of a task
275  *
276  * \param task a task
277  * \return a newly allocated dynar comprising the parents of this task
278  */
279
280 xbt_dynar_t SD_task_get_parents(SD_task_t task)
281 {
282   unsigned int i;
283   xbt_dynar_t parents;
284   SD_dependency_t dep;
285
286   parents = xbt_dynar_new(sizeof(SD_task_t), NULL);
287   xbt_dynar_foreach(task->tasks_before, i, dep) {
288     xbt_dynar_push(parents, &(dep->src));
289   }
290   return parents;
291 }
292
293 /** @brief Returns the dynar of the parents of a task
294  *
295  * \param task a task
296  * \return a newly allocated dynar comprising the parents of this task
297  */
298 xbt_dynar_t SD_task_get_children(SD_task_t task)
299 {
300   unsigned int i;
301   xbt_dynar_t children;
302   SD_dependency_t dep;
303
304   children = xbt_dynar_new(sizeof(SD_task_t), NULL);
305   xbt_dynar_foreach(task->tasks_after, i, dep) {
306     xbt_dynar_push(children, &(dep->dst));
307   }
308   return children;
309 }
310
311 /**
312  * \brief Returns the amount of workstations involved in a task
313  *
314  * Only call this on already scheduled tasks!
315  * \param task a task
316  */
317 int SD_task_get_workstation_count(SD_task_t task)
318 {
319   return task->workstation_nb;
320 }
321
322 /**
323  * \brief Returns the list of workstations involved in a task
324  *
325  * Only call this on already scheduled tasks!
326  * \param task a task
327  */
328 SD_workstation_t *SD_task_get_workstation_list(SD_task_t task)
329 {
330   return task->workstation_list;
331 }
332
333 /**
334  * \brief Returns the total amount of work contained in a task
335  *
336  * \param task a task
337  * \return the total amount of work (computation or data transfer) for this task
338  * \see SD_task_get_remaining_amount()
339  */
340 double SD_task_get_amount(SD_task_t task)
341 {
342   return task->amount;
343 }
344
345 /**
346  * \brief Returns the remaining amount work to do till the completion of a task
347  *
348  * \param task a task
349  * \return the remaining amount of work (computation or data transfer) of this task
350  * \see SD_task_get_amount()
351  */
352 double SD_task_get_remaining_amount(SD_task_t task)
353 {
354   if (task->surf_action)
355     return surf_workstation_model->get_remains(task->surf_action);
356   else
357     return task->remains;
358 }
359
360 int SD_task_get_kind(SD_task_t task)
361 {
362   return task->kind;
363 }
364
365 /** @brief Displays debugging informations about a task */
366 void SD_task_dump(SD_task_t task)
367 {
368   unsigned int counter;
369   SD_dependency_t dependency;
370   char *statename;
371
372   XBT_INFO("Displaying task %s", SD_task_get_name(task));
373   statename = bprintf("%s %s %s %s %s %s %s %s",
374                       (task->state & SD_NOT_SCHEDULED ? "not scheduled" :
375                        ""),
376                       (task->state & SD_SCHEDULABLE ? "schedulable" : ""),
377                       (task->state & SD_SCHEDULED ? "scheduled" : ""),
378                       (task->state & SD_RUNNABLE ? "runnable" :
379                        "not runnable"),
380                       (task->state & SD_IN_FIFO ? "in fifo" : ""),
381                       (task->state & SD_RUNNING ? "running" : ""),
382                       (task->state & SD_DONE ? "done" : ""),
383                       (task->state & SD_FAILED ? "failed" : ""));
384   XBT_INFO("  - state: %s", statename);
385   free(statename);
386
387   if (task->kind != 0) {
388     switch (task->kind) {
389     case SD_TASK_COMM_E2E:
390       XBT_INFO("  - kind: end-to-end communication");
391       break;
392     case SD_TASK_COMP_SEQ:
393       XBT_INFO("  - kind: sequential computation");
394       break;
395     default:
396       XBT_INFO("  - (unknown kind %d)", task->kind);
397     }
398   }
399   XBT_INFO("  - amount: %.0f", SD_task_get_amount(task));
400   XBT_INFO("  - Dependencies to satisfy: %d", task->unsatisfied_dependencies);
401   if (xbt_dynar_length(task->tasks_before)) {
402     XBT_INFO("  - pre-dependencies:");
403     xbt_dynar_foreach(task->tasks_before, counter, dependency) {
404       XBT_INFO("    %s", SD_task_get_name(dependency->src));
405     }
406   }
407   if (xbt_dynar_length(task->tasks_after)) {
408     XBT_INFO("  - post-dependencies:");
409     xbt_dynar_foreach(task->tasks_after, counter, dependency) {
410       XBT_INFO("    %s", SD_task_get_name(dependency->dst));
411     }
412   }
413 }
414
415 /** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */
416 void SD_task_dotty(SD_task_t task, void *out)
417 {
418   unsigned int counter;
419   SD_dependency_t dependency;
420   fprintf(out, "  T%p [label=\"%.20s\"", task, task->name);
421   switch (task->kind) {
422   case SD_TASK_COMM_E2E:
423     fprintf(out, ", shape=box");
424     break;
425   case SD_TASK_COMP_SEQ:
426     fprintf(out, ", shape=circle");
427     break;
428   default:
429     xbt_die("Unknown task type!");
430   }
431   fprintf(out, "];\n");
432   xbt_dynar_foreach(task->tasks_before, counter, dependency) {
433     fprintf(out, " T%p -> T%p;\n", dependency->src, dependency->dst);
434   }
435 }
436
437 /* Destroys a dependency between two tasks.
438  */
439 static void __SD_task_dependency_destroy(void *dependency)
440 {
441   if (((SD_dependency_t) dependency)->name != NULL)
442     xbt_free(((SD_dependency_t) dependency)->name);
443   xbt_free(dependency);
444 }
445
446 /**
447  * \brief Adds a dependency between two tasks
448  *
449  * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
450  * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_RUNNABLE.
451  *
452  * \param name the name of the new dependency (can be \c NULL)
453  * \param data the user data you want to associate with this dependency (can be \c NULL)
454  * \param src the task which must be executed first
455  * \param dst the task you want to make depend on \a src
456  * \see SD_task_dependency_remove()
457  */
458 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
459                             SD_task_t dst)
460 {
461   xbt_dynar_t dynar;
462   int length;
463   int found = 0;
464   int i;
465   SD_dependency_t dependency;
466
467   dynar = src->tasks_after;
468   length = xbt_dynar_length(dynar);
469
470   if (src == dst)
471     THROWF(arg_error, 0,
472            "Cannot add a dependency between task '%s' and itself",
473            SD_task_get_name(src));
474
475   if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_schedulable(src)
476       && !__SD_task_is_scheduled_or_runnable(src))
477     THROWF(arg_error, 0,
478            "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE",
479            SD_task_get_name(src));
480
481   if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_schedulable(dst)
482       && !__SD_task_is_scheduled_or_runnable(dst))
483     THROWF(arg_error, 0,
484            "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE",
485            SD_task_get_name(dst));
486
487   XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s",
488          SD_task_get_name(src), SD_task_get_name(dst));
489   for (i = 0; i < length && !found; i++) {
490     xbt_dynar_get_cpy(dynar, i, &dependency);
491     found = (dependency->dst == dst);
492     XBT_DEBUG("Dependency %d: dependency->dst = %s", i,
493            SD_task_get_name(dependency->dst));
494   }
495
496   if (found)
497     THROWF(arg_error, 0,
498            "A dependency already exists between task '%s' and task '%s'",
499            SD_task_get_name(src), SD_task_get_name(dst));
500
501   dependency = xbt_new(s_SD_dependency_t, 1);
502
503   dependency->name = xbt_strdup(name);  /* xbt_strdup is cleaver enough to deal with NULL args itself */
504   dependency->data = data;
505   dependency->src = src;
506   dependency->dst = dst;
507
508   /* src must be executed before dst */
509   xbt_dynar_push(src->tasks_after, &dependency);
510   xbt_dynar_push(dst->tasks_before, &dependency);
511
512   dst->unsatisfied_dependencies++;
513   dst->is_not_ready++;
514
515   /* if the task was runnable, then dst->tasks_before is not empty anymore,
516      so we must go back to state SD_SCHEDULED */
517   if (__SD_task_is_runnable(dst)) {
518     XBT_DEBUG
519         ("SD_task_dependency_add: %s was runnable and becomes scheduled!",
520          SD_task_get_name(dst));
521     __SD_task_set_state(dst, SD_SCHEDULED);
522   }
523
524   /*  __SD_print_dependencies(src);
525      __SD_print_dependencies(dst); */
526 }
527
528 /**
529  * \brief Indacates whether there is a dependency between two tasks.
530  *
531  * \param src a task
532  * \param dst a task depending on \a src
533  *
534  * If src is NULL, checks whether dst has any pre-dependency.
535  * If dst is NULL, checks whether src has any post-dependency.
536  */
537 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
538 {
539   unsigned int counter;
540   SD_dependency_t dependency;
541
542   xbt_assert(src != NULL
543               || dst != NULL,
544               "Invalid parameter: both src and dst are NULL");
545
546   if (src) {
547     if (dst) {
548       xbt_dynar_foreach(src->tasks_after, counter, dependency) {
549         if (dependency->dst == dst)
550           return 1;
551       }
552     } else {
553       return xbt_dynar_length(src->tasks_after);
554     }
555   } else {
556     return xbt_dynar_length(dst->tasks_before);
557   }
558   return 0;
559 }
560
561 /**
562  * \brief Remove a dependency between two tasks
563  *
564  * \param src a task
565  * \param dst a task depending on \a src
566  * \see SD_task_dependency_add()
567  */
568 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
569 {
570
571   xbt_dynar_t dynar;
572   int length;
573   int found = 0;
574   int i;
575   SD_dependency_t dependency;
576
577   /* remove the dependency from src->tasks_after */
578   dynar = src->tasks_after;
579   length = xbt_dynar_length(dynar);
580
581   for (i = 0; i < length && !found; i++) {
582     xbt_dynar_get_cpy(dynar, i, &dependency);
583     if (dependency->dst == dst) {
584       xbt_dynar_remove_at(dynar, i, NULL);
585       found = 1;
586     }
587   }
588   if (!found)
589     THROWF(arg_error, 0,
590            "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
591            SD_task_get_name(src), SD_task_get_name(dst),
592            SD_task_get_name(dst), SD_task_get_name(src));
593
594   /* remove the dependency from dst->tasks_before */
595   dynar = dst->tasks_before;
596   length = xbt_dynar_length(dynar);
597   found = 0;
598
599   for (i = 0; i < length && !found; i++) {
600     xbt_dynar_get_cpy(dynar, i, &dependency);
601     if (dependency->src == src) {
602       xbt_dynar_remove_at(dynar, i, NULL);
603       __SD_task_dependency_destroy(dependency);
604       dst->unsatisfied_dependencies--;
605       dst->is_not_ready--;
606       found = 1;
607     }
608   }
609   /* should never happen... */
610   xbt_assert(found,
611               "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
612               SD_task_get_name(dst), SD_task_get_name(src),
613               SD_task_get_name(src), SD_task_get_name(dst));
614
615   /* if the task was scheduled and dst->tasks_before is empty now, we can make it runnable */
616
617   if (dst->unsatisfied_dependencies == 0) {
618     if (__SD_task_is_scheduled(dst))
619       __SD_task_set_state(dst, SD_RUNNABLE);
620     else
621       __SD_task_set_state(dst, SD_SCHEDULABLE);
622   }
623
624   if (dst->is_not_ready == 0)
625     __SD_task_set_state(dst, SD_SCHEDULABLE);
626
627   /*  __SD_print_dependencies(src);
628      __SD_print_dependencies(dst); */
629 }
630
631 /**
632  * \brief Returns the user data associated with a dependency between two tasks
633  *
634  * \param src a task
635  * \param dst a task depending on \a src
636  * \return the user data associated with this dependency (can be \c NULL)
637  * \see SD_task_dependency_add()
638  */
639 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
640 {
641
642   xbt_dynar_t dynar;
643   int length;
644   int found = 0;
645   int i;
646   SD_dependency_t dependency;
647
648   dynar = src->tasks_after;
649   length = xbt_dynar_length(dynar);
650
651   for (i = 0; i < length && !found; i++) {
652     xbt_dynar_get_cpy(dynar, i, &dependency);
653     found = (dependency->dst == dst);
654   }
655   if (!found)
656     THROWF(arg_error, 0, "No dependency found between task '%s' and '%s'",
657            SD_task_get_name(src), SD_task_get_name(dst));
658   return dependency->data;
659 }
660
661 /* temporary function for debugging */
662 static void __SD_print_watch_points(SD_task_t task)
663 {
664   static const int state_masks[] =
665       { SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNING, SD_RUNNABLE, SD_DONE,
666     SD_FAILED
667   };
668   static const char *state_names[] =
669       { "schedulable", "scheduled", "running", "runnable", "done",
670     "failed"
671   };
672   int i;
673
674   XBT_INFO("Task '%s' watch points (%x): ", SD_task_get_name(task),
675         task->watch_points);
676
677
678   for (i = 0; i < 5; i++) {
679     if (task->watch_points & state_masks[i])
680       XBT_INFO("%s ", state_names[i]);
681   }
682 }
683
684 /**
685  * \brief Adds a watch point to a task
686  *
687  * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
688  * task becomes the one given in argument. The
689  * watch point is then automatically removed.
690  *
691  * \param task a task
692  * \param state the \ref e_SD_task_state_t "state" you want to watch
693  * (cannot be #SD_NOT_SCHEDULED)
694  * \see SD_task_unwatch()
695  */
696 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
697 {
698   if (state & SD_NOT_SCHEDULED)
699     THROWF(arg_error, 0,
700            "Cannot add a watch point for state SD_NOT_SCHEDULED");
701
702   task->watch_points = task->watch_points | state;
703   /*  __SD_print_watch_points(task); */
704 }
705
706 /**
707  * \brief Removes a watch point from a task
708  *
709  * \param task a task
710  * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
711  * \see SD_task_watch()
712  */
713 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
714 {
715   xbt_assert(state != SD_NOT_SCHEDULED,
716               "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
717
718   task->watch_points = task->watch_points & ~state;
719   /*  __SD_print_watch_points(task); */
720 }
721
722 /**
723  * \brief Returns an approximative estimation of the execution time of a task.
724  *
725  * The estimation is very approximative because the value returned is the time
726  * the task would take if it was executed now and if it was the only task.
727  *
728  * \param task the task to evaluate
729  * \param workstation_nb number of workstations on which the task would be executed
730  * \param workstation_list the workstations on which the task would be executed
731  * \param computation_amount computation amount for each workstation
732  * \param communication_amount communication amount between each pair of workstations
733  * \see SD_schedule()
734  */
735 double SD_task_get_execution_time(SD_task_t task,
736                                   int workstation_nb,
737                                   const SD_workstation_t *
738                                   workstation_list,
739                                   const double *computation_amount,
740                                   const double *communication_amount)
741 {
742   double time, max_time = 0.0;
743   int i, j;
744   xbt_assert(workstation_nb > 0, "Invalid parameter");
745
746   /* the task execution time is the maximum execution time of the parallel tasks */
747
748   for (i = 0; i < workstation_nb; i++) {
749     time = 0.0;
750     if (computation_amount != NULL)
751       time =
752           SD_workstation_get_computation_time(workstation_list[i],
753                                               computation_amount[i]);
754
755     if (communication_amount != NULL)
756       for (j = 0; j < workstation_nb; j++) {
757         time +=
758             SD_route_get_communication_time(workstation_list[i],
759                                             workstation_list[j],
760                                             communication_amount[i *
761                                                                  workstation_nb
762                                                                  + j]);
763       }
764
765     if (time > max_time) {
766       max_time = time;
767     }
768   }
769   return max_time;
770 }
771
772 static XBT_INLINE void SD_task_do_schedule(SD_task_t task)
773 {
774   if (!__SD_task_is_not_scheduled(task) && !__SD_task_is_schedulable(task))
775     THROWF(arg_error, 0, "Task '%s' has already been scheduled",
776            SD_task_get_name(task));
777
778   /* update the task state */
779   if (task->unsatisfied_dependencies == 0)
780     __SD_task_set_state(task, SD_RUNNABLE);
781   else
782     __SD_task_set_state(task, SD_SCHEDULED);
783 }
784
785 /**
786  * \brief Schedules a task
787  *
788  * The task state must be #SD_NOT_SCHEDULED.
789  * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
790  * i.e. when its dependencies are satisfied.
791  *
792  * \param task the task you want to schedule
793  * \param workstation_count number of workstations on which the task will be executed
794  * \param workstation_list the workstations on which the task will be executed
795  * \param computation_amount computation amount for each workstation
796  * \param communication_amount communication amount between each pair of workstations
797  * \param rate task execution speed rate
798  * \see SD_task_unschedule()
799  */
800 void SD_task_schedule(SD_task_t task, int workstation_count,
801                       const SD_workstation_t * workstation_list,
802                       const double *computation_amount,
803                       const double *communication_amount, double rate)
804 {
805   int communication_nb;
806   task->workstation_nb = 0;
807   task->rate = -1;
808   xbt_assert(workstation_count > 0, "workstation_nb must be positive");
809
810   task->workstation_nb = workstation_count;
811   task->rate = rate;
812
813   if (computation_amount) {
814     task->computation_amount = xbt_realloc(task->computation_amount,
815                                            sizeof(double) * workstation_count);
816     memcpy(task->computation_amount, computation_amount,
817            sizeof(double) * workstation_count);
818   } else {
819     xbt_free(task->computation_amount);
820     task->computation_amount = NULL;
821   }
822
823   communication_nb = workstation_count * workstation_count;
824   if (communication_amount) {
825     task->communication_amount = xbt_realloc(task->communication_amount,
826                                              sizeof(double) * communication_nb);
827     memcpy(task->communication_amount, communication_amount,
828            sizeof(double) * communication_nb);
829   } else {
830     xbt_free(task->communication_amount);
831     task->communication_amount = NULL;
832   }
833
834   task->workstation_list =
835     xbt_realloc(task->workstation_list,
836                 sizeof(SD_workstation_t) * workstation_count);
837   memcpy(task->workstation_list, workstation_list,
838          sizeof(SD_workstation_t) * workstation_count);
839
840   SD_task_do_schedule(task);
841 }
842
843 /**
844  * \brief Unschedules a task
845  *
846  * The task state must be #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING or #SD_FAILED.
847  * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
848  * Call SD_task_schedule() to schedule it again.
849  *
850  * \param task the task you want to unschedule
851  * \see SD_task_schedule()
852  */
853 void SD_task_unschedule(SD_task_t task)
854 {
855   if (task->state_set != sd_global->scheduled_task_set &&
856       task->state_set != sd_global->runnable_task_set &&
857       task->state_set != sd_global->running_task_set &&
858       task->state_set != sd_global->failed_task_set)
859     THROWF(arg_error, 0,
860            "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED",
861            SD_task_get_name(task));
862
863   if (__SD_task_is_scheduled_or_runnable(task)  /* if the task is scheduled or runnable */
864       &&task->kind == SD_TASK_NOT_TYPED)        /* Don't free scheduling data for typed tasks */
865     __SD_task_destroy_scheduling_data(task);
866
867   if (__SD_task_is_running(task))       /* the task should become SD_FAILED */
868     surf_workstation_model->action_cancel(task->surf_action);
869   else {
870     if (task->unsatisfied_dependencies == 0)
871       __SD_task_set_state(task, SD_SCHEDULABLE);
872     else
873       __SD_task_set_state(task, SD_NOT_SCHEDULED);
874   }
875   task->remains = task->amount;
876   task->start_time = -1.0;
877 }
878
879 /* Destroys the data memorized by SD_task_schedule. Task state must be SD_SCHEDULED or SD_RUNNABLE.
880  */
881 static void __SD_task_destroy_scheduling_data(SD_task_t task)
882 {
883   if (!__SD_task_is_scheduled_or_runnable(task)
884       && !__SD_task_is_in_fifo(task))
885     THROWF(arg_error, 0,
886            "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
887            SD_task_get_name(task));
888
889   xbt_free(task->computation_amount);
890   xbt_free(task->communication_amount);
891   task->computation_amount = task->communication_amount = NULL;
892 }
893
894 /* Runs a task. This function is directly called by __SD_task_try_to_run if the task
895  * doesn't have to wait in fifos. Otherwise, it is called by __SD_task_just_done when
896  * the task gets out of its fifos.
897  */
898 void __SD_task_really_run(SD_task_t task)
899 {
900
901   int i;
902   void **surf_workstations;
903
904   xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
905               "Task '%s' is not runnable or in a fifo! Task state: %d",
906               SD_task_get_name(task), SD_task_get_state(task));
907   xbt_assert(task->workstation_list != NULL,
908               "Task '%s': workstation_list is NULL!",
909               SD_task_get_name(task));
910
911
912
913   XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
914
915   /* set this task as current task for the workstations in sequential mode */
916   for (i = 0; i < task->workstation_nb; i++) {
917     if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
918         SD_WORKSTATION_SEQUENTIAL_ACCESS) {
919       task->workstation_list[i]->current_task = task;
920       xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
921                   "The workstation should be busy now");
922     }
923   }
924
925   XBT_DEBUG("Task '%s' set as current task for its workstations",
926          SD_task_get_name(task));
927
928   /* start the task */
929
930   /* we have to create a Surf workstation array instead of the SimDag workstation array */
931   surf_workstations = xbt_new(void *, task->workstation_nb);
932
933   for (i = 0; i < task->workstation_nb; i++)
934     surf_workstations[i] = task->workstation_list[i]->surf_workstation;
935
936   /* It's allowed to pass a NULL vector as cost to mean vector of 0.0 (easing user's life). Let's deal with it */
937 #define cost_or_zero(array,pos) ((array)?(array)[pos]:0.0)
938
939   task->surf_action = NULL;
940   if ((task->workstation_nb == 1)
941       && (cost_or_zero(task->communication_amount, 0) == 0.0)) {
942     task->surf_action =
943         surf_workstation_model->extension.
944         workstation.execute(surf_workstations[0],
945                             cost_or_zero(task->computation_amount, 0));
946   } else if ((task->workstation_nb == 1)
947              && (cost_or_zero(task->computation_amount, 0) == 0.0)) {
948
949     task->surf_action =
950         surf_workstation_model->extension.
951         workstation.communicate(surf_workstations[0], surf_workstations[0],
952                                 cost_or_zero(task->communication_amount,
953                                              0), task->rate);
954   } else if ((task->workstation_nb == 2)
955              && (cost_or_zero(task->computation_amount, 0) == 0.0)
956              && (cost_or_zero(task->computation_amount, 1) == 0.0)) {
957     int nb = 0;
958     double value = 0.0;
959
960     for (i = 0; i < task->workstation_nb * task->workstation_nb; i++) {
961       if (cost_or_zero(task->communication_amount, i) > 0.0) {
962         nb++;
963         value = cost_or_zero(task->communication_amount, i);
964       }
965     }
966     if (nb == 1) {
967       task->surf_action =
968           surf_workstation_model->extension.
969           workstation.communicate(surf_workstations[0],
970                                   surf_workstations[1], value, task->rate);
971     }
972   }
973 #undef cost_or_zero
974
975   if (!task->surf_action) {
976     double *computation_amount = xbt_new(double, task->workstation_nb);
977     double *communication_amount = xbt_new(double, task->workstation_nb *
978                                            task->workstation_nb);
979
980     memcpy(computation_amount, task->computation_amount, sizeof(double) *
981            task->workstation_nb);
982     memcpy(communication_amount, task->communication_amount,
983            sizeof(double) * task->workstation_nb * task->workstation_nb);
984
985     task->surf_action =
986         surf_workstation_model->extension.
987         workstation.execute_parallel_task(task->workstation_nb,
988                                           surf_workstations,
989                                           computation_amount,
990                                           communication_amount,
991                                           task->amount, task->rate);
992   } else {
993     xbt_free(surf_workstations);
994   }
995
996   surf_workstation_model->action_data_set(task->surf_action, task);
997
998   XBT_DEBUG("surf_action = %p", task->surf_action);
999
1000 #ifdef HAVE_TRACING
1001   if (task->category)
1002     TRACE_surf_action(task->surf_action, task->category);
1003 #endif
1004
1005   __SD_task_destroy_scheduling_data(task);      /* now the scheduling data are not useful anymore */
1006   __SD_task_set_state(task, SD_RUNNING);
1007   xbt_assert(__SD_task_is_running(task), "Bad state of task '%s': %d",
1008               SD_task_get_name(task), SD_task_get_state(task));
1009
1010 }
1011
1012 /* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_RUNNABLE
1013  * (ie when its dependencies are satisfied).
1014  * If one of the workstations where the task is scheduled on is busy (in sequential mode),
1015  * the task doesn't start.
1016  * Returns whether the task has started.
1017  */
1018 int __SD_task_try_to_run(SD_task_t task)
1019 {
1020
1021   int can_start = 1;
1022   int i;
1023   SD_workstation_t workstation;
1024
1025   xbt_assert(__SD_task_is_runnable(task),
1026               "Task '%s' is not runnable! Task state: %d",
1027               SD_task_get_name(task), SD_task_get_state(task));
1028
1029
1030   for (i = 0; i < task->workstation_nb; i++) {
1031     can_start = can_start &&
1032         !__SD_workstation_is_busy(task->workstation_list[i]);
1033   }
1034
1035   XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
1036
1037   if (!can_start) {             /* if the task cannot start and is not in the fifos yet */
1038     for (i = 0; i < task->workstation_nb; i++) {
1039       workstation = task->workstation_list[i];
1040       if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1041         XBT_DEBUG("Pushing task '%s' in the fifo of workstation '%s'",
1042                SD_task_get_name(task),
1043                SD_workstation_get_name(workstation));
1044         xbt_fifo_push(workstation->task_fifo, task);
1045       }
1046     }
1047     __SD_task_set_state(task, SD_IN_FIFO);
1048     xbt_assert(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
1049                 SD_task_get_name(task), SD_task_get_state(task));
1050     XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
1051   } else {
1052     __SD_task_really_run(task);
1053   }
1054
1055   return can_start;
1056 }
1057
1058 /* This function is called by SD_simulate when a task is done.
1059  * It updates task->state and task->action and executes if necessary the tasks
1060  * which were waiting in fifos for the end of `task'
1061  */
1062 void __SD_task_just_done(SD_task_t task)
1063 {
1064   int i, j;
1065   SD_workstation_t workstation;
1066
1067   SD_task_t candidate;
1068   int candidate_nb = 0;
1069   int candidate_capacity = 8;
1070   SD_task_t *candidates;
1071   int can_start = 1;
1072
1073   xbt_assert(__SD_task_is_running(task),
1074               "The task must be running! Task state: %d",
1075               SD_task_get_state(task));
1076   xbt_assert(task->workstation_list != NULL,
1077               "Task '%s': workstation_list is NULL!",
1078               SD_task_get_name(task));
1079
1080
1081   candidates = xbt_new(SD_task_t, 8);
1082
1083   __SD_task_set_state(task, SD_DONE);
1084   surf_workstation_model->action_unref(task->surf_action);
1085   task->surf_action = NULL;
1086
1087   XBT_DEBUG("Looking for candidates");
1088
1089   /* if the task was executed on sequential workstations,
1090      maybe we can execute the next task of the fifo for each workstation */
1091   for (i = 0; i < task->workstation_nb; i++) {
1092     workstation = task->workstation_list[i];
1093     XBT_DEBUG("Workstation '%s': access_mode = %d",
1094            SD_workstation_get_name(workstation), workstation->access_mode);
1095     if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1096       xbt_assert(workstation->task_fifo != NULL,
1097                   "Workstation '%s' has sequential access but no fifo!",
1098                   SD_workstation_get_name(workstation));
1099       xbt_assert(workstation->current_task =
1100                   task, "Workstation '%s': current task should be '%s'",
1101                   SD_workstation_get_name(workstation),
1102                   SD_task_get_name(task));
1103
1104       /* the task is over so we can release the workstation */
1105       workstation->current_task = NULL;
1106
1107       XBT_DEBUG("Getting candidate in fifo");
1108       candidate =
1109           xbt_fifo_get_item_content(xbt_fifo_get_first_item
1110                                     (workstation->task_fifo));
1111
1112       if (candidate != NULL) {
1113         XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
1114         xbt_assert(__SD_task_is_in_fifo(candidate),
1115                     "Bad state of candidate '%s': %d",
1116                     SD_task_get_name(candidate),
1117                     SD_task_get_state(candidate));
1118       }
1119
1120       XBT_DEBUG("Candidate in fifo: %p", candidate);
1121
1122       /* if there was a task waiting for my place */
1123       if (candidate != NULL) {
1124         /* Unfortunately, we are not sure yet that we can execute the task now,
1125            because the task can be waiting more deeply in some other workstation's fifos...
1126            So we memorize all candidate tasks, and then we will check for each candidate
1127            whether or not all its workstations are available. */
1128
1129         /* realloc if necessary */
1130         if (candidate_nb == candidate_capacity) {
1131           candidate_capacity *= 2;
1132           candidates =
1133               xbt_realloc(candidates,
1134                           sizeof(SD_task_t) * candidate_capacity);
1135         }
1136
1137         /* register the candidate */
1138         candidates[candidate_nb++] = candidate;
1139         candidate->fifo_checked = 0;
1140       }
1141     }
1142   }
1143
1144   XBT_DEBUG("Candidates found: %d", candidate_nb);
1145
1146   /* now we check every candidate task */
1147   for (i = 0; i < candidate_nb; i++) {
1148     candidate = candidates[i];
1149
1150     if (candidate->fifo_checked) {
1151       continue;                 /* we have already evaluated that task */
1152     }
1153
1154     xbt_assert(__SD_task_is_in_fifo(candidate),
1155                 "Bad state of candidate '%s': %d",
1156                 SD_task_get_name(candidate), SD_task_get_state(candidate));
1157
1158     for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1159       workstation = candidate->workstation_list[j];
1160
1161       /* I can start on this workstation if the workstation is shared
1162          or if I am the first task in the fifo */
1163       can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS
1164           || candidate ==
1165           xbt_fifo_get_item_content(xbt_fifo_get_first_item
1166                                     (workstation->task_fifo));
1167     }
1168
1169     XBT_DEBUG("Candidate '%s' can start: %d", SD_task_get_name(candidate),
1170            can_start);
1171
1172     /* now we are sure that I can start! */
1173     if (can_start) {
1174       for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1175         workstation = candidate->workstation_list[j];
1176
1177         /* update the fifo */
1178         if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1179           candidate = xbt_fifo_shift(workstation->task_fifo);   /* the return value is stored just for debugging */
1180           XBT_DEBUG("Head of the fifo: '%s'",
1181                  (candidate !=
1182                   NULL) ? SD_task_get_name(candidate) : "NULL");
1183           xbt_assert(candidate == candidates[i],
1184                       "Error in __SD_task_just_done: bad first task in the fifo");
1185         }
1186       }                         /* for each workstation */
1187
1188       /* finally execute the task */
1189       XBT_DEBUG("Task '%s' state: %d", SD_task_get_name(candidate),
1190              SD_task_get_state(candidate));
1191       __SD_task_really_run(candidate);
1192
1193       XBT_DEBUG
1194           ("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
1195            SD_task_get_name(candidate), candidate->state_set,
1196            sd_global->running_task_set, __SD_task_is_running(candidate));
1197       xbt_assert(__SD_task_is_running(candidate),
1198                   "Bad state of task '%s': %d",
1199                   SD_task_get_name(candidate),
1200                   SD_task_get_state(candidate));
1201       XBT_DEBUG("Okay, the task is running.");
1202
1203     }                           /* can start */
1204     candidate->fifo_checked = 1;
1205   }                             /* for each candidate */
1206
1207   xbt_free(candidates);
1208 }
1209
1210 /* Remove all dependencies associated with a task. This function is called when the task is destroyed.
1211  */
1212 static void __SD_task_remove_dependencies(SD_task_t task)
1213 {
1214   /* we must destroy the dependencies carefuly (with SD_dependency_remove)
1215      because each one is stored twice */
1216   SD_dependency_t dependency;
1217   while (xbt_dynar_length(task->tasks_before) > 0) {
1218     xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
1219     SD_task_dependency_remove(dependency->src, dependency->dst);
1220   }
1221
1222   while (xbt_dynar_length(task->tasks_after) > 0) {
1223     xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
1224     SD_task_dependency_remove(dependency->src, dependency->dst);
1225   }
1226 }
1227
1228 /**
1229  * \brief Returns the start time of a task
1230  *
1231  * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1232  *
1233  * \param task: a task
1234  * \return the start time of this task
1235  */
1236 double SD_task_get_start_time(SD_task_t task)
1237 {
1238   if (task->surf_action)
1239     return surf_workstation_model->
1240         action_get_start_time(task->surf_action);
1241   else
1242     return task->start_time;
1243 }
1244
1245 /**
1246  * \brief Returns the finish time of a task
1247  *
1248  * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1249  * If the state is not completed yet, the returned value is an
1250  * estimation of the task finish time. This value can fluctuate
1251  * until the task is completed.
1252  *
1253  * \param task: a task
1254  * \return the start time of this task
1255  */
1256 double SD_task_get_finish_time(SD_task_t task)
1257 {
1258   if (task->surf_action)        /* should never happen as actions are destroyed right after their completion */
1259     return surf_workstation_model->
1260         action_get_finish_time(task->surf_action);
1261   else
1262     return task->finish_time;
1263 }
1264
1265 static XBT_INLINE SD_task_t SD_task_create_sized(const char *name,
1266                                                  void *data, double amount,
1267                                                  int ws_count)
1268 {
1269   SD_task_t task = SD_task_create(name, data, amount);
1270   task->communication_amount = xbt_new0(double, ws_count * ws_count);
1271   task->computation_amount = xbt_new0(double, ws_count);
1272   task->workstation_nb = ws_count;
1273   task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
1274   return task;
1275 }
1276
1277 /** @brief create a end-to-end communication task that can then be auto-scheduled
1278  *
1279  * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1280  * allows to specify the task costs at creation, and decorelate them from the
1281  * scheduling process where you just specify which resource should deliver the
1282  * mandatory power.
1283  *
1284  * A end-to-end communication must be scheduled on 2 hosts, and the amount
1285  * specified at creation is sent from hosts[0] to hosts[1].
1286  */
1287 SD_task_t SD_task_create_comm_e2e(const char *name, void *data,
1288                                   double amount)
1289 {
1290   SD_task_t res = SD_task_create_sized(name, data, amount, 2);
1291   res->communication_amount[2] = amount;
1292   res->kind = SD_TASK_COMM_E2E;
1293   return res;
1294 }
1295
1296 /** @brief create a sequential computation task that can then be auto-scheduled
1297  *
1298  * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1299  * allows to specify the task costs at creation, and decorelate them from the
1300  * scheduling process where you just specify which resource should deliver the
1301  * mandatory power.
1302  *
1303  * A sequential computation must be scheduled on 1 host, and the amount
1304  * specified at creation to be run on hosts[0].
1305  */
1306 SD_task_t SD_task_create_comp_seq(const char *name, void *data,
1307                                   double amount)
1308 {
1309   SD_task_t res = SD_task_create_sized(name, data, amount, 1);
1310   res->computation_amount[0] = amount;
1311   res->kind = SD_TASK_COMP_SEQ;
1312   return res;
1313 }
1314
1315 /** @brief Auto-schedules a task.
1316  *
1317  * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1318  * allows to specify the task costs at creation, and decorelate them from the
1319  * scheduling process where you just specify which resource should deliver the
1320  * mandatory power.
1321  *
1322  * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e() or
1323  * SD_task_create_comp_seq(). Check their definitions for the exact semantic of each
1324  * of them.
1325  *
1326  * @todo
1327  * We should create tasks kind for the following categories:
1328  *  - Point to point communication (done)
1329  *  - Sequential computation       (done)
1330  *  - group communication (redistribution, several kinds)
1331  *  - parallel tasks with no internal communication (one kind per speedup model such as amdal)
1332  *  - idem+ internal communication. Task type not enough since we cannot store comm cost alongside to comp one)
1333  */
1334 void SD_task_schedulev(SD_task_t task, int count,
1335                        const SD_workstation_t * list)
1336 {
1337   int i;
1338   SD_dependency_t dep;
1339   unsigned int cpt;
1340   xbt_assert(task->kind != 0,
1341               "Task %s is not typed. Cannot automatically schedule it.",
1342               SD_task_get_name(task));
1343   switch (task->kind) {
1344   case SD_TASK_COMM_E2E:
1345   case SD_TASK_COMP_SEQ:
1346     xbt_assert(task->workstation_nb == count,"Got %d locations, but were expecting %d locations",count,task->workstation_nb);
1347     for (i = 0; i < count; i++)
1348       task->workstation_list[i] = list[i];
1349     SD_task_do_schedule(task);
1350     break;
1351   default:
1352     xbt_die("Kind of task %s not supported by SD_task_schedulev()",
1353             SD_task_get_name(task));
1354   }
1355   if (task->kind == SD_TASK_COMM_E2E) {
1356     XBT_VERB("Schedule comm task %s between %s -> %s. It costs %.f bytes",
1357           SD_task_get_name(task),
1358           SD_workstation_get_name(task->workstation_list[0]),
1359           SD_workstation_get_name(task->workstation_list[1]),
1360           task->communication_amount[2]);
1361
1362   }
1363   /* Iterate over all childs and parent being COMM_E2E to say where I am located (and start them if runnable) */
1364   if (task->kind == SD_TASK_COMP_SEQ) {
1365     XBT_VERB("Schedule computation task %s on %s. It costs %.f flops",
1366           SD_task_get_name(task),
1367           SD_workstation_get_name(task->workstation_list[0]),
1368           task->computation_amount[0]);
1369
1370     xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1371       SD_task_t before = dep->src;
1372       if (before->kind == SD_TASK_COMM_E2E) {
1373         before->workstation_list[1] = task->workstation_list[0];
1374
1375         if (before->workstation_list[0] &&
1376             (__SD_task_is_schedulable(before)
1377              || __SD_task_is_not_scheduled(before))) {
1378           SD_task_do_schedule(before);
1379           XBT_VERB
1380               ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1381                SD_task_get_name(before),
1382                SD_workstation_get_name(before->workstation_list[0]),
1383                SD_workstation_get_name(before->workstation_list[1]),
1384                before->communication_amount[2]);
1385         }
1386       }
1387     }
1388     xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1389       SD_task_t after = dep->dst;
1390       if (after->kind == SD_TASK_COMM_E2E) {
1391         after->workstation_list[0] = task->workstation_list[0];
1392         //J-N : Why did you comment on these line (this comment add a bug I think)?
1393         if (after->workstation_list[1]
1394             && (__SD_task_is_not_scheduled(after)
1395                 || __SD_task_is_schedulable(after))) {
1396           SD_task_do_schedule(after);
1397           XBT_VERB
1398               ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1399                SD_task_get_name(after),
1400                SD_workstation_get_name(after->workstation_list[0]),
1401                SD_workstation_get_name(after->workstation_list[1]),
1402                after->communication_amount[2]);
1403
1404         }
1405       }
1406     }
1407   }
1408 }
1409
1410 /** @brief autoschedule a task on a list of workstations
1411  *
1412  * This function is very similar to SD_task_schedulev(),
1413  * but takes the list of workstations to schedule onto as separate parameters.
1414  * It builds a proper vector of workstations and then call SD_task_schedulev()
1415  */
1416 void SD_task_schedulel(SD_task_t task, int count, ...)
1417 {
1418   va_list ap;
1419   SD_workstation_t *list = xbt_new(SD_workstation_t, count);
1420   int i;
1421   va_start(ap, count);
1422   for (i = 0; i < count; i++) {
1423     list[i] = va_arg(ap, SD_workstation_t);
1424   }
1425   va_end(ap);
1426   SD_task_schedulev(task, count, list);
1427   free(list);
1428 }