Logo AND Algorithmique Numérique Distribuée

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