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: %d", 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);
638 * \brief Indicates whether there is a dependency between two tasks.
641 * \param dst a task depending on \a src
643 * If src is NULL, checks whether dst has any pre-dependency.
644 * If dst is NULL, checks whether src has any post-dependency.
646 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
648 unsigned int counter;
649 SD_dependency_t dependency;
651 xbt_assert(src != NULL
653 "Invalid parameter: both src and dst are NULL");
657 xbt_dynar_foreach(src->tasks_after, counter, dependency) {
658 if (dependency->dst == dst)
662 return xbt_dynar_length(src->tasks_after);
665 return xbt_dynar_length(dst->tasks_before);
671 * \brief Remove a dependency between two tasks
674 * \param dst a task depending on \a src
675 * \see SD_task_dependency_add()
677 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
684 SD_dependency_t dependency;
686 /* remove the dependency from src->tasks_after */
687 dynar = src->tasks_after;
688 length = xbt_dynar_length(dynar);
690 for (i = 0; i < length && !found; i++) {
691 xbt_dynar_get_cpy(dynar, i, &dependency);
692 if (dependency->dst == dst) {
693 xbt_dynar_remove_at(dynar, i, NULL);
699 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
700 SD_task_get_name(src), SD_task_get_name(dst),
701 SD_task_get_name(dst), SD_task_get_name(src));
703 /* remove the dependency from dst->tasks_before */
704 dynar = dst->tasks_before;
705 length = xbt_dynar_length(dynar);
708 for (i = 0; i < length && !found; i++) {
709 xbt_dynar_get_cpy(dynar, i, &dependency);
710 if (dependency->src == src) {
711 xbt_dynar_remove_at(dynar, i, NULL);
712 __SD_task_dependency_destroy(dependency);
713 dst->unsatisfied_dependencies--;
718 /* should never happen... */
720 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
721 SD_task_get_name(dst), SD_task_get_name(src),
722 SD_task_get_name(src), SD_task_get_name(dst));
724 /* if the task was scheduled and dst->tasks_before is empty now, we can make it runnable */
726 if (dst->unsatisfied_dependencies == 0) {
727 if (__SD_task_is_scheduled(dst))
728 __SD_task_set_state(dst, SD_RUNNABLE);
730 __SD_task_set_state(dst, SD_SCHEDULABLE);
733 if (dst->is_not_ready == 0)
734 __SD_task_set_state(dst, SD_SCHEDULABLE);
736 /* __SD_print_dependencies(src);
737 __SD_print_dependencies(dst); */
741 * \brief Returns the user data associated with a dependency between two tasks
744 * \param dst a task depending on \a src
745 * \return the user data associated with this dependency (can be \c NULL)
746 * \see SD_task_dependency_add()
748 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
755 SD_dependency_t dependency;
757 dynar = src->tasks_after;
758 length = xbt_dynar_length(dynar);
760 for (i = 0; i < length && !found; i++) {
761 xbt_dynar_get_cpy(dynar, i, &dependency);
762 found = (dependency->dst == dst);
765 THROWF(arg_error, 0, "No dependency found between task '%s' and '%s'",
766 SD_task_get_name(src), SD_task_get_name(dst));
767 return dependency->data;
770 /* temporary function for debugging */
771 static void __SD_print_watch_points(SD_task_t task)
773 static const int state_masks[] =
774 { SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNING, SD_RUNNABLE, SD_DONE,
777 static const char *state_names[] =
778 { "schedulable", "scheduled", "running", "runnable", "done",
783 XBT_INFO("Task '%s' watch points (%x): ", SD_task_get_name(task),
787 for (i = 0; i < 5; i++) {
788 if (task->watch_points & state_masks[i])
789 XBT_INFO("%s ", state_names[i]);
794 * \brief Adds a watch point to a task
796 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
797 * task becomes the one given in argument. The
798 * watch point is then automatically removed.
801 * \param state the \ref e_SD_task_state_t "state" you want to watch
802 * (cannot be #SD_NOT_SCHEDULED)
803 * \see SD_task_unwatch()
805 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
807 if (state & SD_NOT_SCHEDULED)
809 "Cannot add a watch point for state SD_NOT_SCHEDULED");
811 task->watch_points = task->watch_points | state;
812 /* __SD_print_watch_points(task); */
816 * \brief Removes a watch point from a task
819 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
820 * \see SD_task_watch()
822 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
824 xbt_assert(state != SD_NOT_SCHEDULED,
825 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
827 task->watch_points = task->watch_points & ~state;
828 /* __SD_print_watch_points(task); */
832 * \brief Returns an approximative estimation of the execution time of a task.
834 * The estimation is very approximative because the value returned is the time
835 * the task would take if it was executed now and if it was the only task.
837 * \param task the task to evaluate
838 * \param workstation_nb number of workstations on which the task would be executed
839 * \param workstation_list the workstations on which the task would be executed
840 * \param computation_amount computation amount for each workstation
841 * \param communication_amount communication amount between each pair of workstations
844 double SD_task_get_execution_time(SD_task_t task,
846 const SD_workstation_t *
848 const double *computation_amount,
849 const double *communication_amount)
851 double time, max_time = 0.0;
853 xbt_assert(workstation_nb > 0, "Invalid parameter");
855 /* the task execution time is the maximum execution time of the parallel tasks */
857 for (i = 0; i < workstation_nb; i++) {
859 if (computation_amount != NULL)
861 SD_workstation_get_computation_time(workstation_list[i],
862 computation_amount[i]);
864 if (communication_amount != NULL)
865 for (j = 0; j < workstation_nb; j++) {
867 SD_route_get_communication_time(workstation_list[i],
869 communication_amount[i *
874 if (time > max_time) {
881 static XBT_INLINE void SD_task_do_schedule(SD_task_t task)
883 if (!__SD_task_is_not_scheduled(task) && !__SD_task_is_schedulable(task))
884 THROWF(arg_error, 0, "Task '%s' has already been scheduled",
885 SD_task_get_name(task));
887 /* update the task state */
888 if (task->unsatisfied_dependencies == 0)
889 __SD_task_set_state(task, SD_RUNNABLE);
891 __SD_task_set_state(task, SD_SCHEDULED);
895 * \brief Schedules a task
897 * The task state must be #SD_NOT_SCHEDULED.
898 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
899 * i.e. when its dependencies are satisfied.
901 * \param task the task you want to schedule
902 * \param workstation_count number of workstations on which the task will be executed
903 * \param workstation_list the workstations on which the task will be executed
904 * \param computation_amount computation amount for each workstation
905 * \param communication_amount communication amount between each pair of workstations
906 * \param rate task execution speed rate
907 * \see SD_task_unschedule()
909 void SD_task_schedule(SD_task_t task, int workstation_count,
910 const SD_workstation_t * workstation_list,
911 const double *computation_amount,
912 const double *communication_amount, double rate)
914 int communication_nb;
915 task->workstation_nb = 0;
917 xbt_assert(workstation_count > 0, "workstation_nb must be positive");
919 task->workstation_nb = workstation_count;
922 if (computation_amount) {
923 task->computation_amount = xbt_realloc(task->computation_amount,
924 sizeof(double) * workstation_count);
925 memcpy(task->computation_amount, computation_amount,
926 sizeof(double) * workstation_count);
928 xbt_free(task->computation_amount);
929 task->computation_amount = NULL;
932 communication_nb = workstation_count * workstation_count;
933 if (communication_amount) {
934 task->communication_amount = xbt_realloc(task->communication_amount,
935 sizeof(double) * communication_nb);
936 memcpy(task->communication_amount, communication_amount,
937 sizeof(double) * communication_nb);
939 xbt_free(task->communication_amount);
940 task->communication_amount = NULL;
943 task->workstation_list =
944 xbt_realloc(task->workstation_list,
945 sizeof(SD_workstation_t) * workstation_count);
946 memcpy(task->workstation_list, workstation_list,
947 sizeof(SD_workstation_t) * workstation_count);
949 SD_task_do_schedule(task);
953 * \brief Unschedules a task
955 * The task state must be #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING or #SD_FAILED.
956 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
957 * Call SD_task_schedule() to schedule it again.
959 * \param task the task you want to unschedule
960 * \see SD_task_schedule()
962 void SD_task_unschedule(SD_task_t task)
964 if (task->state_set != sd_global->scheduled_task_set &&
965 task->state_set != sd_global->runnable_task_set &&
966 task->state_set != sd_global->running_task_set &&
967 task->state_set != sd_global->failed_task_set)
969 "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED",
970 SD_task_get_name(task));
972 if (__SD_task_is_scheduled_or_runnable(task) /* if the task is scheduled or runnable */
973 && ((task->kind == SD_TASK_COMP_PAR_AMDAHL) ||
974 (task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK))) { /* Don't free scheduling data for typed tasks */
975 __SD_task_destroy_scheduling_data(task);
976 task->workstation_list=NULL;
977 task->workstation_nb = 0;
980 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
981 surf_workstation_model->action_cancel(task->surf_action);
983 if (task->unsatisfied_dependencies == 0)
984 __SD_task_set_state(task, SD_SCHEDULABLE);
986 __SD_task_set_state(task, SD_NOT_SCHEDULED);
988 task->remains = task->amount;
989 task->start_time = -1.0;
992 /* Destroys the data memorized by SD_task_schedule.
993 * Task state must be SD_SCHEDULED or SD_RUNNABLE.
995 static void __SD_task_destroy_scheduling_data(SD_task_t task)
997 if (!__SD_task_is_scheduled_or_runnable(task)
998 && !__SD_task_is_in_fifo(task))
1000 "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
1001 SD_task_get_name(task));
1003 xbt_free(task->computation_amount);
1004 xbt_free(task->communication_amount);
1005 task->computation_amount = task->communication_amount = NULL;
1008 /* Runs a task. This function is directly called by __SD_task_try_to_run if
1009 * the task doesn't have to wait in FIFOs. Otherwise, it is called by
1010 * __SD_task_just_done when the task gets out of its FIFOs.
1012 void __SD_task_really_run(SD_task_t task)
1016 void **surf_workstations;
1018 xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
1019 "Task '%s' is not runnable or in a fifo! Task state: %d",
1020 SD_task_get_name(task), (int)SD_task_get_state(task));
1021 xbt_assert(task->workstation_list != NULL,
1022 "Task '%s': workstation_list is NULL!",
1023 SD_task_get_name(task));
1025 XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
1026 int workstation_nb = task->workstation_nb;
1028 /* set this task as current task for the workstations in sequential mode */
1029 for (i = 0; i < workstation_nb; i++) {
1030 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
1031 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1032 task->workstation_list[i]->current_task = task;
1033 xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
1034 "The workstation should be busy now");
1038 XBT_DEBUG("Task '%s' set as current task for its workstations",
1039 SD_task_get_name(task));
1041 /* start the task */
1043 /* we have to create a Surf workstation array instead of the SimDag
1044 * workstation array */
1045 surf_workstations = xbt_new(void *, workstation_nb);
1047 for (i = 0; i < workstation_nb; i++)
1048 surf_workstations[i] = task->workstation_list[i]->surf_workstation;
1050 double *computation_amount = xbt_new0(double, workstation_nb);
1051 double *communication_amount = xbt_new0(double, workstation_nb * workstation_nb);
1054 if(task->computation_amount)
1055 memcpy(computation_amount, task->computation_amount, sizeof(double) *
1057 if(task->communication_amount)
1058 memcpy(communication_amount, task->communication_amount,
1059 sizeof(double) * workstation_nb * workstation_nb);
1062 surf_workstation_model->extension.
1063 workstation.execute_parallel_task(workstation_nb,
1066 communication_amount,
1069 surf_workstation_model->action_data_set(task->surf_action, task);
1071 XBT_DEBUG("surf_action = %p", task->surf_action);
1075 TRACE_surf_action(task->surf_action, task->category);
1078 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
1079 __SD_task_set_state(task, SD_RUNNING);
1080 xbt_assert(__SD_task_is_running(task), "Bad state of task '%s': %d",
1081 SD_task_get_name(task), (int)SD_task_get_state(task));
1085 /* Tries to run a task. This function is called by SD_simulate() when a
1086 * scheduled task becomes SD_RUNNABLE (i.e., when its dependencies are
1088 * If one of the workstations where the task is scheduled on is busy (in
1089 * sequential mode), the task doesn't start.
1090 * Returns whether the task has started.
1092 int __SD_task_try_to_run(SD_task_t task)
1097 SD_workstation_t workstation;
1099 xbt_assert(__SD_task_is_runnable(task),
1100 "Task '%s' is not runnable! Task state: %d",
1101 SD_task_get_name(task), (int)SD_task_get_state(task));
1104 for (i = 0; i < task->workstation_nb; i++) {
1105 can_start = can_start &&
1106 !__SD_workstation_is_busy(task->workstation_list[i]);
1109 XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
1111 if (!can_start) { /* if the task cannot start and is not in the FIFOs yet */
1112 for (i = 0; i < task->workstation_nb; i++) {
1113 workstation = task->workstation_list[i];
1114 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1115 XBT_DEBUG("Pushing task '%s' in the FIFO of workstation '%s'",
1116 SD_task_get_name(task),
1117 SD_workstation_get_name(workstation));
1118 xbt_fifo_push(workstation->task_fifo, task);
1121 __SD_task_set_state(task, SD_IN_FIFO);
1122 xbt_assert(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
1123 SD_task_get_name(task), (int)SD_task_get_state(task));
1124 XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
1126 __SD_task_really_run(task);
1132 /* This function is called by SD_simulate when a task is done.
1133 * It updates task->state and task->action and executes if necessary the tasks
1134 * which were waiting in FIFOs for the end of `task'
1136 void __SD_task_just_done(SD_task_t task)
1139 SD_workstation_t workstation;
1141 SD_task_t candidate;
1142 int candidate_nb = 0;
1143 int candidate_capacity = 8;
1144 SD_task_t *candidates;
1147 xbt_assert(__SD_task_is_running(task),
1148 "The task must be running! Task state: %d",
1149 (int)SD_task_get_state(task));
1150 xbt_assert(task->workstation_list != NULL,
1151 "Task '%s': workstation_list is NULL!",
1152 SD_task_get_name(task));
1155 candidates = xbt_new(SD_task_t, 8);
1157 __SD_task_set_state(task, SD_DONE);
1158 surf_workstation_model->action_unref(task->surf_action);
1159 task->surf_action = NULL;
1161 XBT_DEBUG("Looking for candidates");
1163 /* if the task was executed on sequential workstations,
1164 maybe we can execute the next task of the FIFO for each workstation */
1165 for (i = 0; i < task->workstation_nb; i++) {
1166 workstation = task->workstation_list[i];
1167 XBT_DEBUG("Workstation '%s': access_mode = %d",
1168 SD_workstation_get_name(workstation), (int)workstation->access_mode);
1169 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1170 xbt_assert(workstation->task_fifo != NULL,
1171 "Workstation '%s' has sequential access but no FIFO!",
1172 SD_workstation_get_name(workstation));
1173 xbt_assert(workstation->current_task =
1174 task, "Workstation '%s': current task should be '%s'",
1175 SD_workstation_get_name(workstation),
1176 SD_task_get_name(task));
1178 /* the task is over so we can release the workstation */
1179 workstation->current_task = NULL;
1181 XBT_DEBUG("Getting candidate in FIFO");
1183 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1184 (workstation->task_fifo));
1186 if (candidate != NULL) {
1187 XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
1188 xbt_assert(__SD_task_is_in_fifo(candidate),
1189 "Bad state of candidate '%s': %d",
1190 SD_task_get_name(candidate),
1191 (int)SD_task_get_state(candidate));
1194 XBT_DEBUG("Candidate in fifo: %p", candidate);
1196 /* if there was a task waiting for my place */
1197 if (candidate != NULL) {
1198 /* Unfortunately, we are not sure yet that we can execute the task now,
1199 because the task can be waiting more deeply in some other
1200 workstation's FIFOs ...
1201 So we memorize all candidate tasks, and then we will check for each
1202 candidate 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 decouple 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()
1372 * or SD_task_create_comp_seq(). Check their definitions for the exact semantic
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
1381 * model such as Amdahl)
1382 * - idem+ internal communication. Task type not enough since we cannot store
1383 * comm cost alongside to comp one)
1385 void SD_task_schedulev(SD_task_t task, int count,
1386 const SD_workstation_t * list)
1389 SD_dependency_t dep;
1391 xbt_assert(task->kind != 0,
1392 "Task %s is not typed. Cannot automatically schedule it.",
1393 SD_task_get_name(task));
1394 switch (task->kind) {
1395 case SD_TASK_COMP_PAR_AMDAHL:
1396 SD_task_distribute_comp_amdhal(task, count);
1397 case SD_TASK_COMM_E2E:
1398 case SD_TASK_COMP_SEQ:
1399 xbt_assert(task->workstation_nb == count,
1400 "Got %d locations, but were expecting %d locations",
1401 count,task->workstation_nb);
1402 for (i = 0; i < count; i++)
1403 task->workstation_list[i] = list[i];
1404 if (SD_task_get_kind(task)== SD_TASK_COMP_SEQ && !task->computation_amount){
1405 /*This task has failed and is rescheduled. Reset the computation amount*/
1406 task->computation_amount = xbt_new0(double, 1);
1407 task->computation_amount[0] = task->remains;
1409 SD_task_do_schedule(task);
1412 xbt_die("Kind of task %s not supported by SD_task_schedulev()",
1413 SD_task_get_name(task));
1415 if (task->kind == SD_TASK_COMM_E2E) {
1416 XBT_VERB("Schedule comm task %s between %s -> %s. It costs %.f bytes",
1417 SD_task_get_name(task),
1418 SD_workstation_get_name(task->workstation_list[0]),
1419 SD_workstation_get_name(task->workstation_list[1]),
1420 task->communication_amount[2]);
1424 /* Iterate over all children and parents being COMM_E2E to say where I am
1425 * located (and start them if runnable) */
1426 if (task->kind == SD_TASK_COMP_SEQ) {
1427 XBT_VERB("Schedule computation task %s on %s. It costs %.f flops",
1428 SD_task_get_name(task),
1429 SD_workstation_get_name(task->workstation_list[0]),
1430 task->computation_amount[0]);
1432 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1433 SD_task_t before = dep->src;
1434 if (before->kind == SD_TASK_COMM_E2E) {
1435 before->workstation_list[1] = task->workstation_list[0];
1437 if (before->workstation_list[0] &&
1438 (__SD_task_is_schedulable(before)
1439 || __SD_task_is_not_scheduled(before))) {
1440 SD_task_do_schedule(before);
1442 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1443 SD_task_get_name(before),
1444 SD_workstation_get_name(before->workstation_list[0]),
1445 SD_workstation_get_name(before->workstation_list[1]),
1446 before->communication_amount[2]);
1450 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1451 SD_task_t after = dep->dst;
1452 if (after->kind == SD_TASK_COMM_E2E) {
1453 after->workstation_list[0] = task->workstation_list[0];
1454 if (after->workstation_list[1]
1455 && (__SD_task_is_not_scheduled(after)
1456 || __SD_task_is_schedulable(after))) {
1457 SD_task_do_schedule(after);
1459 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1460 SD_task_get_name(after),
1461 SD_workstation_get_name(after->workstation_list[0]),
1462 SD_workstation_get_name(after->workstation_list[1]),
1463 after->communication_amount[2]);
1469 /* Iterate over all children and parents being MXN_1D_BLOCK to say where I am
1470 * located (and start them if runnable) */
1471 if (task->kind == SD_TASK_COMP_PAR_AMDAHL) {
1472 XBT_VERB("Schedule computation task %s on %d workstations. %.f flops"
1473 " will be distributed following Amdahl'Law",
1474 SD_task_get_name(task), task->workstation_nb,
1475 task->computation_amount[0]);
1476 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1477 SD_task_t before = dep->src;
1478 if (before->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1479 if (!before->workstation_list){
1480 XBT_VERB("Sender side of Task %s is not scheduled yet. Fill the workstation list with receiver side",
1481 SD_task_get_name(before));
1482 before->workstation_list = xbt_new0(SD_workstation_t, count);
1483 before->workstation_nb = count;
1484 for (i=0;i<count;i++)
1485 before->workstation_list[i] = task->workstation_list[i];
1488 double src_start, src_end, dst_start, dst_end;
1489 src_nb = before->workstation_nb;
1491 before->workstation_list = (SD_workstation_t*) xbt_realloc(
1492 before->workstation_list,
1493 (before->workstation_nb+count)*sizeof(s_SD_workstation_t));
1494 for(i=0; i<count; i++)
1495 before->workstation_list[before->workstation_nb+i] =
1496 task->workstation_list[i];
1498 before->workstation_nb += count;
1500 before->computation_amount = xbt_new0(double,
1501 before->workstation_nb);
1502 before->communication_amount = xbt_new0(double,
1503 before->workstation_nb*
1504 before->workstation_nb);
1506 for(i=0;i<src_nb;i++){
1507 src_start = i*before->amount/src_nb;
1508 src_end = src_start + before->amount/src_nb;
1509 for(j=0; j<dst_nb; j++){
1510 dst_start = j*before->amount/dst_nb;
1511 dst_end = dst_start + before->amount/dst_nb;
1512 XBT_VERB("(%s->%s): (%.2f, %.2f)-> (%.2f, %.2f)",
1513 SD_workstation_get_name(before->workstation_list[i]),
1514 SD_workstation_get_name(before->workstation_list[src_nb+j]),
1515 src_start, src_end, dst_start, dst_end);
1516 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1517 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1519 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1520 MIN(src_end, dst_end) - MAX(src_start, dst_start);
1522 XBT_VERB("==> %.2f",
1523 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1527 if (__SD_task_is_schedulable(before) ||
1528 __SD_task_is_not_scheduled(before)) {
1529 SD_task_do_schedule(before);
1531 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1532 SD_task_get_name(before),before->amount, src_nb, dst_nb);
1537 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1538 SD_task_t after = dep->dst;
1539 if (after->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1540 if (!after->workstation_list){
1541 XBT_VERB("Receiver side of Task %s is not scheduled yet. Fill the workstation list with sender side",
1542 SD_task_get_name(after));
1543 after->workstation_list = xbt_new0(SD_workstation_t, count);
1544 after->workstation_nb = count;
1545 for (i=0;i<count;i++)
1546 after->workstation_list[i] = task->workstation_list[i];
1549 double src_start, src_end, dst_start, dst_end;
1551 dst_nb = after->workstation_nb;
1552 after->workstation_list = (SD_workstation_t*) xbt_realloc(
1553 after->workstation_list,
1554 (after->workstation_nb+count)*sizeof(s_SD_workstation_t));
1555 for(i=after->workstation_nb - 1; i>=0; i--)
1556 after->workstation_list[count+i] = after->workstation_list[i];
1557 for(i=0; i<count; i++)
1558 after->workstation_list[i] = task->workstation_list[i];
1560 after->workstation_nb += count;
1562 after->computation_amount = xbt_new0(double, after->workstation_nb);
1563 after->communication_amount = xbt_new0(double,
1564 after->workstation_nb*
1565 after->workstation_nb);
1567 for(i=0;i<src_nb;i++){
1568 src_start = i*after->amount/src_nb;
1569 src_end = src_start + after->amount/src_nb;
1570 for(j=0; j<dst_nb; j++){
1571 dst_start = j*after->amount/dst_nb;
1572 dst_end = dst_start + after->amount/dst_nb;
1573 XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)",
1574 i, j, src_start, src_end, dst_start, dst_end);
1575 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1576 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1578 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1579 MIN(src_end, dst_end)- MAX(src_start, dst_start);
1581 XBT_VERB("==> %.2f",
1582 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1586 if (__SD_task_is_schedulable(after) ||
1587 __SD_task_is_not_scheduled(after)) {
1588 SD_task_do_schedule(after);
1590 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1591 SD_task_get_name(after),after->amount, src_nb, dst_nb);
1599 /** @brief autoschedule a task on a list of workstations
1601 * This function is very similar to SD_task_schedulev(),
1602 * but takes the list of workstations to schedule onto as separate parameters.
1603 * It builds a proper vector of workstations and then call SD_task_schedulev()
1605 void SD_task_schedulel(SD_task_t task, int count, ...)
1608 SD_workstation_t *list = xbt_new(SD_workstation_t, count);
1610 va_start(ap, count);
1611 for (i = 0; i < count; i++) {
1612 list[i] = va_arg(ap, SD_workstation_t);
1615 SD_task_schedulev(task, count, list);
1620 * \brief Sets the tracing category of a task.
1622 * This function should be called after the creation of a
1623 * SimDAG task, to define the category of that task. The first
1624 * parameter must contain a task that was created with the
1625 * function #SD_task_create. The second parameter must contain
1626 * a category that was previously declared with the function
1629 * \param task The task to be considered
1630 * \param category the name of the category to be associated to the task
1632 * \see SD_task_get_category, TRACE_category, TRACE_category_with_color
1634 void SD_task_set_category (SD_task_t task, const char *category)
1637 if (!TRACE_is_enabled()) return;
1638 if (task == NULL) return;
1639 if (category == NULL){
1640 if (task->category) xbt_free (task->category);
1641 task->category = NULL;
1643 task->category = xbt_strdup (category);
1649 * \brief Gets the current tracing category of a task.
1651 * \param task The task to be considered
1653 * \see SD_task_set_category
1655 * \return Returns the name of the tracing category of the given task, NULL otherwise
1657 const char *SD_task_get_category (SD_task_t task)
1660 return task->category;