Logo AND Algorithmique Numérique Distribuée

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