Logo AND Algorithmique Numérique Distribuée

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