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);
242 xbt_mallocator_release(sd_global->task_mallocator,task);
243 sd_global->task_number--;
246 if (task->category) xbt_free(task->category);
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 percentage of the available power or network bandwidth
286 * \param rate the new rate you want to associate with this task
288 void SD_task_set_rate(SD_task_t task, double rate)
294 * \brief Returns the state of a task
297 * \return the current \ref e_SD_task_state_t "state" of this task:
298 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING, #SD_DONE or #SD_FAILED
299 * \see e_SD_task_state_t
301 e_SD_task_state_t SD_task_get_state(SD_task_t task)
306 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
308 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
310 xbt_swag_remove(task, task->state_set);
312 case SD_NOT_SCHEDULED:
313 task->state_set = sd_global->not_scheduled_task_set;
316 task->state_set = sd_global->schedulable_task_set;
319 task->state_set = sd_global->scheduled_task_set;
322 task->state_set = sd_global->runnable_task_set;
325 task->state_set = sd_global->in_fifo_task_set;
328 task->state_set = sd_global->running_task_set;
330 surf_workstation_model->action_get_start_time(task->surf_action);
333 task->state_set = sd_global->done_task_set;
335 surf_workstation_model->action_get_finish_time(task->surf_action);
338 jedule_log_sd_event(task);
342 task->state_set = sd_global->failed_task_set;
345 xbt_die( "Invalid state");
347 xbt_swag_insert(task, task->state_set);
348 task->state = new_state;
350 if (task->watch_points & new_state) {
351 XBT_VERB("Watch point reached with task '%s'!", SD_task_get_name(task));
352 sd_global->watch_point_reached = 1;
353 SD_task_unwatch(task, new_state); /* remove the watch point */
358 * \brief Returns the name of a task
361 * \return the name of this task (can be \c NULL)
363 const char *SD_task_get_name(SD_task_t task)
368 /** @brief Allows to change the name of a task */
369 void SD_task_set_name(SD_task_t task, const char *name)
371 xbt_free(task->name);
372 task->name = xbt_strdup(name);
375 /** @brief Returns the dynar of the parents of a task
378 * \return a newly allocated dynar comprising the parents of this task
381 xbt_dynar_t SD_task_get_parents(SD_task_t task)
387 parents = xbt_dynar_new(sizeof(SD_task_t), NULL);
388 xbt_dynar_foreach(task->tasks_before, i, dep) {
389 xbt_dynar_push(parents, &(dep->src));
394 /** @brief Returns the dynar of the parents of a task
397 * \return a newly allocated dynar comprising the parents of this task
399 xbt_dynar_t SD_task_get_children(SD_task_t task)
402 xbt_dynar_t children;
405 children = xbt_dynar_new(sizeof(SD_task_t), NULL);
406 xbt_dynar_foreach(task->tasks_after, i, dep) {
407 xbt_dynar_push(children, &(dep->dst));
413 * \brief Returns the amount of workstations involved in a task
415 * Only call this on already scheduled tasks!
418 int SD_task_get_workstation_count(SD_task_t task)
420 return task->workstation_nb;
424 * \brief Returns the list of workstations involved in a task
426 * Only call this on already scheduled tasks!
429 SD_workstation_t *SD_task_get_workstation_list(SD_task_t task)
431 return task->workstation_list;
435 * \brief Returns the total amount of work contained in a task
438 * \return the total amount of work (computation or data transfer) for this task
439 * \see SD_task_get_remaining_amount()
441 double SD_task_get_amount(SD_task_t task)
447 * \brief Returns the remaining amount work to do till the completion of a task
450 * \return the remaining amount of work (computation or data transfer) of this task
451 * \see SD_task_get_amount()
453 double SD_task_get_remaining_amount(SD_task_t task)
455 if (task->surf_action)
456 return surf_workstation_model->get_remains(task->surf_action);
458 return task->remains;
461 int SD_task_get_kind(SD_task_t task)
466 /** @brief Displays debugging informations about a task */
467 void SD_task_dump(SD_task_t task)
469 unsigned int counter;
470 SD_dependency_t dependency;
473 XBT_INFO("Displaying task %s", SD_task_get_name(task));
474 statename = bprintf("%s %s %s %s %s %s %s %s",
475 (task->state & SD_NOT_SCHEDULED ? "not scheduled" :
477 (task->state & SD_SCHEDULABLE ? "schedulable" : ""),
478 (task->state & SD_SCHEDULED ? "scheduled" : ""),
479 (task->state & SD_RUNNABLE ? "runnable" :
481 (task->state & SD_IN_FIFO ? "in fifo" : ""),
482 (task->state & SD_RUNNING ? "running" : ""),
483 (task->state & SD_DONE ? "done" : ""),
484 (task->state & SD_FAILED ? "failed" : ""));
485 XBT_INFO(" - state: %s", statename);
488 if (task->kind != 0) {
489 switch (task->kind) {
490 case SD_TASK_COMM_E2E:
491 XBT_INFO(" - kind: end-to-end communication");
493 case SD_TASK_COMP_SEQ:
494 XBT_INFO(" - kind: sequential computation");
496 case SD_TASK_COMP_PAR_AMDAHL:
497 XBT_INFO(" - kind: parallel computation following Amdahl's law");
500 XBT_INFO(" - (unknown kind %d)", task->kind);
503 XBT_INFO(" - amount: %.0f", SD_task_get_amount(task));
504 XBT_INFO(" - Dependencies to satisfy: %u", task->unsatisfied_dependencies);
505 if (!xbt_dynar_is_empty(task->tasks_before)) {
506 XBT_INFO(" - pre-dependencies:");
507 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
508 XBT_INFO(" %s", SD_task_get_name(dependency->src));
511 if (!xbt_dynar_is_empty(task->tasks_after)) {
512 XBT_INFO(" - post-dependencies:");
513 xbt_dynar_foreach(task->tasks_after, counter, dependency) {
514 XBT_INFO(" %s", SD_task_get_name(dependency->dst));
519 /** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */
520 void SD_task_dotty(SD_task_t task, void *out)
522 unsigned int counter;
523 SD_dependency_t dependency;
524 fprintf(out, " T%p [label=\"%.20s\"", task, task->name);
525 switch (task->kind) {
526 case SD_TASK_COMM_E2E:
527 fprintf(out, ", shape=box");
529 case SD_TASK_COMP_SEQ:
530 fprintf(out, ", shape=circle");
533 xbt_die("Unknown task type!");
535 fprintf(out, "];\n");
536 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
537 fprintf(out, " T%p -> T%p;\n", dependency->src, dependency->dst);
541 /* Destroys a dependency between two tasks.
543 static void __SD_task_dependency_destroy(void *dependency)
545 xbt_free(((SD_dependency_t)dependency)->name);
546 xbt_free(dependency);
550 * \brief Adds a dependency between two tasks
552 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
553 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_RUNNABLE.
555 * \param name the name of the new dependency (can be \c NULL)
556 * \param data the user data you want to associate with this dependency (can be \c NULL)
557 * \param src the task which must be executed first
558 * \param dst the task you want to make depend on \a src
559 * \see SD_task_dependency_remove()
561 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
568 SD_dependency_t dependency;
570 dynar = src->tasks_after;
571 length = xbt_dynar_length(dynar);
575 "Cannot add a dependency between task '%s' and itself",
576 SD_task_get_name(src));
578 if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_schedulable(src)
579 && !__SD_task_is_scheduled_or_runnable(src) && !__SD_task_is_running(src))
581 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE"
583 SD_task_get_name(src));
585 if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_schedulable(dst)
586 && !__SD_task_is_scheduled_or_runnable(dst))
588 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE",
589 SD_task_get_name(dst));
591 XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s",
592 SD_task_get_name(src), SD_task_get_name(dst));
593 for (i = 0; i < length && !found; i++) {
594 xbt_dynar_get_cpy(dynar, i, &dependency);
595 found = (dependency->dst == dst);
596 XBT_DEBUG("Dependency %d: dependency->dst = %s", i,
597 SD_task_get_name(dependency->dst));
602 "A dependency already exists between task '%s' and task '%s'",
603 SD_task_get_name(src), SD_task_get_name(dst));
605 dependency = xbt_new(s_SD_dependency_t, 1);
607 dependency->name = xbt_strdup(name); /* xbt_strdup is cleaver enough to deal with NULL args itself */
608 dependency->data = data;
609 dependency->src = src;
610 dependency->dst = dst;
612 /* src must be executed before dst */
613 xbt_dynar_push(src->tasks_after, &dependency);
614 xbt_dynar_push(dst->tasks_before, &dependency);
616 dst->unsatisfied_dependencies++;
619 /* if the task was runnable, then dst->tasks_before is not empty anymore,
620 so we must go back to state SD_SCHEDULED */
621 if (__SD_task_is_runnable(dst)) {
623 ("SD_task_dependency_add: %s was runnable and becomes scheduled!",
624 SD_task_get_name(dst));
625 __SD_task_set_state(dst, SD_SCHEDULED);
628 /* __SD_print_dependencies(src);
629 __SD_print_dependencies(dst); */
633 * \brief Indicates whether there is a dependency between two tasks.
636 * \param dst a task depending on \a src
638 * If src is NULL, checks whether dst has any pre-dependency.
639 * If dst is NULL, checks whether src has any post-dependency.
641 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
643 unsigned int counter;
644 SD_dependency_t dependency;
646 xbt_assert(src != NULL
648 "Invalid parameter: both src and dst are NULL");
652 xbt_dynar_foreach(src->tasks_after, counter, dependency) {
653 if (dependency->dst == dst)
657 return xbt_dynar_length(src->tasks_after);
660 return xbt_dynar_length(dst->tasks_before);
666 * \brief Remove a dependency between two tasks
669 * \param dst a task depending on \a src
670 * \see SD_task_dependency_add()
672 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
679 SD_dependency_t dependency;
681 /* remove the dependency from src->tasks_after */
682 dynar = src->tasks_after;
683 length = xbt_dynar_length(dynar);
685 for (i = 0; i < length && !found; i++) {
686 xbt_dynar_get_cpy(dynar, i, &dependency);
687 if (dependency->dst == dst) {
688 xbt_dynar_remove_at(dynar, i, NULL);
694 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
695 SD_task_get_name(src), SD_task_get_name(dst),
696 SD_task_get_name(dst), SD_task_get_name(src));
698 /* remove the dependency from dst->tasks_before */
699 dynar = dst->tasks_before;
700 length = xbt_dynar_length(dynar);
703 for (i = 0; i < length && !found; i++) {
704 xbt_dynar_get_cpy(dynar, i, &dependency);
705 if (dependency->src == src) {
706 xbt_dynar_remove_at(dynar, i, NULL);
707 __SD_task_dependency_destroy(dependency);
708 dst->unsatisfied_dependencies--;
713 /* should never happen... */
715 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
716 SD_task_get_name(dst), SD_task_get_name(src),
717 SD_task_get_name(src), SD_task_get_name(dst));
719 /* if the task was scheduled and dst->tasks_before is empty now, we can make it runnable */
721 if (dst->unsatisfied_dependencies == 0) {
722 if (__SD_task_is_scheduled(dst))
723 __SD_task_set_state(dst, SD_RUNNABLE);
725 __SD_task_set_state(dst, SD_SCHEDULABLE);
728 if (dst->is_not_ready == 0)
729 __SD_task_set_state(dst, SD_SCHEDULABLE);
731 /* __SD_print_dependencies(src);
732 __SD_print_dependencies(dst); */
736 * \brief Returns the user data associated with a dependency between two tasks
739 * \param dst a task depending on \a src
740 * \return the user data associated with this dependency (can be \c NULL)
741 * \see SD_task_dependency_add()
743 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
750 SD_dependency_t dependency;
752 dynar = src->tasks_after;
753 length = xbt_dynar_length(dynar);
755 for (i = 0; i < length && !found; i++) {
756 xbt_dynar_get_cpy(dynar, i, &dependency);
757 found = (dependency->dst == dst);
760 THROWF(arg_error, 0, "No dependency found between task '%s' and '%s'",
761 SD_task_get_name(src), SD_task_get_name(dst));
762 return dependency->data;
765 /* temporary function for debugging */
766 static void __SD_print_watch_points(SD_task_t task)
768 static const int state_masks[] =
769 { SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNING, SD_RUNNABLE, SD_DONE,
772 static const char *state_names[] =
773 { "schedulable", "scheduled", "running", "runnable", "done",
778 XBT_INFO("Task '%s' watch points (%x): ", SD_task_get_name(task),
782 for (i = 0; i < 5; i++) {
783 if (task->watch_points & state_masks[i])
784 XBT_INFO("%s ", state_names[i]);
789 * \brief Adds a watch point to a task
791 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
792 * task becomes the one given in argument. The
793 * watch point is then automatically removed.
796 * \param state the \ref e_SD_task_state_t "state" you want to watch
797 * (cannot be #SD_NOT_SCHEDULED)
798 * \see SD_task_unwatch()
800 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
802 if (state & SD_NOT_SCHEDULED)
804 "Cannot add a watch point for state SD_NOT_SCHEDULED");
806 task->watch_points = task->watch_points | state;
807 /* __SD_print_watch_points(task); */
811 * \brief Removes a watch point from a task
814 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
815 * \see SD_task_watch()
817 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
819 xbt_assert(state != SD_NOT_SCHEDULED,
820 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
822 task->watch_points = task->watch_points & ~state;
823 /* __SD_print_watch_points(task); */
827 * \brief Returns an approximative estimation of the execution time of a task.
829 * The estimation is very approximative because the value returned is the time
830 * the task would take if it was executed now and if it was the only task.
832 * \param task the task to evaluate
833 * \param workstation_nb number of workstations on which the task would be executed
834 * \param workstation_list the workstations on which the task would be executed
835 * \param computation_amount computation amount for each workstation
836 * \param communication_amount communication amount between each pair of workstations
839 double SD_task_get_execution_time(SD_task_t task,
841 const SD_workstation_t *
843 const double *computation_amount,
844 const double *communication_amount)
846 double time, max_time = 0.0;
848 xbt_assert(workstation_nb > 0, "Invalid parameter");
850 /* the task execution time is the maximum execution time of the parallel tasks */
852 for (i = 0; i < workstation_nb; i++) {
854 if (computation_amount != NULL)
856 SD_workstation_get_computation_time(workstation_list[i],
857 computation_amount[i]);
859 if (communication_amount != NULL)
860 for (j = 0; j < workstation_nb; j++) {
862 SD_route_get_communication_time(workstation_list[i],
864 communication_amount[i *
869 if (time > max_time) {
876 static XBT_INLINE void SD_task_do_schedule(SD_task_t task)
878 if (!__SD_task_is_not_scheduled(task) && !__SD_task_is_schedulable(task))
879 THROWF(arg_error, 0, "Task '%s' has already been scheduled",
880 SD_task_get_name(task));
882 /* update the task state */
883 if (task->unsatisfied_dependencies == 0)
884 __SD_task_set_state(task, SD_RUNNABLE);
886 __SD_task_set_state(task, SD_SCHEDULED);
890 * \brief Schedules a task
892 * The task state must be #SD_NOT_SCHEDULED.
893 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
894 * i.e. when its dependencies are satisfied.
896 * \param task the task you want to schedule
897 * \param workstation_count number of workstations on which the task will be executed
898 * \param workstation_list the workstations on which the task will be executed
899 * \param computation_amount computation amount for each workstation
900 * \param communication_amount communication amount between each pair of workstations
901 * \param rate task execution speed rate
902 * \see SD_task_unschedule()
904 void SD_task_schedule(SD_task_t task, int workstation_count,
905 const SD_workstation_t * workstation_list,
906 const double *computation_amount,
907 const double *communication_amount, double rate)
909 int communication_nb;
910 task->workstation_nb = 0;
912 xbt_assert(workstation_count > 0, "workstation_nb must be positive");
914 task->workstation_nb = workstation_count;
917 if (computation_amount) {
918 task->computation_amount = xbt_realloc(task->computation_amount,
919 sizeof(double) * workstation_count);
920 memcpy(task->computation_amount, computation_amount,
921 sizeof(double) * workstation_count);
923 xbt_free(task->computation_amount);
924 task->computation_amount = NULL;
927 communication_nb = workstation_count * workstation_count;
928 if (communication_amount) {
929 task->communication_amount = xbt_realloc(task->communication_amount,
930 sizeof(double) * communication_nb);
931 memcpy(task->communication_amount, communication_amount,
932 sizeof(double) * communication_nb);
934 xbt_free(task->communication_amount);
935 task->communication_amount = NULL;
938 task->workstation_list =
939 xbt_realloc(task->workstation_list,
940 sizeof(SD_workstation_t) * workstation_count);
941 memcpy(task->workstation_list, workstation_list,
942 sizeof(SD_workstation_t) * workstation_count);
944 SD_task_do_schedule(task);
948 * \brief Unschedules a task
950 * The task state must be #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING or #SD_FAILED.
951 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
952 * Call SD_task_schedule() to schedule it again.
954 * \param task the task you want to unschedule
955 * \see SD_task_schedule()
957 void SD_task_unschedule(SD_task_t task)
959 if (task->state_set != sd_global->scheduled_task_set &&
960 task->state_set != sd_global->runnable_task_set &&
961 task->state_set != sd_global->running_task_set &&
962 task->state_set != sd_global->failed_task_set)
964 "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED",
965 SD_task_get_name(task));
967 if (__SD_task_is_scheduled_or_runnable(task) /* if the task is scheduled or runnable */
968 && ((task->kind == SD_TASK_COMP_PAR_AMDAHL) ||
969 (task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK))) { /* Don't free scheduling data for typed tasks */
970 __SD_task_destroy_scheduling_data(task);
971 task->workstation_list=NULL;
972 task->workstation_nb = 0;
975 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
976 surf_workstation_model->action_cancel(task->surf_action);
978 if (task->unsatisfied_dependencies == 0)
979 __SD_task_set_state(task, SD_SCHEDULABLE);
981 __SD_task_set_state(task, SD_NOT_SCHEDULED);
983 task->remains = task->amount;
984 task->start_time = -1.0;
987 /* Destroys the data memorized by SD_task_schedule. Task state must be SD_SCHEDULED or SD_RUNNABLE.
989 static void __SD_task_destroy_scheduling_data(SD_task_t task)
991 if (!__SD_task_is_scheduled_or_runnable(task)
992 && !__SD_task_is_in_fifo(task))
994 "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
995 SD_task_get_name(task));
997 xbt_free(task->computation_amount);
998 xbt_free(task->communication_amount);
999 task->computation_amount = task->communication_amount = NULL;
1002 /* Runs a task. This function is directly called by __SD_task_try_to_run if the task
1003 * doesn't have to wait in fifos. Otherwise, it is called by __SD_task_just_done when
1004 * the task gets out of its fifos.
1006 void __SD_task_really_run(SD_task_t task)
1010 void **surf_workstations;
1012 xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
1013 "Task '%s' is not runnable or in a fifo! Task state: %d",
1014 SD_task_get_name(task), (int)SD_task_get_state(task));
1015 xbt_assert(task->workstation_list != NULL,
1016 "Task '%s': workstation_list is NULL!",
1017 SD_task_get_name(task));
1021 XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
1023 /* set this task as current task for the workstations in sequential mode */
1024 for (i = 0; i < task->workstation_nb; i++) {
1025 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
1026 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1027 task->workstation_list[i]->current_task = task;
1028 xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
1029 "The workstation should be busy now");
1033 XBT_DEBUG("Task '%s' set as current task for its workstations",
1034 SD_task_get_name(task));
1036 /* start the task */
1038 /* we have to create a Surf workstation array instead of the SimDag
1039 * workstation array */
1040 surf_workstations = xbt_new(void *, task->workstation_nb);
1042 for (i = 0; i < task->workstation_nb; i++)
1043 surf_workstations[i] = task->workstation_list[i]->surf_workstation;
1045 /* It's allowed to pass a NULL vector as cost to mean vector of 0.0 (easing
1046 * user's life). Let's deal with it */
1047 #define cost_or_zero(array,pos) ((array)?(array)[pos]:0.0)
1049 task->surf_action = NULL;
1050 if ((task->workstation_nb == 1)
1051 && (cost_or_zero(task->communication_amount, 0) == 0.0)) {
1053 surf_workstation_model->extension.
1054 workstation.execute(surf_workstations[0],
1055 cost_or_zero(task->computation_amount, 0));
1056 } else if ((task->workstation_nb == 1)
1057 && (cost_or_zero(task->computation_amount, 0) == 0.0)) {
1060 surf_workstation_model->extension.
1061 workstation.communicate(surf_workstations[0], surf_workstations[0],
1062 cost_or_zero(task->communication_amount,
1064 } else if ((task->workstation_nb == 2)
1065 && (cost_or_zero(task->computation_amount, 0) == 0.0)
1066 && (cost_or_zero(task->computation_amount, 1) == 0.0)) {
1070 for (i = 0; i < task->workstation_nb * task->workstation_nb; i++) {
1071 if (cost_or_zero(task->communication_amount, i) > 0.0) {
1073 value = cost_or_zero(task->communication_amount, i);
1078 surf_workstation_model->extension.
1079 workstation.communicate(surf_workstations[0],
1080 surf_workstations[1], value, task->rate);
1085 if (!task->surf_action) {
1086 double *computation_amount = xbt_new(double, task->workstation_nb);
1087 double *communication_amount = xbt_new(double, task->workstation_nb *
1088 task->workstation_nb);
1090 memcpy(computation_amount, task->computation_amount, sizeof(double) *
1091 task->workstation_nb);
1092 memcpy(communication_amount, task->communication_amount,
1093 sizeof(double) * task->workstation_nb * task->workstation_nb);
1096 surf_workstation_model->extension.
1097 workstation.execute_parallel_task(task->workstation_nb,
1100 communication_amount,
1103 xbt_free(surf_workstations);
1106 surf_workstation_model->action_data_set(task->surf_action, task);
1108 XBT_DEBUG("surf_action = %p", task->surf_action);
1112 TRACE_surf_action(task->surf_action, task->category);
1115 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
1116 __SD_task_set_state(task, SD_RUNNING);
1117 xbt_assert(__SD_task_is_running(task), "Bad state of task '%s': %d",
1118 SD_task_get_name(task), (int)SD_task_get_state(task));
1122 /* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_RUNNABLE
1123 * (ie when its dependencies are satisfied).
1124 * If one of the workstations where the task is scheduled on is busy (in sequential mode),
1125 * the task doesn't start.
1126 * Returns whether the task has started.
1128 int __SD_task_try_to_run(SD_task_t task)
1133 SD_workstation_t workstation;
1135 xbt_assert(__SD_task_is_runnable(task),
1136 "Task '%s' is not runnable! Task state: %d",
1137 SD_task_get_name(task), (int)SD_task_get_state(task));
1140 for (i = 0; i < task->workstation_nb; i++) {
1141 can_start = can_start &&
1142 !__SD_workstation_is_busy(task->workstation_list[i]);
1145 XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
1147 if (!can_start) { /* if the task cannot start and is not in the fifos yet */
1148 for (i = 0; i < task->workstation_nb; i++) {
1149 workstation = task->workstation_list[i];
1150 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1151 XBT_DEBUG("Pushing task '%s' in the fifo of workstation '%s'",
1152 SD_task_get_name(task),
1153 SD_workstation_get_name(workstation));
1154 xbt_fifo_push(workstation->task_fifo, task);
1157 __SD_task_set_state(task, SD_IN_FIFO);
1158 xbt_assert(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
1159 SD_task_get_name(task), (int)SD_task_get_state(task));
1160 XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
1162 __SD_task_really_run(task);
1168 /* This function is called by SD_simulate when a task is done.
1169 * It updates task->state and task->action and executes if necessary the tasks
1170 * which were waiting in fifos for the end of `task'
1172 void __SD_task_just_done(SD_task_t task)
1175 SD_workstation_t workstation;
1177 SD_task_t candidate;
1178 int candidate_nb = 0;
1179 int candidate_capacity = 8;
1180 SD_task_t *candidates;
1183 xbt_assert(__SD_task_is_running(task),
1184 "The task must be running! Task state: %d",
1185 (int)SD_task_get_state(task));
1186 xbt_assert(task->workstation_list != NULL,
1187 "Task '%s': workstation_list is NULL!",
1188 SD_task_get_name(task));
1191 candidates = xbt_new(SD_task_t, 8);
1193 __SD_task_set_state(task, SD_DONE);
1194 surf_workstation_model->action_unref(task->surf_action);
1195 task->surf_action = NULL;
1197 XBT_DEBUG("Looking for candidates");
1199 /* if the task was executed on sequential workstations,
1200 maybe we can execute the next task of the fifo for each workstation */
1201 for (i = 0; i < task->workstation_nb; i++) {
1202 workstation = task->workstation_list[i];
1203 XBT_DEBUG("Workstation '%s': access_mode = %d",
1204 SD_workstation_get_name(workstation), (int)workstation->access_mode);
1205 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1206 xbt_assert(workstation->task_fifo != NULL,
1207 "Workstation '%s' has sequential access but no fifo!",
1208 SD_workstation_get_name(workstation));
1209 xbt_assert(workstation->current_task =
1210 task, "Workstation '%s': current task should be '%s'",
1211 SD_workstation_get_name(workstation),
1212 SD_task_get_name(task));
1214 /* the task is over so we can release the workstation */
1215 workstation->current_task = NULL;
1217 XBT_DEBUG("Getting candidate in fifo");
1219 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1220 (workstation->task_fifo));
1222 if (candidate != NULL) {
1223 XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
1224 xbt_assert(__SD_task_is_in_fifo(candidate),
1225 "Bad state of candidate '%s': %d",
1226 SD_task_get_name(candidate),
1227 (int)SD_task_get_state(candidate));
1230 XBT_DEBUG("Candidate in fifo: %p", candidate);
1232 /* if there was a task waiting for my place */
1233 if (candidate != NULL) {
1234 /* Unfortunately, we are not sure yet that we can execute the task now,
1235 because the task can be waiting more deeply in some other workstation's fifos...
1236 So we memorize all candidate tasks, and then we will check for each candidate
1237 whether or not all its workstations are available. */
1239 /* realloc if necessary */
1240 if (candidate_nb == candidate_capacity) {
1241 candidate_capacity *= 2;
1243 xbt_realloc(candidates,
1244 sizeof(SD_task_t) * candidate_capacity);
1247 /* register the candidate */
1248 candidates[candidate_nb++] = candidate;
1249 candidate->fifo_checked = 0;
1254 XBT_DEBUG("Candidates found: %d", candidate_nb);
1256 /* now we check every candidate task */
1257 for (i = 0; i < candidate_nb; i++) {
1258 candidate = candidates[i];
1260 if (candidate->fifo_checked) {
1261 continue; /* we have already evaluated that task */
1264 xbt_assert(__SD_task_is_in_fifo(candidate),
1265 "Bad state of candidate '%s': %d",
1266 SD_task_get_name(candidate), (int)SD_task_get_state(candidate));
1268 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1269 workstation = candidate->workstation_list[j];
1271 /* I can start on this workstation if the workstation is shared
1272 or if I am the first task in the fifo */
1273 can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS
1275 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1276 (workstation->task_fifo));
1279 XBT_DEBUG("Candidate '%s' can start: %d", SD_task_get_name(candidate),
1282 /* now we are sure that I can start! */
1284 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1285 workstation = candidate->workstation_list[j];
1287 /* update the fifo */
1288 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1289 candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */
1290 XBT_DEBUG("Head of the fifo: '%s'",
1292 NULL) ? SD_task_get_name(candidate) : "NULL");
1293 xbt_assert(candidate == candidates[i],
1294 "Error in __SD_task_just_done: bad first task in the fifo");
1296 } /* for each workstation */
1298 /* finally execute the task */
1299 XBT_DEBUG("Task '%s' state: %d", SD_task_get_name(candidate),
1300 (int)SD_task_get_state(candidate));
1301 __SD_task_really_run(candidate);
1304 ("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
1305 SD_task_get_name(candidate), candidate->state_set,
1306 sd_global->running_task_set, __SD_task_is_running(candidate));
1307 xbt_assert(__SD_task_is_running(candidate),
1308 "Bad state of task '%s': %d",
1309 SD_task_get_name(candidate),
1310 (int)SD_task_get_state(candidate));
1311 XBT_DEBUG("Okay, the task is running.");
1314 candidate->fifo_checked = 1;
1315 } /* for each candidate */
1317 xbt_free(candidates);
1321 * Remove all dependencies associated with a task. This function is called
1322 * when the task is destroyed.
1324 static void __SD_task_remove_dependencies(SD_task_t task)
1326 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
1327 because each one is stored twice */
1328 SD_dependency_t dependency;
1329 while (!xbt_dynar_is_empty(task->tasks_before)) {
1330 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
1331 SD_task_dependency_remove(dependency->src, dependency->dst);
1334 while (!xbt_dynar_is_empty(task->tasks_after)) {
1335 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
1336 SD_task_dependency_remove(dependency->src, dependency->dst);
1341 * \brief Returns the start time of a task
1343 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1345 * \param task: a task
1346 * \return the start time of this task
1348 double SD_task_get_start_time(SD_task_t task)
1350 if (task->surf_action)
1351 return surf_workstation_model->
1352 action_get_start_time(task->surf_action);
1354 return task->start_time;
1358 * \brief Returns the finish time of a task
1360 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1361 * If the state is not completed yet, the returned value is an
1362 * estimation of the task finish time. This value can fluctuate
1363 * until the task is completed.
1365 * \param task: a task
1366 * \return the start time of this task
1368 double SD_task_get_finish_time(SD_task_t task)
1370 if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
1371 return surf_workstation_model->
1372 action_get_finish_time(task->surf_action);
1374 return task->finish_time;
1379 void SD_task_distribute_comp_amdhal(SD_task_t task, int ws_count)
1382 xbt_assert(task->kind == SD_TASK_COMP_PAR_AMDAHL,
1383 "Task %s is not a SD_TASK_COMP_PAR_AMDAHL typed task."
1384 "Cannot use this function.",
1385 SD_task_get_name(task));
1387 task->computation_amount = xbt_new0(double, ws_count);
1388 task->communication_amount = xbt_new0(double, ws_count * ws_count);
1389 task->workstation_nb = ws_count;
1390 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
1392 for(i=0;i<ws_count;i++){
1393 task->computation_amount[i] =
1394 (task->alpha + (1 - task->alpha)/ws_count) * task->amount;
1399 /** @brief Auto-schedules a task.
1401 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1402 * allows to specify the task costs at creation, and decorelate them from the
1403 * scheduling process where you just specify which resource should deliver the
1406 * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e() or
1407 * SD_task_create_comp_seq(). Check their definitions for the exact semantic of each
1411 * We should create tasks kind for the following categories:
1412 * - Point to point communication (done)
1413 * - Sequential computation (done)
1414 * - group communication (redistribution, several kinds)
1415 * - parallel tasks with no internal communication (one kind per speedup model such as amdal)
1416 * - idem+ internal communication. Task type not enough since we cannot store comm cost alongside to comp one)
1418 void SD_task_schedulev(SD_task_t task, int count,
1419 const SD_workstation_t * list)
1422 SD_dependency_t dep;
1424 xbt_assert(task->kind != 0,
1425 "Task %s is not typed. Cannot automatically schedule it.",
1426 SD_task_get_name(task));
1427 switch (task->kind) {
1428 case SD_TASK_COMP_PAR_AMDAHL:
1429 SD_task_distribute_comp_amdhal(task, count);
1430 case SD_TASK_COMM_E2E:
1431 case SD_TASK_COMP_SEQ:
1432 xbt_assert(task->workstation_nb == count,"Got %d locations, but were expecting %d locations",count,task->workstation_nb);
1433 for (i = 0; i < count; i++)
1434 task->workstation_list[i] = list[i];
1435 SD_task_do_schedule(task);
1438 xbt_die("Kind of task %s not supported by SD_task_schedulev()",
1439 SD_task_get_name(task));
1441 if (task->kind == SD_TASK_COMM_E2E) {
1442 XBT_VERB("Schedule comm task %s between %s -> %s. It costs %.f bytes",
1443 SD_task_get_name(task),
1444 SD_workstation_get_name(task->workstation_list[0]),
1445 SD_workstation_get_name(task->workstation_list[1]),
1446 task->communication_amount[2]);
1450 /* Iterate over all childs and parent being COMM_E2E to say where I am located (and start them if runnable) */
1451 if (task->kind == SD_TASK_COMP_SEQ) {
1452 XBT_VERB("Schedule computation task %s on %s. It costs %.f flops",
1453 SD_task_get_name(task),
1454 SD_workstation_get_name(task->workstation_list[0]),
1455 task->computation_amount[0]);
1457 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1458 SD_task_t before = dep->src;
1459 if (before->kind == SD_TASK_COMM_E2E) {
1460 before->workstation_list[1] = task->workstation_list[0];
1462 if (before->workstation_list[0] &&
1463 (__SD_task_is_schedulable(before)
1464 || __SD_task_is_not_scheduled(before))) {
1465 SD_task_do_schedule(before);
1467 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1468 SD_task_get_name(before),
1469 SD_workstation_get_name(before->workstation_list[0]),
1470 SD_workstation_get_name(before->workstation_list[1]),
1471 before->communication_amount[2]);
1475 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1476 SD_task_t after = dep->dst;
1477 if (after->kind == SD_TASK_COMM_E2E) {
1478 after->workstation_list[0] = task->workstation_list[0];
1479 if (after->workstation_list[1]
1480 && (__SD_task_is_not_scheduled(after)
1481 || __SD_task_is_schedulable(after))) {
1482 SD_task_do_schedule(after);
1484 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1485 SD_task_get_name(after),
1486 SD_workstation_get_name(after->workstation_list[0]),
1487 SD_workstation_get_name(after->workstation_list[1]),
1488 after->communication_amount[2]);
1494 /* Iterate over all childs and parent being MXN_1D_BLOC to say where I am located (and start them if runnable) */
1495 if (task->kind == SD_TASK_COMP_PAR_AMDAHL) {
1496 XBT_VERB("Schedule computation task %s on %d workstations. %.f flops"
1497 " will be distributed following Amdahl'Law",
1498 SD_task_get_name(task), task->workstation_nb,
1499 task->computation_amount[0]);
1500 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1501 SD_task_t before = dep->src;
1502 if (before->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1503 if (!before->workstation_list){
1504 XBT_VERB("Sender side of Task %s is not scheduled yet. Fill the workstation list with receiver side",
1505 SD_task_get_name(before));
1506 before->workstation_list = xbt_new0(SD_workstation_t, count);
1507 before->workstation_nb = count;
1508 for (i=0;i<count;i++)
1509 before->workstation_list[i] = task->workstation_list[i];
1512 double src_start, src_end, dst_start, dst_end;
1513 src_nb = before->workstation_nb;
1515 before->workstation_list = (SD_workstation_t*) xbt_realloc(
1516 before->workstation_list,
1517 (before->workstation_nb+count)*sizeof(s_SD_workstation_t));
1518 for(i=0; i<count; i++)
1519 before->workstation_list[before->workstation_nb+i] =
1520 task->workstation_list[i];
1522 before->workstation_nb += count;
1524 before->computation_amount = xbt_new0(double,
1525 before->workstation_nb);
1526 before->communication_amount = xbt_new0(double,
1527 before->workstation_nb*
1528 before->workstation_nb);
1530 for(i=0;i<src_nb;i++){
1531 src_start = i*before->amount/src_nb;
1532 src_end = src_start + before->amount/src_nb;
1533 for(j=0; j<dst_nb; j++){
1534 dst_start = j*before->amount/dst_nb;
1535 dst_end = dst_start + before->amount/dst_nb;
1536 XBT_VERB("(%s->%s): (%.2f, %.2f)-> (%.2f, %.2f)",
1537 SD_workstation_get_name(before->workstation_list[i]),
1538 SD_workstation_get_name(before->workstation_list[src_nb+j]),
1539 src_start, src_end, dst_start, dst_end);
1540 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1541 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1543 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1544 MIN(src_end, dst_end) - MAX(src_start, dst_start);
1546 XBT_VERB("==> %.2f",
1547 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1551 if (__SD_task_is_schedulable(before) ||
1552 __SD_task_is_not_scheduled(before)) {
1553 SD_task_do_schedule(before);
1555 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1556 SD_task_get_name(before),before->amount, src_nb, dst_nb);
1561 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1562 SD_task_t after = dep->dst;
1563 if (after->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1564 if (!after->workstation_list){
1565 XBT_VERB("Receiver side of Task %s is not scheduled yet. Fill the workstation list with sender side",
1566 SD_task_get_name(after));
1567 after->workstation_list = xbt_new0(SD_workstation_t, count);
1568 after->workstation_nb = count;
1569 for (i=0;i<count;i++)
1570 after->workstation_list[i] = task->workstation_list[i];
1573 double src_start, src_end, dst_start, dst_end;
1575 dst_nb = after->workstation_nb;
1576 after->workstation_list = (SD_workstation_t*) xbt_realloc(
1577 after->workstation_list,
1578 (after->workstation_nb+count)*sizeof(s_SD_workstation_t));
1579 for(i=after->workstation_nb - 1; i>=0; i--)
1580 after->workstation_list[count+i] = after->workstation_list[i];
1581 for(i=0; i<count; i++)
1582 after->workstation_list[i] = task->workstation_list[i];
1584 after->workstation_nb += count;
1586 after->computation_amount = xbt_new0(double, after->workstation_nb);
1587 after->communication_amount = xbt_new0(double,
1588 after->workstation_nb*
1589 after->workstation_nb);
1591 for(i=0;i<src_nb;i++){
1592 src_start = i*after->amount/src_nb;
1593 src_end = src_start + after->amount/src_nb;
1594 for(j=0; j<dst_nb; j++){
1595 dst_start = j*after->amount/dst_nb;
1596 dst_end = dst_start + after->amount/dst_nb;
1597 XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)",
1598 i, j, src_start, src_end, dst_start, dst_end);
1599 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1600 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1602 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1603 MIN(src_end, dst_end)- MAX(src_start, dst_start);
1605 XBT_VERB("==> %.2f",
1606 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1610 if (__SD_task_is_schedulable(after) ||
1611 __SD_task_is_not_scheduled(after)) {
1612 SD_task_do_schedule(after);
1614 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1615 SD_task_get_name(after),after->amount, src_nb, dst_nb);
1623 /** @brief autoschedule a task on a list of workstations
1625 * This function is very similar to SD_task_schedulev(),
1626 * but takes the list of workstations to schedule onto as separate parameters.
1627 * It builds a proper vector of workstations and then call SD_task_schedulev()
1629 void SD_task_schedulel(SD_task_t task, int count, ...)
1632 SD_workstation_t *list = xbt_new(SD_workstation_t, count);
1634 va_start(ap, count);
1635 for (i = 0; i < count; i++) {
1636 list[i] = va_arg(ap, SD_workstation_t);
1639 SD_task_schedulev(task, count, list);
1644 * \brief Sets the tracing category of a task.
1646 * This function should be called after the creation of a
1647 * SimDAG task, to define the category of that task. The first
1648 * parameter must contain a task that was created with the
1649 * function #SD_task_create. The second parameter must contain
1650 * a category that was previously declared with the function
1653 * \param task The task to be considered
1654 * \param category the name of the category to be associated to the task
1656 * \see SD_task_get_category, TRACE_category, TRACE_category_with_color
1658 void SD_task_set_category (SD_task_t task, const char *category)
1661 if (!TRACE_is_enabled()) return;
1662 if (task == NULL) return;
1663 if (category == NULL){
1664 if (task->category) xbt_free (task->category);
1665 task->category = NULL;
1667 task->category = xbt_strdup (category);
1673 * \brief Gets the current tracing category of a task.
1675 * \param task The task to be considered
1677 * \see SD_task_set_category
1679 * \return Returns the name of the tracing category of the given task, NULL otherwise
1681 const char *SD_task_get_category (SD_task_t task)
1684 return task->category;