1 /* Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011. The SimGrid Team.
2 * All rights reserved. */
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. */
8 #include "simdag/simdag.h"
9 #include "xbt/sysdep.h"
10 #include "xbt/dynar.h"
11 #include "instr/instr_private.h"
13 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_task, sd,
14 "Logging specific to SimDag (task)");
16 static void __SD_task_remove_dependencies(SD_task_t task);
17 static void __SD_task_destroy_scheduling_data(SD_task_t task);
19 void* SD_task_new_f(void)
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);
28 void SD_task_recycle_f(void *t)
30 SD_task_t task = (SD_task_t) t;
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;
44 task->start_time = -1.0;
45 task->finish_time = -1.0;
46 task->surf_action = NULL;
47 task->watch_points = 0;
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;
55 /* scheduling parameters */
56 task->workstation_nb = 0;
57 task->workstation_list = NULL;
58 task->computation_amount = NULL;
59 task->communication_amount = NULL;
63 void SD_task_free_f(void *t)
65 SD_task_t task = (SD_task_t)t;
67 xbt_dynar_free(&task->tasks_before);
68 xbt_dynar_free(&task->tasks_after);
73 * \brief Creates a new task.
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()
81 SD_task_t SD_task_create(const char *name, void *data, double amount)
83 SD_task_t task = xbt_mallocator_get(sd_global->task_mallocator);
85 /* general information */
86 task->data = data; /* user data */
87 task->name = xbt_strdup(name);
88 task->amount = amount;
89 task->remains = amount;
91 sd_global->task_number++;
94 task->category = NULL;
100 static XBT_INLINE SD_task_t SD_task_create_sized(const char *name,
101 void *data, double amount,
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);
112 /** @brief create a end-to-end communication task that can then be auto-scheduled
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
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].
122 SD_task_t SD_task_create_comm_e2e(const char *name, void *data,
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;
131 /** @brief create a sequential computation task that can then be auto-scheduled
133 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
134 * allows to specify the task costs at creation, and decouple them from the
135 * scheduling process where you just specify which resource should deliver the
138 * A sequential computation must be scheduled on 1 host, and the amount
139 * specified at creation to be run on hosts[0].
141 * \param name the name of the task (can be \c NULL)
142 * \param data the user data you want to associate with the task (can be \c NULL)
143 * \param amount amount of compute work to be done by the task
144 * \return the new SD_TASK_COMP_SEQ typed task
146 SD_task_t SD_task_create_comp_seq(const char *name, void *data,
149 SD_task_t res = SD_task_create_sized(name, data, amount, 1);
150 res->computation_amount[0] = amount;
151 res->kind = SD_TASK_COMP_SEQ;
155 /** @brief create a parallel computation task that can then be auto-scheduled
157 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
158 * allows to specify the task costs at creation, and decouple them from the
159 * scheduling process where you just specify which resource should deliver the
162 * A parallel computation can be scheduled on any number of host.
163 * The underlying speedup model is Amdahl's law.
164 * To be auto-scheduled, \see SD_task_distribute_comp_amdhal has to be called
166 * \param name the name of the task (can be \c NULL)
167 * \param data the user data you want to associate with the task (can be \c NULL)
168 * \param amount amount of compute work to be done by the task
169 * \param alpha purely serial fraction of the work to be done (in [0.;1.[)
170 * \return the new task
172 SD_task_t SD_task_create_comp_par_amdahl(const char *name, void *data,
173 double amount, double alpha)
175 xbt_assert(alpha < 1. && alpha >= 0.,
176 "Invalid parameter: alpha must be in [0.;1.[");
178 SD_task_t res = SD_task_create(name, data, amount);
180 res->kind = SD_TASK_COMP_PAR_AMDAHL;
184 /** @brief create a complex data redistribution task that can then be
187 * Auto-scheduling mean that the task can be used with SD_task_schedulev().
188 * This allows to specify the task costs at creation, and decouple them from
189 * the scheduling process where you just specify which resource should
192 * A data redistribution can be scheduled on any number of host.
193 * The assumed distribution is a 1D block distribution. Each host owns the same
194 * share of the \see amount.
195 * To be auto-scheduled, \see SD_task_distribute_comm_mxn_1d_block has to be
197 * \param name the name of the task (can be \c NULL)
198 * \param data the user data you want to associate with the task (can be
200 * \param amount amount of data to redistribute by the task
201 * \return the new task
203 SD_task_t SD_task_create_comm_par_mxn_1d_block(const char *name, void *data,
206 SD_task_t res = SD_task_create(name, data, amount);
207 res->workstation_list=NULL;
208 res->kind = SD_TASK_COMM_PAR_MXN_1D_BLOCK;
213 * \brief Destroys a task.
215 * The user data (if any) should have been destroyed first.
217 * \param task the task you want to destroy
218 * \see SD_task_create()
220 void SD_task_destroy(SD_task_t task)
222 XBT_DEBUG("Destroying task %s...", SD_task_get_name(task));
224 __SD_task_remove_dependencies(task);
225 /* if the task was scheduled or runnable we have to free the scheduling parameters */
226 if (__SD_task_is_scheduled_or_runnable(task))
227 __SD_task_destroy_scheduling_data(task);
228 if (task->state_set != NULL) /* would be null if just created */
229 xbt_swag_remove(task, task->state_set);
231 xbt_swag_remove(task, sd_global->return_set);
233 xbt_free(task->name);
235 if (task->surf_action != NULL)
236 surf_workstation_model->action_unref(task->surf_action);
238 xbt_free(task->workstation_list);
239 xbt_free(task->communication_amount);
240 xbt_free(task->computation_amount);
243 if (task->category) xbt_free(task->category);
246 xbt_mallocator_release(sd_global->task_mallocator,task);
247 sd_global->task_number--;
249 XBT_DEBUG("Task destroyed.");
253 * \brief Returns the user data of a task
256 * \return the user data associated with this task (can be \c NULL)
257 * \see SD_task_set_data()
259 void *SD_task_get_data(SD_task_t task)
265 * \brief Sets the user data of a task
267 * The new data can be \c NULL. The old data should have been freed first
268 * if it was not \c NULL.
271 * \param data the new data you want to associate with this task
272 * \see SD_task_get_data()
274 void SD_task_set_data(SD_task_t task, void *data)
280 * \brief Sets the rate of a task
282 * This will change the network bandwidth a task can use. This rate
283 * depends on both the nominal bandwidth on the route onto which the task is
284 * scheduled (\see SD_task_get_current_bandwidth) and the amount of data to
287 * To divide the nominal bandwidth by 2, the rate then has to be :
288 * rate = bandwidth/(2*amount)
290 * \param task a \see SD_TASK_COMM_E2E task (end-to-end communication)
291 * \param rate the new rate you want to associate with this task.
293 void SD_task_set_rate(SD_task_t task, double rate)
295 xbt_assert(task->kind == SD_TASK_COMM_E2E,
296 "The rate can be modified for end-to-end communications only.");
302 * \brief Returns the state of a task
305 * \return the current \ref e_SD_task_state_t "state" of this task:
306 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING, #SD_DONE or #SD_FAILED
307 * \see e_SD_task_state_t
309 e_SD_task_state_t SD_task_get_state(SD_task_t task)
314 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
316 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
318 xbt_swag_remove(task, task->state_set);
320 case SD_NOT_SCHEDULED:
321 task->state_set = sd_global->not_scheduled_task_set;
324 task->state_set = sd_global->schedulable_task_set;
327 task->state_set = sd_global->scheduled_task_set;
330 task->state_set = sd_global->runnable_task_set;
333 task->state_set = sd_global->in_fifo_task_set;
336 task->state_set = sd_global->running_task_set;
338 surf_workstation_model->action_get_start_time(task->surf_action);
341 task->state_set = sd_global->done_task_set;
343 surf_workstation_model->action_get_finish_time(task->surf_action);
346 jedule_log_sd_event(task);
350 task->state_set = sd_global->failed_task_set;
353 xbt_die( "Invalid state");
355 xbt_swag_insert(task, task->state_set);
356 task->state = new_state;
358 if (task->watch_points & new_state) {
359 XBT_VERB("Watch point reached with task '%s'!", SD_task_get_name(task));
360 sd_global->watch_point_reached = 1;
361 SD_task_unwatch(task, new_state); /* remove the watch point */
366 * \brief Returns the name of a task
369 * \return the name of this task (can be \c NULL)
371 const char *SD_task_get_name(SD_task_t task)
376 /** @brief Allows to change the name of a task */
377 void SD_task_set_name(SD_task_t task, const char *name)
379 xbt_free(task->name);
380 task->name = xbt_strdup(name);
383 /** @brief Returns the dynar of the parents of a task
386 * \return a newly allocated dynar comprising the parents of this task
389 xbt_dynar_t SD_task_get_parents(SD_task_t task)
395 parents = xbt_dynar_new(sizeof(SD_task_t), NULL);
396 xbt_dynar_foreach(task->tasks_before, i, dep) {
397 xbt_dynar_push(parents, &(dep->src));
402 /** @brief Returns the dynar of the parents of a task
405 * \return a newly allocated dynar comprising the parents of this task
407 xbt_dynar_t SD_task_get_children(SD_task_t task)
410 xbt_dynar_t children;
413 children = xbt_dynar_new(sizeof(SD_task_t), NULL);
414 xbt_dynar_foreach(task->tasks_after, i, dep) {
415 xbt_dynar_push(children, &(dep->dst));
421 * \brief Returns the amount of workstations involved in a task
423 * Only call this on already scheduled tasks!
426 int SD_task_get_workstation_count(SD_task_t task)
428 return task->workstation_nb;
432 * \brief Returns the list of workstations involved in a task
434 * Only call this on already scheduled tasks!
437 SD_workstation_t *SD_task_get_workstation_list(SD_task_t task)
439 return task->workstation_list;
443 * \brief Returns the total amount of work contained in a task
446 * \return the total amount of work (computation or data transfer) for this task
447 * \see SD_task_get_remaining_amount()
449 double SD_task_get_amount(SD_task_t task)
455 * \brief Returns the remaining amount work to do till the completion of a task
458 * \return the remaining amount of work (computation or data transfer) of this task
459 * \see SD_task_get_amount()
461 double SD_task_get_remaining_amount(SD_task_t task)
463 if (task->surf_action)
464 return surf_workstation_model->get_remains(task->surf_action);
466 return task->remains;
469 int SD_task_get_kind(SD_task_t task)
474 /** @brief Displays debugging informations about a task */
475 void SD_task_dump(SD_task_t task)
477 unsigned int counter;
478 SD_dependency_t dependency;
481 XBT_INFO("Displaying task %s", SD_task_get_name(task));
482 statename = bprintf("%s %s %s %s %s %s %s %s",
483 (task->state & SD_NOT_SCHEDULED ? "not scheduled" :
485 (task->state & SD_SCHEDULABLE ? "schedulable" : ""),
486 (task->state & SD_SCHEDULED ? "scheduled" : ""),
487 (task->state & SD_RUNNABLE ? "runnable" :
489 (task->state & SD_IN_FIFO ? "in fifo" : ""),
490 (task->state & SD_RUNNING ? "running" : ""),
491 (task->state & SD_DONE ? "done" : ""),
492 (task->state & SD_FAILED ? "failed" : ""));
493 XBT_INFO(" - state: %s", statename);
496 if (task->kind != 0) {
497 switch (task->kind) {
498 case SD_TASK_COMM_E2E:
499 XBT_INFO(" - kind: end-to-end communication");
501 case SD_TASK_COMP_SEQ:
502 XBT_INFO(" - kind: sequential computation");
504 case SD_TASK_COMP_PAR_AMDAHL:
505 XBT_INFO(" - kind: parallel computation following Amdahl's law");
508 XBT_INFO(" - (unknown kind %d)", task->kind);
511 XBT_INFO(" - amount: %.0f", SD_task_get_amount(task));
512 XBT_INFO(" - Dependencies to satisfy: %u", task->unsatisfied_dependencies);
513 if (!xbt_dynar_is_empty(task->tasks_before)) {
514 XBT_INFO(" - pre-dependencies:");
515 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
516 XBT_INFO(" %s", SD_task_get_name(dependency->src));
519 if (!xbt_dynar_is_empty(task->tasks_after)) {
520 XBT_INFO(" - post-dependencies:");
521 xbt_dynar_foreach(task->tasks_after, counter, dependency) {
522 XBT_INFO(" %s", SD_task_get_name(dependency->dst));
527 /** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */
528 void SD_task_dotty(SD_task_t task, void *out)
530 unsigned int counter;
531 SD_dependency_t dependency;
532 fprintf(out, " T%p [label=\"%.20s\"", task, task->name);
533 switch (task->kind) {
534 case SD_TASK_COMM_E2E:
535 fprintf(out, ", shape=box");
537 case SD_TASK_COMP_SEQ:
538 fprintf(out, ", shape=circle");
541 xbt_die("Unknown task type!");
543 fprintf(out, "];\n");
544 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
545 fprintf(out, " T%p -> T%p;\n", dependency->src, dependency->dst);
549 /* Destroys a dependency between two tasks.
551 static void __SD_task_dependency_destroy(void *dependency)
553 xbt_free(((SD_dependency_t)dependency)->name);
554 xbt_free(dependency);
558 * \brief Adds a dependency between two tasks
560 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
561 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_RUNNABLE.
563 * \param name the name of the new dependency (can be \c NULL)
564 * \param data the user data you want to associate with this dependency (can be \c NULL)
565 * \param src the task which must be executed first
566 * \param dst the task you want to make depend on \a src
567 * \see SD_task_dependency_remove()
569 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
576 SD_dependency_t dependency;
578 dynar = src->tasks_after;
579 length = xbt_dynar_length(dynar);
583 "Cannot add a dependency between task '%s' and itself",
584 SD_task_get_name(src));
586 if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_schedulable(src)
587 && !__SD_task_is_scheduled_or_runnable(src) && !__SD_task_is_running(src))
589 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE"
591 SD_task_get_name(src));
593 if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_schedulable(dst)
594 && !__SD_task_is_scheduled_or_runnable(dst))
596 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE",
597 SD_task_get_name(dst));
599 XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s",
600 SD_task_get_name(src), SD_task_get_name(dst));
601 for (i = 0; i < length && !found; i++) {
602 xbt_dynar_get_cpy(dynar, i, &dependency);
603 found = (dependency->dst == dst);
604 XBT_DEBUG("Dependency %d: dependency->dst = %s", i,
605 SD_task_get_name(dependency->dst));
610 "A dependency already exists between task '%s' and task '%s'",
611 SD_task_get_name(src), SD_task_get_name(dst));
613 dependency = xbt_new(s_SD_dependency_t, 1);
615 dependency->name = xbt_strdup(name); /* xbt_strdup is cleaver enough to deal with NULL args itself */
616 dependency->data = data;
617 dependency->src = src;
618 dependency->dst = dst;
620 /* src must be executed before dst */
621 xbt_dynar_push(src->tasks_after, &dependency);
622 xbt_dynar_push(dst->tasks_before, &dependency);
624 dst->unsatisfied_dependencies++;
627 /* if the task was runnable, then dst->tasks_before is not empty anymore,
628 so we must go back to state SD_SCHEDULED */
629 if (__SD_task_is_runnable(dst)) {
631 ("SD_task_dependency_add: %s was runnable and becomes scheduled!",
632 SD_task_get_name(dst));
633 __SD_task_set_state(dst, SD_SCHEDULED);
636 /* __SD_print_dependencies(src);
637 __SD_print_dependencies(dst); */
641 * \brief Indicates whether there is a dependency between two tasks.
644 * \param dst a task depending on \a src
646 * If src is NULL, checks whether dst has any pre-dependency.
647 * If dst is NULL, checks whether src has any post-dependency.
649 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
651 unsigned int counter;
652 SD_dependency_t dependency;
654 xbt_assert(src != NULL
656 "Invalid parameter: both src and dst are NULL");
660 xbt_dynar_foreach(src->tasks_after, counter, dependency) {
661 if (dependency->dst == dst)
665 return xbt_dynar_length(src->tasks_after);
668 return xbt_dynar_length(dst->tasks_before);
674 * \brief Remove a dependency between two tasks
677 * \param dst a task depending on \a src
678 * \see SD_task_dependency_add()
680 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
687 SD_dependency_t dependency;
689 /* remove the dependency from src->tasks_after */
690 dynar = src->tasks_after;
691 length = xbt_dynar_length(dynar);
693 for (i = 0; i < length && !found; i++) {
694 xbt_dynar_get_cpy(dynar, i, &dependency);
695 if (dependency->dst == dst) {
696 xbt_dynar_remove_at(dynar, i, NULL);
702 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
703 SD_task_get_name(src), SD_task_get_name(dst),
704 SD_task_get_name(dst), SD_task_get_name(src));
706 /* remove the dependency from dst->tasks_before */
707 dynar = dst->tasks_before;
708 length = xbt_dynar_length(dynar);
711 for (i = 0; i < length && !found; i++) {
712 xbt_dynar_get_cpy(dynar, i, &dependency);
713 if (dependency->src == src) {
714 xbt_dynar_remove_at(dynar, i, NULL);
715 __SD_task_dependency_destroy(dependency);
716 dst->unsatisfied_dependencies--;
721 /* should never happen... */
723 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
724 SD_task_get_name(dst), SD_task_get_name(src),
725 SD_task_get_name(src), SD_task_get_name(dst));
727 /* if the task was scheduled and dst->tasks_before is empty now, we can make it runnable */
729 if (dst->unsatisfied_dependencies == 0) {
730 if (__SD_task_is_scheduled(dst))
731 __SD_task_set_state(dst, SD_RUNNABLE);
733 __SD_task_set_state(dst, SD_SCHEDULABLE);
736 if (dst->is_not_ready == 0)
737 __SD_task_set_state(dst, SD_SCHEDULABLE);
739 /* __SD_print_dependencies(src);
740 __SD_print_dependencies(dst); */
744 * \brief Returns the user data associated with a dependency between two tasks
747 * \param dst a task depending on \a src
748 * \return the user data associated with this dependency (can be \c NULL)
749 * \see SD_task_dependency_add()
751 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
758 SD_dependency_t dependency;
760 dynar = src->tasks_after;
761 length = xbt_dynar_length(dynar);
763 for (i = 0; i < length && !found; i++) {
764 xbt_dynar_get_cpy(dynar, i, &dependency);
765 found = (dependency->dst == dst);
768 THROWF(arg_error, 0, "No dependency found between task '%s' and '%s'",
769 SD_task_get_name(src), SD_task_get_name(dst));
770 return dependency->data;
773 /* temporary function for debugging */
774 static void __SD_print_watch_points(SD_task_t task)
776 static const int state_masks[] =
777 { SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNING, SD_RUNNABLE, SD_DONE,
780 static const char *state_names[] =
781 { "schedulable", "scheduled", "running", "runnable", "done",
786 XBT_INFO("Task '%s' watch points (%x): ", SD_task_get_name(task),
790 for (i = 0; i < 5; i++) {
791 if (task->watch_points & state_masks[i])
792 XBT_INFO("%s ", state_names[i]);
797 * \brief Adds a watch point to a task
799 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
800 * task becomes the one given in argument. The
801 * watch point is then automatically removed.
804 * \param state the \ref e_SD_task_state_t "state" you want to watch
805 * (cannot be #SD_NOT_SCHEDULED)
806 * \see SD_task_unwatch()
808 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
810 if (state & SD_NOT_SCHEDULED)
812 "Cannot add a watch point for state SD_NOT_SCHEDULED");
814 task->watch_points = task->watch_points | state;
815 /* __SD_print_watch_points(task); */
819 * \brief Removes a watch point from a task
822 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
823 * \see SD_task_watch()
825 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
827 xbt_assert(state != SD_NOT_SCHEDULED,
828 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
830 task->watch_points = task->watch_points & ~state;
831 /* __SD_print_watch_points(task); */
835 * \brief Returns an approximative estimation of the execution time of a task.
837 * The estimation is very approximative because the value returned is the time
838 * the task would take if it was executed now and if it was the only task.
840 * \param task the task to evaluate
841 * \param workstation_nb number of workstations on which the task would be executed
842 * \param workstation_list the workstations on which the task would be executed
843 * \param computation_amount computation amount for each workstation
844 * \param communication_amount communication amount between each pair of workstations
847 double SD_task_get_execution_time(SD_task_t task,
849 const SD_workstation_t *
851 const double *computation_amount,
852 const double *communication_amount)
854 double time, max_time = 0.0;
856 xbt_assert(workstation_nb > 0, "Invalid parameter");
858 /* the task execution time is the maximum execution time of the parallel tasks */
860 for (i = 0; i < workstation_nb; i++) {
862 if (computation_amount != NULL)
864 SD_workstation_get_computation_time(workstation_list[i],
865 computation_amount[i]);
867 if (communication_amount != NULL)
868 for (j = 0; j < workstation_nb; j++) {
870 SD_route_get_communication_time(workstation_list[i],
872 communication_amount[i *
877 if (time > max_time) {
884 static XBT_INLINE void SD_task_do_schedule(SD_task_t task)
886 if (!__SD_task_is_not_scheduled(task) && !__SD_task_is_schedulable(task))
887 THROWF(arg_error, 0, "Task '%s' has already been scheduled",
888 SD_task_get_name(task));
890 /* update the task state */
891 if (task->unsatisfied_dependencies == 0)
892 __SD_task_set_state(task, SD_RUNNABLE);
894 __SD_task_set_state(task, SD_SCHEDULED);
898 * \brief Schedules a task
900 * The task state must be #SD_NOT_SCHEDULED.
901 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
902 * i.e. when its dependencies are satisfied.
904 * \param task the task you want to schedule
905 * \param workstation_count number of workstations on which the task will be executed
906 * \param workstation_list the workstations on which the task will be executed
907 * \param computation_amount computation amount for each workstation
908 * \param communication_amount communication amount between each pair of workstations
909 * \param rate task execution speed rate
910 * \see SD_task_unschedule()
912 void SD_task_schedule(SD_task_t task, int workstation_count,
913 const SD_workstation_t * workstation_list,
914 const double *computation_amount,
915 const double *communication_amount, double rate)
917 int communication_nb;
918 task->workstation_nb = 0;
920 xbt_assert(workstation_count > 0, "workstation_nb must be positive");
922 task->workstation_nb = workstation_count;
925 if (computation_amount) {
926 task->computation_amount = xbt_realloc(task->computation_amount,
927 sizeof(double) * workstation_count);
928 memcpy(task->computation_amount, computation_amount,
929 sizeof(double) * workstation_count);
931 xbt_free(task->computation_amount);
932 task->computation_amount = NULL;
935 communication_nb = workstation_count * workstation_count;
936 if (communication_amount) {
937 task->communication_amount = xbt_realloc(task->communication_amount,
938 sizeof(double) * communication_nb);
939 memcpy(task->communication_amount, communication_amount,
940 sizeof(double) * communication_nb);
942 xbt_free(task->communication_amount);
943 task->communication_amount = NULL;
946 task->workstation_list =
947 xbt_realloc(task->workstation_list,
948 sizeof(SD_workstation_t) * workstation_count);
949 memcpy(task->workstation_list, workstation_list,
950 sizeof(SD_workstation_t) * workstation_count);
952 SD_task_do_schedule(task);
956 * \brief Unschedules a task
958 * The task state must be #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING or #SD_FAILED.
959 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
960 * Call SD_task_schedule() to schedule it again.
962 * \param task the task you want to unschedule
963 * \see SD_task_schedule()
965 void SD_task_unschedule(SD_task_t task)
967 if (task->state_set != sd_global->scheduled_task_set &&
968 task->state_set != sd_global->runnable_task_set &&
969 task->state_set != sd_global->running_task_set &&
970 task->state_set != sd_global->failed_task_set)
972 "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED",
973 SD_task_get_name(task));
975 if (__SD_task_is_scheduled_or_runnable(task) /* if the task is scheduled or runnable */
976 && ((task->kind == SD_TASK_COMP_PAR_AMDAHL) ||
977 (task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK))) { /* Don't free scheduling data for typed tasks */
978 __SD_task_destroy_scheduling_data(task);
979 task->workstation_list=NULL;
980 task->workstation_nb = 0;
983 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
984 surf_workstation_model->action_cancel(task->surf_action);
986 if (task->unsatisfied_dependencies == 0)
987 __SD_task_set_state(task, SD_SCHEDULABLE);
989 __SD_task_set_state(task, SD_NOT_SCHEDULED);
991 task->remains = task->amount;
992 task->start_time = -1.0;
995 /* Destroys the data memorized by SD_task_schedule. Task state must be SD_SCHEDULED or SD_RUNNABLE.
997 static void __SD_task_destroy_scheduling_data(SD_task_t task)
999 if (!__SD_task_is_scheduled_or_runnable(task)
1000 && !__SD_task_is_in_fifo(task))
1001 THROWF(arg_error, 0,
1002 "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
1003 SD_task_get_name(task));
1005 xbt_free(task->computation_amount);
1006 xbt_free(task->communication_amount);
1007 task->computation_amount = task->communication_amount = NULL;
1010 /* Runs a task. This function is directly called by __SD_task_try_to_run if the task
1011 * doesn't have to wait in fifos. Otherwise, it is called by __SD_task_just_done when
1012 * the task gets out of its fifos.
1014 void __SD_task_really_run(SD_task_t task)
1018 void **surf_workstations;
1020 xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
1021 "Task '%s' is not runnable or in a fifo! Task state: %d",
1022 SD_task_get_name(task), (int)SD_task_get_state(task));
1023 xbt_assert(task->workstation_list != NULL,
1024 "Task '%s': workstation_list is NULL!",
1025 SD_task_get_name(task));
1027 XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
1028 int workstation_nb = task->workstation_nb;
1030 /* set this task as current task for the workstations in sequential mode */
1031 for (i = 0; i < workstation_nb; i++) {
1032 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
1033 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1034 task->workstation_list[i]->current_task = task;
1035 xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
1036 "The workstation should be busy now");
1040 XBT_DEBUG("Task '%s' set as current task for its workstations",
1041 SD_task_get_name(task));
1043 /* start the task */
1045 /* we have to create a Surf workstation array instead of the SimDag
1046 * workstation array */
1047 surf_workstations = xbt_new(void *, workstation_nb);
1049 for (i = 0; i < workstation_nb; i++)
1050 surf_workstations[i] = task->workstation_list[i]->surf_workstation;
1052 double *computation_amount = xbt_new0(double, workstation_nb);
1053 double *communication_amount = xbt_new0(double, workstation_nb * workstation_nb);
1056 if(task->computation_amount)
1057 memcpy(computation_amount, task->computation_amount, sizeof(double) *
1059 if(task->communication_amount)
1060 memcpy(communication_amount, task->communication_amount,
1061 sizeof(double) * workstation_nb * workstation_nb);
1064 surf_workstation_model->extension.
1065 workstation.execute_parallel_task(workstation_nb,
1068 communication_amount,
1071 surf_workstation_model->action_data_set(task->surf_action, task);
1073 XBT_DEBUG("surf_action = %p", task->surf_action);
1077 TRACE_surf_action(task->surf_action, task->category);
1080 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
1081 __SD_task_set_state(task, SD_RUNNING);
1082 xbt_assert(__SD_task_is_running(task), "Bad state of task '%s': %d",
1083 SD_task_get_name(task), (int)SD_task_get_state(task));
1087 /* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_RUNNABLE
1088 * (ie when its dependencies are satisfied).
1089 * If one of the workstations where the task is scheduled on is busy (in sequential mode),
1090 * the task doesn't start.
1091 * Returns whether the task has started.
1093 int __SD_task_try_to_run(SD_task_t task)
1098 SD_workstation_t workstation;
1100 xbt_assert(__SD_task_is_runnable(task),
1101 "Task '%s' is not runnable! Task state: %d",
1102 SD_task_get_name(task), (int)SD_task_get_state(task));
1105 for (i = 0; i < task->workstation_nb; i++) {
1106 can_start = can_start &&
1107 !__SD_workstation_is_busy(task->workstation_list[i]);
1110 XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
1112 if (!can_start) { /* if the task cannot start and is not in the fifos yet */
1113 for (i = 0; i < task->workstation_nb; i++) {
1114 workstation = task->workstation_list[i];
1115 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1116 XBT_DEBUG("Pushing task '%s' in the fifo of workstation '%s'",
1117 SD_task_get_name(task),
1118 SD_workstation_get_name(workstation));
1119 xbt_fifo_push(workstation->task_fifo, task);
1122 __SD_task_set_state(task, SD_IN_FIFO);
1123 xbt_assert(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
1124 SD_task_get_name(task), (int)SD_task_get_state(task));
1125 XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
1127 __SD_task_really_run(task);
1133 /* This function is called by SD_simulate when a task is done.
1134 * It updates task->state and task->action and executes if necessary the tasks
1135 * which were waiting in fifos for the end of `task'
1137 void __SD_task_just_done(SD_task_t task)
1140 SD_workstation_t workstation;
1142 SD_task_t candidate;
1143 int candidate_nb = 0;
1144 int candidate_capacity = 8;
1145 SD_task_t *candidates;
1148 xbt_assert(__SD_task_is_running(task),
1149 "The task must be running! Task state: %d",
1150 (int)SD_task_get_state(task));
1151 xbt_assert(task->workstation_list != NULL,
1152 "Task '%s': workstation_list is NULL!",
1153 SD_task_get_name(task));
1156 candidates = xbt_new(SD_task_t, 8);
1158 __SD_task_set_state(task, SD_DONE);
1159 surf_workstation_model->action_unref(task->surf_action);
1160 task->surf_action = NULL;
1162 XBT_DEBUG("Looking for candidates");
1164 /* if the task was executed on sequential workstations,
1165 maybe we can execute the next task of the fifo for each workstation */
1166 for (i = 0; i < task->workstation_nb; i++) {
1167 workstation = task->workstation_list[i];
1168 XBT_DEBUG("Workstation '%s': access_mode = %d",
1169 SD_workstation_get_name(workstation), (int)workstation->access_mode);
1170 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1171 xbt_assert(workstation->task_fifo != NULL,
1172 "Workstation '%s' has sequential access but no fifo!",
1173 SD_workstation_get_name(workstation));
1174 xbt_assert(workstation->current_task =
1175 task, "Workstation '%s': current task should be '%s'",
1176 SD_workstation_get_name(workstation),
1177 SD_task_get_name(task));
1179 /* the task is over so we can release the workstation */
1180 workstation->current_task = NULL;
1182 XBT_DEBUG("Getting candidate in fifo");
1184 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1185 (workstation->task_fifo));
1187 if (candidate != NULL) {
1188 XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
1189 xbt_assert(__SD_task_is_in_fifo(candidate),
1190 "Bad state of candidate '%s': %d",
1191 SD_task_get_name(candidate),
1192 (int)SD_task_get_state(candidate));
1195 XBT_DEBUG("Candidate in fifo: %p", candidate);
1197 /* if there was a task waiting for my place */
1198 if (candidate != NULL) {
1199 /* Unfortunately, we are not sure yet that we can execute the task now,
1200 because the task can be waiting more deeply in some other workstation's fifos...
1201 So we memorize all candidate tasks, and then we will check for each candidate
1202 whether or not all its workstations are available. */
1204 /* realloc if necessary */
1205 if (candidate_nb == candidate_capacity) {
1206 candidate_capacity *= 2;
1208 xbt_realloc(candidates,
1209 sizeof(SD_task_t) * candidate_capacity);
1212 /* register the candidate */
1213 candidates[candidate_nb++] = candidate;
1214 candidate->fifo_checked = 0;
1219 XBT_DEBUG("Candidates found: %d", candidate_nb);
1221 /* now we check every candidate task */
1222 for (i = 0; i < candidate_nb; i++) {
1223 candidate = candidates[i];
1225 if (candidate->fifo_checked) {
1226 continue; /* we have already evaluated that task */
1229 xbt_assert(__SD_task_is_in_fifo(candidate),
1230 "Bad state of candidate '%s': %d",
1231 SD_task_get_name(candidate), (int)SD_task_get_state(candidate));
1233 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1234 workstation = candidate->workstation_list[j];
1236 /* I can start on this workstation if the workstation is shared
1237 or if I am the first task in the fifo */
1238 can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS
1240 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1241 (workstation->task_fifo));
1244 XBT_DEBUG("Candidate '%s' can start: %d", SD_task_get_name(candidate),
1247 /* now we are sure that I can start! */
1249 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1250 workstation = candidate->workstation_list[j];
1252 /* update the fifo */
1253 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1254 candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */
1255 XBT_DEBUG("Head of the fifo: '%s'",
1257 NULL) ? SD_task_get_name(candidate) : "NULL");
1258 xbt_assert(candidate == candidates[i],
1259 "Error in __SD_task_just_done: bad first task in the fifo");
1261 } /* for each workstation */
1263 /* finally execute the task */
1264 XBT_DEBUG("Task '%s' state: %d", SD_task_get_name(candidate),
1265 (int)SD_task_get_state(candidate));
1266 __SD_task_really_run(candidate);
1269 ("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
1270 SD_task_get_name(candidate), candidate->state_set,
1271 sd_global->running_task_set, __SD_task_is_running(candidate));
1272 xbt_assert(__SD_task_is_running(candidate),
1273 "Bad state of task '%s': %d",
1274 SD_task_get_name(candidate),
1275 (int)SD_task_get_state(candidate));
1276 XBT_DEBUG("Okay, the task is running.");
1279 candidate->fifo_checked = 1;
1280 } /* for each candidate */
1282 xbt_free(candidates);
1286 * Remove all dependencies associated with a task. This function is called
1287 * when the task is destroyed.
1289 static void __SD_task_remove_dependencies(SD_task_t task)
1291 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
1292 because each one is stored twice */
1293 SD_dependency_t dependency;
1294 while (!xbt_dynar_is_empty(task->tasks_before)) {
1295 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
1296 SD_task_dependency_remove(dependency->src, dependency->dst);
1299 while (!xbt_dynar_is_empty(task->tasks_after)) {
1300 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
1301 SD_task_dependency_remove(dependency->src, dependency->dst);
1306 * \brief Returns the start time of a task
1308 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1310 * \param task: a task
1311 * \return the start time of this task
1313 double SD_task_get_start_time(SD_task_t task)
1315 if (task->surf_action)
1316 return surf_workstation_model->
1317 action_get_start_time(task->surf_action);
1319 return task->start_time;
1323 * \brief Returns the finish time of a task
1325 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1326 * If the state is not completed yet, the returned value is an
1327 * estimation of the task finish time. This value can fluctuate
1328 * until the task is completed.
1330 * \param task: a task
1331 * \return the start time of this task
1333 double SD_task_get_finish_time(SD_task_t task)
1335 if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
1336 return surf_workstation_model->
1337 action_get_finish_time(task->surf_action);
1339 return task->finish_time;
1344 void SD_task_distribute_comp_amdhal(SD_task_t task, int ws_count)
1347 xbt_assert(task->kind == SD_TASK_COMP_PAR_AMDAHL,
1348 "Task %s is not a SD_TASK_COMP_PAR_AMDAHL typed task."
1349 "Cannot use this function.",
1350 SD_task_get_name(task));
1352 task->computation_amount = xbt_new0(double, ws_count);
1353 task->communication_amount = xbt_new0(double, ws_count * ws_count);
1354 task->workstation_nb = ws_count;
1355 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
1357 for(i=0;i<ws_count;i++){
1358 task->computation_amount[i] =
1359 (task->alpha + (1 - task->alpha)/ws_count) * task->amount;
1364 /** @brief Auto-schedules a task.
1366 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1367 * allows to specify the task costs at creation, and decorelate them from the
1368 * scheduling process where you just specify which resource should deliver the
1371 * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e() or
1372 * SD_task_create_comp_seq(). Check their definitions for the exact semantic of each
1376 * We should create tasks kind for the following categories:
1377 * - Point to point communication (done)
1378 * - Sequential computation (done)
1379 * - group communication (redistribution, several kinds)
1380 * - parallel tasks with no internal communication (one kind per speedup model such as amdal)
1381 * - idem+ internal communication. Task type not enough since we cannot store comm cost alongside to comp one)
1383 void SD_task_schedulev(SD_task_t task, int count,
1384 const SD_workstation_t * list)
1387 SD_dependency_t dep;
1389 xbt_assert(task->kind != 0,
1390 "Task %s is not typed. Cannot automatically schedule it.",
1391 SD_task_get_name(task));
1392 switch (task->kind) {
1393 case SD_TASK_COMP_PAR_AMDAHL:
1394 SD_task_distribute_comp_amdhal(task, count);
1395 case SD_TASK_COMM_E2E:
1396 case SD_TASK_COMP_SEQ:
1397 xbt_assert(task->workstation_nb == count,"Got %d locations, but were expecting %d locations",count,task->workstation_nb);
1398 for (i = 0; i < count; i++)
1399 task->workstation_list[i] = list[i];
1400 if (SD_task_get_kind(task)== SD_TASK_COMP_SEQ && !task->computation_amount){
1401 /*This task has failed and is rescheduled. Reset the computation amount*/
1402 task->computation_amount = xbt_new0(double, 1);
1403 task->computation_amount[0] = task->remains;
1405 SD_task_do_schedule(task);
1408 xbt_die("Kind of task %s not supported by SD_task_schedulev()",
1409 SD_task_get_name(task));
1411 if (task->kind == SD_TASK_COMM_E2E) {
1412 XBT_VERB("Schedule comm task %s between %s -> %s. It costs %.f bytes",
1413 SD_task_get_name(task),
1414 SD_workstation_get_name(task->workstation_list[0]),
1415 SD_workstation_get_name(task->workstation_list[1]),
1416 task->communication_amount[2]);
1420 /* Iterate over all childs and parent being COMM_E2E to say where I am located (and start them if runnable) */
1421 if (task->kind == SD_TASK_COMP_SEQ) {
1422 XBT_VERB("Schedule computation task %s on %s. It costs %.f flops",
1423 SD_task_get_name(task),
1424 SD_workstation_get_name(task->workstation_list[0]),
1425 task->computation_amount[0]);
1427 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1428 SD_task_t before = dep->src;
1429 if (before->kind == SD_TASK_COMM_E2E) {
1430 before->workstation_list[1] = task->workstation_list[0];
1432 if (before->workstation_list[0] &&
1433 (__SD_task_is_schedulable(before)
1434 || __SD_task_is_not_scheduled(before))) {
1435 SD_task_do_schedule(before);
1437 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1438 SD_task_get_name(before),
1439 SD_workstation_get_name(before->workstation_list[0]),
1440 SD_workstation_get_name(before->workstation_list[1]),
1441 before->communication_amount[2]);
1445 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1446 SD_task_t after = dep->dst;
1447 if (after->kind == SD_TASK_COMM_E2E) {
1448 after->workstation_list[0] = task->workstation_list[0];
1449 if (after->workstation_list[1]
1450 && (__SD_task_is_not_scheduled(after)
1451 || __SD_task_is_schedulable(after))) {
1452 SD_task_do_schedule(after);
1454 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1455 SD_task_get_name(after),
1456 SD_workstation_get_name(after->workstation_list[0]),
1457 SD_workstation_get_name(after->workstation_list[1]),
1458 after->communication_amount[2]);
1464 /* Iterate over all childs and parent being MXN_1D_BLOC to say where I am located (and start them if runnable) */
1465 if (task->kind == SD_TASK_COMP_PAR_AMDAHL) {
1466 XBT_VERB("Schedule computation task %s on %d workstations. %.f flops"
1467 " will be distributed following Amdahl'Law",
1468 SD_task_get_name(task), task->workstation_nb,
1469 task->computation_amount[0]);
1470 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1471 SD_task_t before = dep->src;
1472 if (before->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1473 if (!before->workstation_list){
1474 XBT_VERB("Sender side of Task %s is not scheduled yet. Fill the workstation list with receiver side",
1475 SD_task_get_name(before));
1476 before->workstation_list = xbt_new0(SD_workstation_t, count);
1477 before->workstation_nb = count;
1478 for (i=0;i<count;i++)
1479 before->workstation_list[i] = task->workstation_list[i];
1482 double src_start, src_end, dst_start, dst_end;
1483 src_nb = before->workstation_nb;
1485 before->workstation_list = (SD_workstation_t*) xbt_realloc(
1486 before->workstation_list,
1487 (before->workstation_nb+count)*sizeof(s_SD_workstation_t));
1488 for(i=0; i<count; i++)
1489 before->workstation_list[before->workstation_nb+i] =
1490 task->workstation_list[i];
1492 before->workstation_nb += count;
1494 before->computation_amount = xbt_new0(double,
1495 before->workstation_nb);
1496 before->communication_amount = xbt_new0(double,
1497 before->workstation_nb*
1498 before->workstation_nb);
1500 for(i=0;i<src_nb;i++){
1501 src_start = i*before->amount/src_nb;
1502 src_end = src_start + before->amount/src_nb;
1503 for(j=0; j<dst_nb; j++){
1504 dst_start = j*before->amount/dst_nb;
1505 dst_end = dst_start + before->amount/dst_nb;
1506 XBT_VERB("(%s->%s): (%.2f, %.2f)-> (%.2f, %.2f)",
1507 SD_workstation_get_name(before->workstation_list[i]),
1508 SD_workstation_get_name(before->workstation_list[src_nb+j]),
1509 src_start, src_end, dst_start, dst_end);
1510 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1511 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1513 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1514 MIN(src_end, dst_end) - MAX(src_start, dst_start);
1516 XBT_VERB("==> %.2f",
1517 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1521 if (__SD_task_is_schedulable(before) ||
1522 __SD_task_is_not_scheduled(before)) {
1523 SD_task_do_schedule(before);
1525 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1526 SD_task_get_name(before),before->amount, src_nb, dst_nb);
1531 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1532 SD_task_t after = dep->dst;
1533 if (after->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1534 if (!after->workstation_list){
1535 XBT_VERB("Receiver side of Task %s is not scheduled yet. Fill the workstation list with sender side",
1536 SD_task_get_name(after));
1537 after->workstation_list = xbt_new0(SD_workstation_t, count);
1538 after->workstation_nb = count;
1539 for (i=0;i<count;i++)
1540 after->workstation_list[i] = task->workstation_list[i];
1543 double src_start, src_end, dst_start, dst_end;
1545 dst_nb = after->workstation_nb;
1546 after->workstation_list = (SD_workstation_t*) xbt_realloc(
1547 after->workstation_list,
1548 (after->workstation_nb+count)*sizeof(s_SD_workstation_t));
1549 for(i=after->workstation_nb - 1; i>=0; i--)
1550 after->workstation_list[count+i] = after->workstation_list[i];
1551 for(i=0; i<count; i++)
1552 after->workstation_list[i] = task->workstation_list[i];
1554 after->workstation_nb += count;
1556 after->computation_amount = xbt_new0(double, after->workstation_nb);
1557 after->communication_amount = xbt_new0(double,
1558 after->workstation_nb*
1559 after->workstation_nb);
1561 for(i=0;i<src_nb;i++){
1562 src_start = i*after->amount/src_nb;
1563 src_end = src_start + after->amount/src_nb;
1564 for(j=0; j<dst_nb; j++){
1565 dst_start = j*after->amount/dst_nb;
1566 dst_end = dst_start + after->amount/dst_nb;
1567 XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)",
1568 i, j, src_start, src_end, dst_start, dst_end);
1569 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1570 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1572 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1573 MIN(src_end, dst_end)- MAX(src_start, dst_start);
1575 XBT_VERB("==> %.2f",
1576 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1580 if (__SD_task_is_schedulable(after) ||
1581 __SD_task_is_not_scheduled(after)) {
1582 SD_task_do_schedule(after);
1584 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1585 SD_task_get_name(after),after->amount, src_nb, dst_nb);
1593 /** @brief autoschedule a task on a list of workstations
1595 * This function is very similar to SD_task_schedulev(),
1596 * but takes the list of workstations to schedule onto as separate parameters.
1597 * It builds a proper vector of workstations and then call SD_task_schedulev()
1599 void SD_task_schedulel(SD_task_t task, int count, ...)
1602 SD_workstation_t *list = xbt_new(SD_workstation_t, count);
1604 va_start(ap, count);
1605 for (i = 0; i < count; i++) {
1606 list[i] = va_arg(ap, SD_workstation_t);
1609 SD_task_schedulev(task, count, list);
1614 * \brief Sets the tracing category of a task.
1616 * This function should be called after the creation of a
1617 * SimDAG task, to define the category of that task. The first
1618 * parameter must contain a task that was created with the
1619 * function #SD_task_create. The second parameter must contain
1620 * a category that was previously declared with the function
1623 * \param task The task to be considered
1624 * \param category the name of the category to be associated to the task
1626 * \see SD_task_get_category, TRACE_category, TRACE_category_with_color
1628 void SD_task_set_category (SD_task_t task, const char *category)
1631 if (!TRACE_is_enabled()) return;
1632 if (task == NULL) return;
1633 if (category == NULL){
1634 if (task->category) xbt_free (task->category);
1635 task->category = NULL;
1637 task->category = xbt_strdup (category);
1643 * \brief Gets the current tracing category of a task.
1645 * \param task The task to be considered
1647 * \see SD_task_set_category
1649 * \return Returns the name of the tracing category of the given task, NULL otherwise
1651 const char *SD_task_get_category (SD_task_t task)
1654 return task->category;