1 /* Copyright (c) 2006 - 2013. 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 TRACE_sd_task_create(task);
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;
130 TRACE_category("COMM_E2E");
131 TRACE_sd_set_task_category(res, "COMM_E2E");
137 /** @brief create a sequential computation task that can then be auto-scheduled
139 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
140 * allows to specify the task costs at creation, and decouple them from the
141 * scheduling process where you just specify which resource should deliver the
144 * A sequential computation must be scheduled on 1 host, and the amount
145 * specified at creation to be run on hosts[0].
147 * \param name the name of the task (can be \c NULL)
148 * \param data the user data you want to associate with the task (can be \c NULL)
149 * \param amount amount of compute work to be done by the task
150 * \return the new SD_TASK_COMP_SEQ typed task
152 SD_task_t SD_task_create_comp_seq(const char *name, void *data,
155 SD_task_t res = SD_task_create_sized(name, data, amount, 1);
156 res->computation_amount[0] = amount;
157 res->kind = SD_TASK_COMP_SEQ;
160 TRACE_category("COMP_SEQ");
161 TRACE_sd_set_task_category(res, "COMP_SEQ");
167 /** @brief create a parallel computation task that can then be auto-scheduled
169 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
170 * allows to specify the task costs at creation, and decouple them from the
171 * scheduling process where you just specify which resource should deliver the
174 * A parallel computation can be scheduled on any number of host.
175 * The underlying speedup model is Amdahl's law.
176 * To be auto-scheduled, \see SD_task_distribute_comp_amdhal has to be called
178 * \param name the name of the task (can be \c NULL)
179 * \param data the user data you want to associate with the task (can be \c NULL)
180 * \param amount amount of compute work to be done by the task
181 * \param alpha purely serial fraction of the work to be done (in [0.;1.[)
182 * \return the new task
184 SD_task_t SD_task_create_comp_par_amdahl(const char *name, void *data,
185 double amount, double alpha)
187 xbt_assert(alpha < 1. && alpha >= 0.,
188 "Invalid parameter: alpha must be in [0.;1.[");
190 SD_task_t res = SD_task_create(name, data, amount);
192 res->kind = SD_TASK_COMP_PAR_AMDAHL;
195 TRACE_category("COMP_PAR_AMDAHL");
196 TRACE_sd_set_task_category(res, "COMP_PAR_AMDAHL");
202 /** @brief create a complex data redistribution task that can then be
205 * Auto-scheduling mean that the task can be used with SD_task_schedulev().
206 * This allows to specify the task costs at creation, and decouple them from
207 * the scheduling process where you just specify which resource should
210 * A data redistribution can be scheduled on any number of host.
211 * The assumed distribution is a 1D block distribution. Each host owns the same
212 * share of the \see amount.
213 * To be auto-scheduled, \see SD_task_distribute_comm_mxn_1d_block has to be
215 * \param name the name of the task (can be \c NULL)
216 * \param data the user data you want to associate with the task (can be
218 * \param amount amount of data to redistribute by the task
219 * \return the new task
221 SD_task_t SD_task_create_comm_par_mxn_1d_block(const char *name, void *data,
224 SD_task_t res = SD_task_create(name, data, amount);
225 res->workstation_list=NULL;
226 res->kind = SD_TASK_COMM_PAR_MXN_1D_BLOCK;
229 TRACE_category("COMM_PAR_MXN_1D_BLOCK");
230 TRACE_sd_set_task_category(res, "COMM_PAR_MXN_1D_BLOCK");
237 * \brief Destroys a task.
239 * The user data (if any) should have been destroyed first.
241 * \param task the task you want to destroy
242 * \see SD_task_create()
244 void SD_task_destroy(SD_task_t task)
246 XBT_DEBUG("Destroying task %s...", SD_task_get_name(task));
248 __SD_task_remove_dependencies(task);
249 /* if the task was scheduled or runnable we have to free the scheduling parameters */
250 if (__SD_task_is_scheduled_or_runnable(task))
251 __SD_task_destroy_scheduling_data(task);
252 if (task->state_set != NULL) /* would be null if just created */
253 xbt_swag_remove(task, task->state_set);
255 xbt_swag_remove(task, sd_global->return_set);
257 xbt_free(task->name);
259 if (task->surf_action != NULL)
260 surf_action_unref(task->surf_action);
262 xbt_free(task->workstation_list);
263 xbt_free(task->communication_amount);
264 xbt_free(task->computation_amount);
267 TRACE_sd_task_destroy(task);
270 xbt_mallocator_release(sd_global->task_mallocator,task);
271 sd_global->task_number--;
273 XBT_DEBUG("Task destroyed.");
277 * \brief Returns the user data of a task
280 * \return the user data associated with this task (can be \c NULL)
281 * \see SD_task_set_data()
283 void *SD_task_get_data(SD_task_t task)
289 * \brief Sets the user data of a task
291 * The new data can be \c NULL. The old data should have been freed first
292 * if it was not \c NULL.
295 * \param data the new data you want to associate with this task
296 * \see SD_task_get_data()
298 void SD_task_set_data(SD_task_t task, void *data)
304 * \brief Sets the rate of a task
306 * This will change the network bandwidth a task can use. This rate
307 * depends on both the nominal bandwidth on the route onto which the task is
308 * scheduled (\see SD_task_get_current_bandwidth) and the amount of data to
311 * To divide the nominal bandwidth by 2, the rate then has to be :
312 * rate = bandwidth/(2*amount)
314 * \param task a \see SD_TASK_COMM_E2E task (end-to-end communication)
315 * \param rate the new rate you want to associate with this task.
317 void SD_task_set_rate(SD_task_t task, double rate)
319 xbt_assert(task->kind == SD_TASK_COMM_E2E,
320 "The rate can be modified for end-to-end communications only.");
326 * \brief Returns the state of a task
329 * \return the current \ref e_SD_task_state_t "state" of this task:
330 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING, #SD_DONE or #SD_FAILED
331 * \see e_SD_task_state_t
333 e_SD_task_state_t SD_task_get_state(SD_task_t task)
338 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
340 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
342 xbt_swag_remove(task, task->state_set);
344 case SD_NOT_SCHEDULED:
345 task->state_set = sd_global->not_scheduled_task_set;
348 task->state_set = sd_global->schedulable_task_set;
351 task->state_set = sd_global->scheduled_task_set;
354 task->state_set = sd_global->runnable_task_set;
357 task->state_set = sd_global->in_fifo_task_set;
360 task->state_set = sd_global->running_task_set;
361 task->start_time = surf_action_get_start_time(task->surf_action);
364 task->state_set = sd_global->done_task_set;
365 task->finish_time = surf_action_get_finish_time(task->surf_action);
368 jedule_log_sd_event(task);
372 task->state_set = sd_global->failed_task_set;
375 xbt_die( "Invalid state");
377 xbt_swag_insert(task, task->state_set);
378 task->state = new_state;
380 if (task->watch_points & new_state) {
381 XBT_VERB("Watch point reached with task '%s'!", SD_task_get_name(task));
382 sd_global->watch_point_reached = 1;
383 SD_task_unwatch(task, new_state); /* remove the watch point */
388 * \brief Returns the name of a task
391 * \return the name of this task (can be \c NULL)
393 const char *SD_task_get_name(SD_task_t task)
398 /** @brief Allows to change the name of a task */
399 void SD_task_set_name(SD_task_t task, const char *name)
401 xbt_free(task->name);
402 task->name = xbt_strdup(name);
405 /** @brief Returns the dynar of the parents of a task
408 * \return a newly allocated dynar comprising the parents of this task
411 xbt_dynar_t SD_task_get_parents(SD_task_t task)
417 parents = xbt_dynar_new(sizeof(SD_task_t), NULL);
418 xbt_dynar_foreach(task->tasks_before, i, dep) {
419 xbt_dynar_push(parents, &(dep->src));
424 /** @brief Returns the dynar of the parents of a task
427 * \return a newly allocated dynar comprising the parents of this task
429 xbt_dynar_t SD_task_get_children(SD_task_t task)
432 xbt_dynar_t children;
435 children = xbt_dynar_new(sizeof(SD_task_t), NULL);
436 xbt_dynar_foreach(task->tasks_after, i, dep) {
437 xbt_dynar_push(children, &(dep->dst));
443 * \brief Returns the amount of workstations involved in a task
445 * Only call this on already scheduled tasks!
448 int SD_task_get_workstation_count(SD_task_t task)
450 return task->workstation_nb;
454 * \brief Returns the list of workstations involved in a task
456 * Only call this on already scheduled tasks!
459 SD_workstation_t *SD_task_get_workstation_list(SD_task_t task)
461 return task->workstation_list;
465 * \brief Returns the total amount of work contained in a task
468 * \return the total amount of work (computation or data transfer) for this task
469 * \see SD_task_get_remaining_amount()
471 double SD_task_get_amount(SD_task_t task)
477 * \brief Returns the alpha parameter of a SD_TASK_COMP_PAR_AMDAH task
479 * \param task a parallel task assuming Amdahl's law as speedup model
480 * \return the alpha parameter (serial part of a task in percent) for this task
482 double SD_task_get_alpha(SD_task_t task)
484 xbt_assert(SD_task_get_kind(task) == SD_TASK_COMP_PAR_AMDAHL,
485 "Alpha parameter is not defined for this kink of task");
491 * \brief Returns the remaining amount work to do till the completion of a task
494 * \return the remaining amount of work (computation or data transfer) of this task
495 * \see SD_task_get_amount()
497 double SD_task_get_remaining_amount(SD_task_t task)
499 if (task->surf_action)
500 return surf_action_get_remains(task->surf_action);
502 return task->remains;
505 int SD_task_get_kind(SD_task_t task)
510 /** @brief Displays debugging informations about a task */
511 void SD_task_dump(SD_task_t task)
513 unsigned int counter;
514 SD_dependency_t dependency;
517 XBT_INFO("Displaying task %s", SD_task_get_name(task));
518 statename = bprintf("%s %s %s %s %s %s %s %s",
519 (task->state == SD_NOT_SCHEDULED ? "not scheduled" :
521 (task->state == SD_SCHEDULABLE ? "schedulable" : ""),
522 (task->state == SD_SCHEDULED ? "scheduled" : ""),
523 (task->state == SD_RUNNABLE ? "runnable" :
525 (task->state == SD_IN_FIFO ? "in fifo" : ""),
526 (task->state == SD_RUNNING ? "running" : ""),
527 (task->state == SD_DONE ? "done" : ""),
528 (task->state == SD_FAILED ? "failed" : ""));
529 XBT_INFO(" - state: %s", statename);
532 if (task->kind != 0) {
533 switch (task->kind) {
534 case SD_TASK_COMM_E2E:
535 XBT_INFO(" - kind: end-to-end communication");
537 case SD_TASK_COMP_SEQ:
538 XBT_INFO(" - kind: sequential computation");
540 case SD_TASK_COMP_PAR_AMDAHL:
541 XBT_INFO(" - kind: parallel computation following Amdahl's law");
543 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
544 XBT_INFO(" - kind: MxN data redistribution assuming 1D block distribution");
547 XBT_INFO(" - (unknown kind %d)", task->kind);
553 XBT_INFO(" - tracing category: %s", task->category);
556 XBT_INFO(" - amount: %.0f", SD_task_get_amount(task));
557 if (task->kind == SD_TASK_COMP_PAR_AMDAHL)
558 XBT_INFO(" - alpha: %.2f", task->alpha);
559 XBT_INFO(" - Dependencies to satisfy: %d", task->unsatisfied_dependencies);
560 if (!xbt_dynar_is_empty(task->tasks_before)) {
561 XBT_INFO(" - pre-dependencies:");
562 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
563 XBT_INFO(" %s", SD_task_get_name(dependency->src));
566 if (!xbt_dynar_is_empty(task->tasks_after)) {
567 XBT_INFO(" - post-dependencies:");
568 xbt_dynar_foreach(task->tasks_after, counter, dependency) {
569 XBT_INFO(" %s", SD_task_get_name(dependency->dst));
574 /** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */
575 void SD_task_dotty(SD_task_t task, void *out)
577 unsigned int counter;
578 SD_dependency_t dependency;
579 fprintf(out, " T%p [label=\"%.20s\"", task, task->name);
580 switch (task->kind) {
581 case SD_TASK_COMM_E2E:
582 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
583 fprintf(out, ", shape=box");
585 case SD_TASK_COMP_SEQ:
586 case SD_TASK_COMP_PAR_AMDAHL:
587 fprintf(out, ", shape=circle");
590 xbt_die("Unknown task type!");
592 fprintf(out, "];\n");
593 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
594 fprintf(out, " T%p -> T%p;\n", dependency->src, dependency->dst);
598 /* Destroys a dependency between two tasks.
600 static void __SD_task_dependency_destroy(void *dependency)
602 xbt_free(((SD_dependency_t)dependency)->name);
603 xbt_free(dependency);
607 * \brief Adds a dependency between two tasks
609 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
610 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_RUNNABLE.
612 * \param name the name of the new dependency (can be \c NULL)
613 * \param data the user data you want to associate with this dependency (can be \c NULL)
614 * \param src the task which must be executed first
615 * \param dst the task you want to make depend on \a src
616 * \see SD_task_dependency_remove()
618 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
622 unsigned long length;
625 SD_dependency_t dependency;
627 dynar = src->tasks_after;
628 length = xbt_dynar_length(dynar);
632 "Cannot add a dependency between task '%s' and itself",
633 SD_task_get_name(src));
635 if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_schedulable(src)
636 && !__SD_task_is_scheduled_or_runnable(src) && !__SD_task_is_running(src))
638 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE"
640 SD_task_get_name(src));
642 if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_schedulable(dst)
643 && !__SD_task_is_scheduled_or_runnable(dst))
645 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE",
646 SD_task_get_name(dst));
648 XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s",
649 SD_task_get_name(src), SD_task_get_name(dst));
650 for (i = 0; i < length && !found; i++) {
651 xbt_dynar_get_cpy(dynar, i, &dependency);
652 found = (dependency->dst == dst);
653 XBT_DEBUG("Dependency %lu: dependency->dst = %s", i,
654 SD_task_get_name(dependency->dst));
659 "A dependency already exists between task '%s' and task '%s'",
660 SD_task_get_name(src), SD_task_get_name(dst));
662 dependency = xbt_new(s_SD_dependency_t, 1);
664 dependency->name = xbt_strdup(name); /* xbt_strdup is cleaver enough to deal with NULL args itself */
665 dependency->data = data;
666 dependency->src = src;
667 dependency->dst = dst;
669 /* src must be executed before dst */
670 xbt_dynar_push(src->tasks_after, &dependency);
671 xbt_dynar_push(dst->tasks_before, &dependency);
673 dst->unsatisfied_dependencies++;
676 /* if the task was runnable, then dst->tasks_before is not empty anymore,
677 so we must go back to state SD_SCHEDULED */
678 if (__SD_task_is_runnable(dst)) {
680 ("SD_task_dependency_add: %s was runnable and becomes scheduled!",
681 SD_task_get_name(dst));
682 __SD_task_set_state(dst, SD_SCHEDULED);
686 * \brief Returns the name given as input when dependency has been created..
689 * \param dst a task depending on \a src
692 const char *SD_task_dependency_get_name(SD_task_t src, SD_task_t dst){
694 SD_dependency_t dependency;
696 xbt_dynar_foreach(src->tasks_after, i, dependency){
697 if (dependency->dst == dst)
698 return dependency->name;
704 * \brief Indicates whether there is a dependency between two tasks.
707 * \param dst a task depending on \a src
709 * If src is NULL, checks whether dst has any pre-dependency.
710 * If dst is NULL, checks whether src has any post-dependency.
712 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
714 unsigned int counter;
715 SD_dependency_t dependency;
717 xbt_assert(src != NULL
719 "Invalid parameter: both src and dst are NULL");
723 xbt_dynar_foreach(src->tasks_after, counter, dependency) {
724 if (dependency->dst == dst)
728 return xbt_dynar_length(src->tasks_after);
731 return xbt_dynar_length(dst->tasks_before);
737 * \brief Remove a dependency between two tasks
740 * \param dst a task depending on \a src
741 * \see SD_task_dependency_add()
743 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
747 unsigned long length;
750 SD_dependency_t dependency;
752 /* remove the dependency from src->tasks_after */
753 dynar = src->tasks_after;
754 length = xbt_dynar_length(dynar);
756 for (i = 0; i < length && !found; i++) {
757 xbt_dynar_get_cpy(dynar, i, &dependency);
758 if (dependency->dst == dst) {
759 xbt_dynar_remove_at(dynar, i, NULL);
765 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
766 SD_task_get_name(src), SD_task_get_name(dst),
767 SD_task_get_name(dst), SD_task_get_name(src));
769 /* remove the dependency from dst->tasks_before */
770 dynar = dst->tasks_before;
771 length = xbt_dynar_length(dynar);
774 for (i = 0; i < length && !found; i++) {
775 xbt_dynar_get_cpy(dynar, i, &dependency);
776 if (dependency->src == src) {
777 xbt_dynar_remove_at(dynar, i, NULL);
778 __SD_task_dependency_destroy(dependency);
779 dst->unsatisfied_dependencies--;
784 /* should never happen... */
786 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
787 SD_task_get_name(dst), SD_task_get_name(src),
788 SD_task_get_name(src), SD_task_get_name(dst));
790 /* if the task was scheduled and dst->tasks_before is empty now, we can make it runnable */
792 if (dst->unsatisfied_dependencies == 0) {
793 if (__SD_task_is_scheduled(dst))
794 __SD_task_set_state(dst, SD_RUNNABLE);
796 __SD_task_set_state(dst, SD_SCHEDULABLE);
799 if (dst->is_not_ready == 0)
800 __SD_task_set_state(dst, SD_SCHEDULABLE);
802 /* __SD_print_dependencies(src);
803 __SD_print_dependencies(dst); */
807 * \brief Returns the user data associated with a dependency between two tasks
810 * \param dst a task depending on \a src
811 * \return the user data associated with this dependency (can be \c NULL)
812 * \see SD_task_dependency_add()
814 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
818 unsigned long length;
821 SD_dependency_t dependency;
823 dynar = src->tasks_after;
824 length = xbt_dynar_length(dynar);
826 for (i = 0; i < length && !found; i++) {
827 xbt_dynar_get_cpy(dynar, i, &dependency);
828 found = (dependency->dst == dst);
831 THROWF(arg_error, 0, "No dependency found between task '%s' and '%s'",
832 SD_task_get_name(src), SD_task_get_name(dst));
833 return dependency->data;
836 /* temporary function for debugging */
837 static void __SD_print_watch_points(SD_task_t task)
839 static const int state_masks[] =
840 { SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNING, SD_RUNNABLE, SD_DONE,
843 static const char *state_names[] =
844 { "schedulable", "scheduled", "running", "runnable", "done",
849 XBT_INFO("Task '%s' watch points (%x): ", SD_task_get_name(task),
853 for (i = 0; i < 5; i++) {
854 if (task->watch_points & state_masks[i])
855 XBT_INFO("%s ", state_names[i]);
860 * \brief Adds a watch point to a task
862 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
863 * task becomes the one given in argument. The
864 * watch point is then automatically removed.
867 * \param state the \ref e_SD_task_state_t "state" you want to watch
868 * (cannot be #SD_NOT_SCHEDULED)
869 * \see SD_task_unwatch()
871 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
873 if (state & SD_NOT_SCHEDULED)
875 "Cannot add a watch point for state SD_NOT_SCHEDULED");
877 task->watch_points = task->watch_points | state;
878 /* __SD_print_watch_points(task); */
882 * \brief Removes a watch point from a task
885 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
886 * \see SD_task_watch()
888 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
890 xbt_assert(state != SD_NOT_SCHEDULED,
891 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
893 task->watch_points = task->watch_points & ~state;
894 /* __SD_print_watch_points(task); */
898 * \brief Returns an approximative estimation of the execution time of a task.
900 * The estimation is very approximative because the value returned is the time
901 * the task would take if it was executed now and if it was the only task.
903 * \param task the task to evaluate
904 * \param workstation_nb number of workstations on which the task would be executed
905 * \param workstation_list the workstations on which the task would be executed
906 * \param computation_amount computation amount for each workstation
907 * \param communication_amount communication amount between each pair of workstations
910 double SD_task_get_execution_time(SD_task_t task,
912 const SD_workstation_t *
914 const double *computation_amount,
915 const double *communication_amount)
917 double time, max_time = 0.0;
919 xbt_assert(workstation_nb > 0, "Invalid parameter");
921 /* the task execution time is the maximum execution time of the parallel tasks */
923 for (i = 0; i < workstation_nb; i++) {
925 if (computation_amount != NULL)
927 SD_workstation_get_computation_time(workstation_list[i],
928 computation_amount[i]);
930 if (communication_amount != NULL)
931 for (j = 0; j < workstation_nb; j++) {
933 SD_route_get_communication_time(workstation_list[i],
935 communication_amount[i *
940 if (time > max_time) {
947 static XBT_INLINE void SD_task_do_schedule(SD_task_t task)
949 if (!__SD_task_is_not_scheduled(task) && !__SD_task_is_schedulable(task))
950 THROWF(arg_error, 0, "Task '%s' has already been scheduled",
951 SD_task_get_name(task));
953 /* update the task state */
954 if (task->unsatisfied_dependencies == 0)
955 __SD_task_set_state(task, SD_RUNNABLE);
957 __SD_task_set_state(task, SD_SCHEDULED);
961 * \brief Schedules a task
963 * The task state must be #SD_NOT_SCHEDULED.
964 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
965 * i.e. when its dependencies are satisfied.
967 * \param task the task you want to schedule
968 * \param workstation_count number of workstations on which the task will be executed
969 * \param workstation_list the workstations on which the task will be executed
970 * \param computation_amount computation amount for each workstation
971 * \param communication_amount communication amount between each pair of workstations
972 * \param rate task execution speed rate
973 * \see SD_task_unschedule()
975 void SD_task_schedule(SD_task_t task, int workstation_count,
976 const SD_workstation_t * workstation_list,
977 const double *computation_amount,
978 const double *communication_amount, double rate)
980 int communication_nb;
981 task->workstation_nb = 0;
983 xbt_assert(workstation_count > 0, "workstation_nb must be positive");
985 task->workstation_nb = workstation_count;
988 if (computation_amount) {
989 task->computation_amount = xbt_realloc(task->computation_amount,
990 sizeof(double) * workstation_count);
991 memcpy(task->computation_amount, computation_amount,
992 sizeof(double) * workstation_count);
994 xbt_free(task->computation_amount);
995 task->computation_amount = NULL;
998 communication_nb = workstation_count * workstation_count;
999 if (communication_amount) {
1000 task->communication_amount = xbt_realloc(task->communication_amount,
1001 sizeof(double) * communication_nb);
1002 memcpy(task->communication_amount, communication_amount,
1003 sizeof(double) * communication_nb);
1005 xbt_free(task->communication_amount);
1006 task->communication_amount = NULL;
1009 task->workstation_list =
1010 xbt_realloc(task->workstation_list,
1011 sizeof(SD_workstation_t) * workstation_count);
1012 memcpy(task->workstation_list, workstation_list,
1013 sizeof(SD_workstation_t) * workstation_count);
1015 SD_task_do_schedule(task);
1019 * \brief Unschedules a task
1021 * The task state must be #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING or #SD_FAILED.
1022 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
1023 * Call SD_task_schedule() to schedule it again.
1025 * \param task the task you want to unschedule
1026 * \see SD_task_schedule()
1028 void SD_task_unschedule(SD_task_t task)
1030 if (task->state_set != sd_global->scheduled_task_set &&
1031 task->state_set != sd_global->runnable_task_set &&
1032 task->state_set != sd_global->running_task_set &&
1033 task->state_set != sd_global->failed_task_set)
1034 THROWF(arg_error, 0,
1035 "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED",
1036 SD_task_get_name(task));
1038 if (__SD_task_is_scheduled_or_runnable(task) /* if the task is scheduled or runnable */
1039 && ((task->kind == SD_TASK_COMP_PAR_AMDAHL) ||
1040 (task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK))) { /* Don't free scheduling data for typed tasks */
1041 __SD_task_destroy_scheduling_data(task);
1042 xbt_free(task->workstation_list);
1043 task->workstation_list=NULL;
1044 task->workstation_nb = 0;
1047 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
1048 surf_action_cancel(task->surf_action);
1050 if (task->unsatisfied_dependencies == 0)
1051 __SD_task_set_state(task, SD_SCHEDULABLE);
1053 __SD_task_set_state(task, SD_NOT_SCHEDULED);
1055 task->remains = task->amount;
1056 task->start_time = -1.0;
1059 /* Destroys the data memorized by SD_task_schedule.
1060 * Task state must be SD_SCHEDULED or SD_RUNNABLE.
1062 static void __SD_task_destroy_scheduling_data(SD_task_t task)
1064 if (!__SD_task_is_scheduled_or_runnable(task)
1065 && !__SD_task_is_in_fifo(task))
1066 THROWF(arg_error, 0,
1067 "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
1068 SD_task_get_name(task));
1070 xbt_free(task->computation_amount);
1071 xbt_free(task->communication_amount);
1072 task->computation_amount = task->communication_amount = NULL;
1075 /* Runs a task. This function is directly called by __SD_task_try_to_run if
1076 * the task doesn't have to wait in FIFOs. Otherwise, it is called by
1077 * __SD_task_just_done when the task gets out of its FIFOs.
1079 void __SD_task_really_run(SD_task_t task)
1083 void **surf_workstations;
1085 xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
1086 "Task '%s' is not runnable or in a fifo! Task state: %d",
1087 SD_task_get_name(task), (int)SD_task_get_state(task));
1088 xbt_assert(task->workstation_list != NULL,
1089 "Task '%s': workstation_list is NULL!",
1090 SD_task_get_name(task));
1092 XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
1093 int workstation_nb = task->workstation_nb;
1095 /* set this task as current task for the workstations in sequential mode */
1096 for (i = 0; i < workstation_nb; i++) {
1097 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
1098 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1099 SD_workstation_priv(task->workstation_list[i])->current_task = task;
1100 xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
1101 "The workstation should be busy now");
1105 XBT_DEBUG("Task '%s' set as current task for its workstations",
1106 SD_task_get_name(task));
1108 /* start the task */
1110 /* we have to create a Surf workstation array instead of the SimDag
1111 * workstation array */
1112 surf_workstations = xbt_new(void *, workstation_nb);
1114 for (i = 0; i < workstation_nb; i++)
1115 surf_workstations[i] = task->workstation_list[i];
1117 double *computation_amount = xbt_new0(double, workstation_nb);
1118 double *communication_amount = xbt_new0(double, workstation_nb * workstation_nb);
1121 if(task->computation_amount)
1122 memcpy(computation_amount, task->computation_amount, sizeof(double) *
1124 if(task->communication_amount)
1125 memcpy(communication_amount, task->communication_amount,
1126 sizeof(double) * workstation_nb * workstation_nb);
1128 task->surf_action = surf_workstation_model_execute_parallel_task((surf_workstation_model_t)surf_workstation_model,
1132 communication_amount,
1135 surf_action_set_data(task->surf_action, task);
1137 XBT_DEBUG("surf_action = %p", task->surf_action);
1141 TRACE_surf_action(task->surf_action, task->category);
1144 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
1145 __SD_task_set_state(task, SD_RUNNING);
1146 xbt_assert(__SD_task_is_running(task), "Bad state of task '%s': %d",
1147 SD_task_get_name(task), (int)SD_task_get_state(task));
1151 /* Tries to run a task. This function is called by SD_simulate() when a
1152 * scheduled task becomes SD_RUNNABLE (i.e., when its dependencies are
1154 * If one of the workstations where the task is scheduled on is busy (in
1155 * sequential mode), the task doesn't start.
1156 * Returns whether the task has started.
1158 int __SD_task_try_to_run(SD_task_t task)
1163 SD_workstation_t workstation;
1165 xbt_assert(__SD_task_is_runnable(task),
1166 "Task '%s' is not runnable! Task state: %d",
1167 SD_task_get_name(task), (int)SD_task_get_state(task));
1170 for (i = 0; i < task->workstation_nb; i++) {
1171 can_start = can_start &&
1172 !__SD_workstation_is_busy(task->workstation_list[i]);
1175 XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
1177 if (!can_start) { /* if the task cannot start and is not in the FIFOs yet */
1178 for (i = 0; i < task->workstation_nb; i++) {
1179 workstation = task->workstation_list[i];
1180 if (SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1181 XBT_DEBUG("Pushing task '%s' in the FIFO of workstation '%s'",
1182 SD_task_get_name(task),
1183 SD_workstation_get_name(workstation));
1184 xbt_fifo_push(SD_workstation_priv(workstation)->task_fifo, task);
1187 __SD_task_set_state(task, SD_IN_FIFO);
1188 xbt_assert(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
1189 SD_task_get_name(task), (int)SD_task_get_state(task));
1190 XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
1192 __SD_task_really_run(task);
1198 /* This function is called by SD_simulate when a task is done.
1199 * It updates task->state and task->action and executes if necessary the tasks
1200 * which were waiting in FIFOs for the end of `task'
1202 void __SD_task_just_done(SD_task_t task)
1205 SD_workstation_t workstation;
1207 SD_task_t candidate;
1208 int candidate_nb = 0;
1209 int candidate_capacity = 8;
1210 SD_task_t *candidates;
1213 xbt_assert(__SD_task_is_running(task),
1214 "The task must be running! Task state: %d",
1215 (int)SD_task_get_state(task));
1216 xbt_assert(task->workstation_list != NULL,
1217 "Task '%s': workstation_list is NULL!",
1218 SD_task_get_name(task));
1221 candidates = xbt_new(SD_task_t, 8);
1223 __SD_task_set_state(task, SD_DONE);
1224 surf_action_unref(task->surf_action);
1225 task->surf_action = NULL;
1227 XBT_DEBUG("Looking for candidates");
1229 /* if the task was executed on sequential workstations,
1230 maybe we can execute the next task of the FIFO for each workstation */
1231 for (i = 0; i < task->workstation_nb; i++) {
1232 workstation = task->workstation_list[i];
1233 XBT_DEBUG("Workstation '%s': access_mode = %d",
1234 SD_workstation_get_name(workstation), (int)SD_workstation_priv(workstation)->access_mode);
1235 if (SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1236 xbt_assert(SD_workstation_priv(workstation)->task_fifo != NULL,
1237 "Workstation '%s' has sequential access but no FIFO!",
1238 SD_workstation_get_name(workstation));
1239 xbt_assert(SD_workstation_priv(workstation)->current_task =
1240 task, "Workstation '%s': current task should be '%s'",
1241 SD_workstation_get_name(workstation),
1242 SD_task_get_name(task));
1244 /* the task is over so we can release the workstation */
1245 SD_workstation_priv(workstation)->current_task = NULL;
1247 XBT_DEBUG("Getting candidate in FIFO");
1249 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1250 (SD_workstation_priv(workstation)->task_fifo));
1252 if (candidate != NULL) {
1253 XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
1254 xbt_assert(__SD_task_is_in_fifo(candidate),
1255 "Bad state of candidate '%s': %d",
1256 SD_task_get_name(candidate),
1257 (int)SD_task_get_state(candidate));
1260 XBT_DEBUG("Candidate in fifo: %p", candidate);
1262 /* if there was a task waiting for my place */
1263 if (candidate != NULL) {
1264 /* Unfortunately, we are not sure yet that we can execute the task now,
1265 because the task can be waiting more deeply in some other
1266 workstation's FIFOs ...
1267 So we memorize all candidate tasks, and then we will check for each
1268 candidate whether or not all its workstations are available. */
1270 /* realloc if necessary */
1271 if (candidate_nb == candidate_capacity) {
1272 candidate_capacity *= 2;
1274 xbt_realloc(candidates,
1275 sizeof(SD_task_t) * candidate_capacity);
1278 /* register the candidate */
1279 candidates[candidate_nb++] = candidate;
1280 candidate->fifo_checked = 0;
1285 XBT_DEBUG("Candidates found: %d", candidate_nb);
1287 /* now we check every candidate task */
1288 for (i = 0; i < candidate_nb; i++) {
1289 candidate = candidates[i];
1291 if (candidate->fifo_checked) {
1292 continue; /* we have already evaluated that task */
1295 xbt_assert(__SD_task_is_in_fifo(candidate),
1296 "Bad state of candidate '%s': %d",
1297 SD_task_get_name(candidate), (int)SD_task_get_state(candidate));
1299 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1300 workstation = candidate->workstation_list[j];
1302 /* I can start on this workstation if the workstation is shared
1303 or if I am the first task in the FIFO */
1304 can_start = SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SHARED_ACCESS
1306 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1307 (SD_workstation_priv(workstation)->task_fifo));
1310 XBT_DEBUG("Candidate '%s' can start: %d", SD_task_get_name(candidate),
1313 /* now we are sure that I can start! */
1315 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1316 workstation = candidate->workstation_list[j];
1318 /* update the FIFO */
1319 if (SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1320 candidate = xbt_fifo_shift(SD_workstation_priv(workstation)->task_fifo); /* the return value is stored just for debugging */
1321 XBT_DEBUG("Head of the FIFO: '%s'",
1323 NULL) ? SD_task_get_name(candidate) : "NULL");
1324 xbt_assert(candidate == candidates[i],
1325 "Error in __SD_task_just_done: bad first task in the FIFO");
1327 } /* for each workstation */
1329 /* finally execute the task */
1330 XBT_DEBUG("Task '%s' state: %d", SD_task_get_name(candidate),
1331 (int)SD_task_get_state(candidate));
1332 __SD_task_really_run(candidate);
1335 ("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
1336 SD_task_get_name(candidate), candidate->state_set,
1337 sd_global->running_task_set, __SD_task_is_running(candidate));
1338 xbt_assert(__SD_task_is_running(candidate),
1339 "Bad state of task '%s': %d",
1340 SD_task_get_name(candidate),
1341 (int)SD_task_get_state(candidate));
1342 XBT_DEBUG("Okay, the task is running.");
1345 candidate->fifo_checked = 1;
1346 } /* for each candidate */
1348 xbt_free(candidates);
1352 * Remove all dependencies associated with a task. This function is called
1353 * when the task is destroyed.
1355 static void __SD_task_remove_dependencies(SD_task_t task)
1357 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
1358 because each one is stored twice */
1359 SD_dependency_t dependency;
1360 while (!xbt_dynar_is_empty(task->tasks_before)) {
1361 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
1362 SD_task_dependency_remove(dependency->src, dependency->dst);
1365 while (!xbt_dynar_is_empty(task->tasks_after)) {
1366 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
1367 SD_task_dependency_remove(dependency->src, dependency->dst);
1372 * \brief Returns the start time of a task
1374 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1376 * \param task: a task
1377 * \return the start time of this task
1379 double SD_task_get_start_time(SD_task_t task)
1381 if (task->surf_action)
1382 return surf_action_get_start_time(task->surf_action);
1384 return task->start_time;
1388 * \brief Returns the finish time of a task
1390 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1391 * If the state is not completed yet, the returned value is an
1392 * estimation of the task finish time. This value can fluctuate
1393 * until the task is completed.
1395 * \param task: a task
1396 * \return the start time of this task
1398 double SD_task_get_finish_time(SD_task_t task)
1400 if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
1401 return surf_action_get_finish_time(task->surf_action);
1403 return task->finish_time;
1408 void SD_task_distribute_comp_amdhal(SD_task_t task, int ws_count)
1411 xbt_assert(task->kind == SD_TASK_COMP_PAR_AMDAHL,
1412 "Task %s is not a SD_TASK_COMP_PAR_AMDAHL typed task."
1413 "Cannot use this function.",
1414 SD_task_get_name(task));
1415 task->computation_amount = xbt_new0(double, ws_count);
1416 task->communication_amount = xbt_new0(double, ws_count * ws_count);
1417 xbt_free(task->workstation_list);
1418 task->workstation_nb = ws_count;
1419 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
1421 for(i=0;i<ws_count;i++){
1422 task->computation_amount[i] =
1423 (task->alpha + (1 - task->alpha)/ws_count) * task->amount;
1428 /** @brief Auto-schedules a task.
1430 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1431 * allows to specify the task costs at creation, and decouple them from the
1432 * scheduling process where you just specify which resource should deliver the
1435 * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e()
1436 * or SD_task_create_comp_seq(). Check their definitions for the exact semantic
1440 * We should create tasks kind for the following categories:
1441 * - Point to point communication (done)
1442 * - Sequential computation (done)
1443 * - group communication (redistribution, several kinds)
1444 * - parallel tasks with no internal communication (one kind per speedup
1445 * model such as Amdahl)
1446 * - idem+ internal communication. Task type not enough since we cannot store
1447 * comm cost alongside to comp one)
1449 void SD_task_schedulev(SD_task_t task, int count,
1450 const SD_workstation_t * list)
1453 SD_dependency_t dep;
1455 xbt_assert(task->kind != 0,
1456 "Task %s is not typed. Cannot automatically schedule it.",
1457 SD_task_get_name(task));
1458 switch (task->kind) {
1459 case SD_TASK_COMP_PAR_AMDAHL:
1460 SD_task_distribute_comp_amdhal(task, count);
1461 case SD_TASK_COMM_E2E:
1462 case SD_TASK_COMP_SEQ:
1463 xbt_assert(task->workstation_nb == count,
1464 "Got %d locations, but were expecting %d locations",
1465 count,task->workstation_nb);
1466 for (i = 0; i < count; i++)
1467 task->workstation_list[i] = list[i];
1468 if (SD_task_get_kind(task)== SD_TASK_COMP_SEQ && !task->computation_amount){
1469 /*This task has failed and is rescheduled. Reset the computation amount*/
1470 task->computation_amount = xbt_new0(double, 1);
1471 task->computation_amount[0] = task->remains;
1473 SD_task_do_schedule(task);
1476 xbt_die("Kind of task %s not supported by SD_task_schedulev()",
1477 SD_task_get_name(task));
1479 if (task->kind == SD_TASK_COMM_E2E) {
1480 XBT_VERB("Schedule comm task %s between %s -> %s. It costs %.f bytes",
1481 SD_task_get_name(task),
1482 SD_workstation_get_name(task->workstation_list[0]),
1483 SD_workstation_get_name(task->workstation_list[1]),
1484 task->communication_amount[2]);
1488 /* Iterate over all children and parents being COMM_E2E to say where I am
1489 * located (and start them if runnable) */
1490 if (task->kind == SD_TASK_COMP_SEQ) {
1491 XBT_VERB("Schedule computation task %s on %s. It costs %.f flops",
1492 SD_task_get_name(task),
1493 SD_workstation_get_name(task->workstation_list[0]),
1494 task->computation_amount[0]);
1496 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1497 SD_task_t before = dep->src;
1498 if (before->kind == SD_TASK_COMM_E2E) {
1499 before->workstation_list[1] = task->workstation_list[0];
1501 if (before->workstation_list[0] &&
1502 (__SD_task_is_schedulable(before)
1503 || __SD_task_is_not_scheduled(before))) {
1504 SD_task_do_schedule(before);
1506 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1507 SD_task_get_name(before),
1508 SD_workstation_get_name(before->workstation_list[0]),
1509 SD_workstation_get_name(before->workstation_list[1]),
1510 before->communication_amount[2]);
1514 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1515 SD_task_t after = dep->dst;
1516 if (after->kind == SD_TASK_COMM_E2E) {
1517 after->workstation_list[0] = task->workstation_list[0];
1518 if (after->workstation_list[1]
1519 && (__SD_task_is_not_scheduled(after)
1520 || __SD_task_is_schedulable(after))) {
1521 SD_task_do_schedule(after);
1523 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1524 SD_task_get_name(after),
1525 SD_workstation_get_name(after->workstation_list[0]),
1526 SD_workstation_get_name(after->workstation_list[1]),
1527 after->communication_amount[2]);
1533 /* Iterate over all children and parents being MXN_1D_BLOCK to say where I am
1534 * located (and start them if runnable) */
1535 if (task->kind == SD_TASK_COMP_PAR_AMDAHL) {
1536 XBT_VERB("Schedule computation task %s on %d workstations. %.f flops"
1537 " will be distributed following Amdahl'Law",
1538 SD_task_get_name(task), task->workstation_nb,
1539 task->computation_amount[0]);
1540 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1541 SD_task_t before = dep->src;
1542 if (before->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1543 if (!before->workstation_list){
1544 XBT_VERB("Sender side of Task %s is not scheduled yet",
1545 SD_task_get_name(before));
1546 before->workstation_list = xbt_new0(SD_workstation_t, count);
1547 before->workstation_nb = count;
1548 XBT_VERB("Fill the workstation list with list of Task '%s'",
1549 SD_task_get_name(task));
1550 for (i=0;i<count;i++)
1551 before->workstation_list[i] = task->workstation_list[i];
1553 XBT_VERB("Build communication matrix for task '%s'",
1554 SD_task_get_name(before));
1556 double src_start, src_end, dst_start, dst_end;
1557 src_nb = before->workstation_nb;
1559 before->workstation_list = (SD_workstation_t*) xbt_realloc(
1560 before->workstation_list,
1561 (before->workstation_nb+count)*sizeof(s_SD_workstation_t));
1562 for(i=0; i<count; i++)
1563 before->workstation_list[before->workstation_nb+i] =
1564 task->workstation_list[i];
1566 before->workstation_nb += count;
1567 xbt_free(before->computation_amount);
1568 xbt_free(before->communication_amount);
1569 before->computation_amount = xbt_new0(double,
1570 before->workstation_nb);
1571 before->communication_amount = xbt_new0(double,
1572 before->workstation_nb*
1573 before->workstation_nb);
1575 for(i=0;i<src_nb;i++){
1576 src_start = i*before->amount/src_nb;
1577 src_end = src_start + before->amount/src_nb;
1578 for(j=0; j<dst_nb; j++){
1579 dst_start = j*before->amount/dst_nb;
1580 dst_end = dst_start + before->amount/dst_nb;
1581 XBT_VERB("(%s->%s): (%.2f, %.2f)-> (%.2f, %.2f)",
1582 SD_workstation_get_name(before->workstation_list[i]),
1583 SD_workstation_get_name(before->workstation_list[src_nb+j]),
1584 src_start, src_end, dst_start, dst_end);
1585 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1586 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1588 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1589 MIN(src_end, dst_end) - MAX(src_start, dst_start);
1591 XBT_VERB("==> %.2f",
1592 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1596 if (__SD_task_is_schedulable(before) ||
1597 __SD_task_is_not_scheduled(before)) {
1598 SD_task_do_schedule(before);
1600 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1601 SD_task_get_name(before),before->amount, src_nb, dst_nb);
1606 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1607 SD_task_t after = dep->dst;
1608 if (after->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1609 if (!after->workstation_list){
1610 XBT_VERB("Receiver side of Task '%s' is not scheduled yet",
1611 SD_task_get_name(after));
1612 after->workstation_list = xbt_new0(SD_workstation_t, count);
1613 after->workstation_nb = count;
1614 XBT_VERB("Fill the workstation list with list of Task '%s'",
1615 SD_task_get_name(task));
1616 for (i=0;i<count;i++)
1617 after->workstation_list[i] = task->workstation_list[i];
1620 double src_start, src_end, dst_start, dst_end;
1622 dst_nb = after->workstation_nb;
1623 after->workstation_list = (SD_workstation_t*) xbt_realloc(
1624 after->workstation_list,
1625 (after->workstation_nb+count)*sizeof(s_SD_workstation_t));
1626 for(i=after->workstation_nb - 1; i>=0; i--)
1627 after->workstation_list[count+i] = after->workstation_list[i];
1628 for(i=0; i<count; i++)
1629 after->workstation_list[i] = task->workstation_list[i];
1631 after->workstation_nb += count;
1633 xbt_free(after->computation_amount);
1634 xbt_free(after->communication_amount);
1636 after->computation_amount = xbt_new0(double, after->workstation_nb);
1637 after->communication_amount = xbt_new0(double,
1638 after->workstation_nb*
1639 after->workstation_nb);
1641 for(i=0;i<src_nb;i++){
1642 src_start = i*after->amount/src_nb;
1643 src_end = src_start + after->amount/src_nb;
1644 for(j=0; j<dst_nb; j++){
1645 dst_start = j*after->amount/dst_nb;
1646 dst_end = dst_start + after->amount/dst_nb;
1647 XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)",
1648 i, j, src_start, src_end, dst_start, dst_end);
1649 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1650 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1652 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1653 MIN(src_end, dst_end)- MAX(src_start, dst_start);
1655 XBT_VERB("==> %.2f",
1656 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1660 if (__SD_task_is_schedulable(after) ||
1661 __SD_task_is_not_scheduled(after)) {
1662 SD_task_do_schedule(after);
1664 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1665 SD_task_get_name(after),after->amount, src_nb, dst_nb);
1673 /** @brief autoschedule a task on a list of workstations
1675 * This function is very similar to SD_task_schedulev(),
1676 * but takes the list of workstations to schedule onto as separate parameters.
1677 * It builds a proper vector of workstations and then call SD_task_schedulev()
1679 void SD_task_schedulel(SD_task_t task, int count, ...)
1682 SD_workstation_t *list = xbt_new(SD_workstation_t, count);
1684 va_start(ap, count);
1685 for (i = 0; i < count; i++) {
1686 list[i] = va_arg(ap, SD_workstation_t);
1689 SD_task_schedulev(task, count, list);