1 /* Copyright (c) 2006-2016. 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. */
7 #include "src/surf/surf_interface.hpp"
8 #include "src/surf/host_interface.hpp"
9 #include "src/simdag/simdag_private.h"
10 #include "simgrid/simdag.h"
11 #include "xbt/sysdep.h"
12 #include "xbt/dynar.h"
13 #include "src/instr/instr_private.h"
15 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_task, sd,
16 "Logging specific to SimDag (task)");
18 static void __SD_task_remove_dependencies(SD_task_t task);
19 static void __SD_task_destroy_scheduling_data(SD_task_t task);
21 void* SD_task_new_f(void)
23 SD_task_t task = xbt_new0(s_SD_task_t, 1);
24 task->tasks_before = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
25 task->tasks_after = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
30 void SD_task_recycle_f(void *t)
32 SD_task_t task = (SD_task_t) t;
34 /* Reset the content */
35 task->kind = SD_TASK_NOT_TYPED;
36 task->state_hookup.prev = NULL;
37 task->state_hookup.next = NULL;
38 task->state_set = sd_global->not_scheduled_task_set;
39 xbt_swag_insert(task, task->state_set);
40 task->state = SD_NOT_SCHEDULED;
41 task->return_hookup.prev = NULL;
42 task->return_hookup.next = NULL;
46 task->start_time = -1.0;
47 task->finish_time = -1.0;
48 task->surf_action = NULL;
49 task->watch_points = 0;
52 xbt_dynar_reset(task->tasks_before);
53 xbt_dynar_reset(task->tasks_after);
54 task->unsatisfied_dependencies = 0;
55 task->is_not_ready = 0;
57 /* scheduling parameters */
58 task->workstation_nb = 0;
59 task->workstation_list = NULL;
60 task->flops_amount = NULL;
61 task->bytes_amount = NULL;
65 void SD_task_free_f(void *t)
67 SD_task_t task = (SD_task_t)t;
69 xbt_dynar_free(&task->tasks_before);
70 xbt_dynar_free(&task->tasks_after);
75 * \brief Creates a new task.
77 * \param name the name of the task (can be \c NULL)
78 * \param data the user data you want to associate with the task (can be \c NULL)
79 * \param amount amount of the task
80 * \return the new task
81 * \see SD_task_destroy()
83 SD_task_t SD_task_create(const char *name, void *data, double amount)
85 SD_task_t task = (SD_task_t)xbt_mallocator_get(sd_global->task_mallocator);
87 /* general information */
88 task->data = data; /* user data */
89 task->name = xbt_strdup(name);
90 task->amount = amount;
91 task->remains = amount;
93 sd_global->task_number++;
95 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->bytes_amount = xbt_new0(double, ws_count * ws_count);
106 task->flops_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->bytes_amount[2] = amount;
127 res->kind = SD_TASK_COMM_E2E;
129 TRACE_category("COMM_E2E");
130 TRACE_sd_set_task_category(res, "COMM_E2E");
135 /** @brief create a sequential computation task that can then be auto-scheduled
137 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
138 * allows to specify the task costs at creation, and decouple them from the
139 * scheduling process where you just specify which resource should deliver the
142 * A sequential computation must be scheduled on 1 host, and the amount
143 * specified at creation to be run on hosts[0].
145 * \param name the name of the task (can be \c NULL)
146 * \param data the user data you want to associate with the task (can be \c NULL)
147 * \param flops_amount amount of compute work to be done by the task
148 * \return the new SD_TASK_COMP_SEQ typed task
150 SD_task_t SD_task_create_comp_seq(const char *name, void *data,
153 SD_task_t res = SD_task_create_sized(name, data, flops_amount, 1);
154 res->flops_amount[0] = flops_amount;
155 res->kind = SD_TASK_COMP_SEQ;
157 TRACE_category("COMP_SEQ");
158 TRACE_sd_set_task_category(res, "COMP_SEQ");
163 /** @brief create a parallel computation task that can then be auto-scheduled
165 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
166 * allows to specify the task costs at creation, and decouple them from the
167 * scheduling process where you just specify which resource should deliver the
170 * A parallel computation can be scheduled on any number of host.
171 * The underlying speedup model is Amdahl's law.
172 * To be auto-scheduled, \see SD_task_distribute_comp_amdahl has to be called
174 * \param name the name of the task (can be \c NULL)
175 * \param data the user data you want to associate with the task (can be \c NULL)
176 * \param flops_amount amount of compute work to be done by the task
177 * \param alpha purely serial fraction of the work to be done (in [0.;1.[)
178 * \return the new task
180 SD_task_t SD_task_create_comp_par_amdahl(const char *name, void *data,
181 double flops_amount, double alpha)
183 xbt_assert(alpha < 1. && alpha >= 0.,
184 "Invalid parameter: alpha must be in [0.;1.[");
186 SD_task_t res = SD_task_create(name, data, flops_amount);
188 res->kind = SD_TASK_COMP_PAR_AMDAHL;
190 TRACE_category("COMP_PAR_AMDAHL");
191 TRACE_sd_set_task_category(res, "COMP_PAR_AMDAHL");
196 /** @brief create a complex data redistribution task that can then be
199 * Auto-scheduling mean that the task can be used with SD_task_schedulev().
200 * This allows to specify the task costs at creation, and decouple them from
201 * the scheduling process where you just specify which resource should
204 * A data redistribution can be scheduled on any number of host.
205 * The assumed distribution is a 1D block distribution. Each host owns the same
206 * share of the \see amount.
207 * To be auto-scheduled, \see SD_task_distribute_comm_mxn_1d_block has to be
209 * \param name the name of the task (can be \c NULL)
210 * \param data the user data you want to associate with the task (can be
212 * \param amount amount of data to redistribute by the task
213 * \return the new task
215 SD_task_t SD_task_create_comm_par_mxn_1d_block(const char *name, void *data,
218 SD_task_t res = SD_task_create(name, data, amount);
219 res->workstation_list=NULL;
220 res->kind = SD_TASK_COMM_PAR_MXN_1D_BLOCK;
222 TRACE_category("COMM_PAR_MXN_1D_BLOCK");
223 TRACE_sd_set_task_category(res, "COMM_PAR_MXN_1D_BLOCK");
229 * \brief Destroys a task.
231 * The user data (if any) should have been destroyed first.
233 * \param task the task you want to destroy
234 * \see SD_task_create()
236 void SD_task_destroy(SD_task_t task)
238 XBT_DEBUG("Destroying task %s...", SD_task_get_name(task));
240 __SD_task_remove_dependencies(task);
241 /* if the task was scheduled or runnable we have to free the scheduling parameters */
242 if (__SD_task_is_scheduled_or_runnable(task))
243 __SD_task_destroy_scheduling_data(task);
244 if (task->state_set != NULL) /* would be null if just created */
245 xbt_swag_remove(task, task->state_set);
247 xbt_swag_remove(task, sd_global->return_set);
249 xbt_free(task->name);
251 if (task->surf_action != NULL)
252 task->surf_action->unref();
254 xbt_free(task->workstation_list);
255 xbt_free(task->bytes_amount);
256 xbt_free(task->flops_amount);
258 TRACE_sd_task_destroy(task);
260 xbt_mallocator_release(sd_global->task_mallocator,task);
261 sd_global->task_number--;
263 XBT_DEBUG("Task destroyed.");
267 * \brief Returns the user data of a task
270 * \return the user data associated with this task (can be \c NULL)
271 * \see SD_task_set_data()
273 void *SD_task_get_data(SD_task_t task)
279 * \brief Sets the user data of a task
281 * The new data can be \c NULL. The old data should have been freed first
282 * if it was not \c NULL.
285 * \param data the new data you want to associate with this task
286 * \see SD_task_get_data()
288 void SD_task_set_data(SD_task_t task, void *data)
294 * \brief Sets the rate of a task
296 * This will change the network bandwidth a task can use. This rate
297 * cannot be dynamically changed. Once the task has started, this call
298 * is ineffective. This rate depends on both the nominal bandwidth on
299 * the route onto which the task is scheduled (\see
300 * SD_task_get_current_bandwidth) and the amount of data to transfer.
302 * To divide the nominal bandwidth by 2, the rate then has to be :
303 * rate = bandwidth/(2*amount)
305 * \param task a \see SD_TASK_COMM_E2E task (end-to-end communication)
306 * \param rate the new rate you want to associate with this task.
308 void SD_task_set_rate(SD_task_t task, double rate)
310 xbt_assert(task->kind == SD_TASK_COMM_E2E,
311 "The rate can be modified for end-to-end communications only.");
312 if(task->start_time<0) {
315 XBT_WARN("Task %p has started. Changing rate is ineffective.", task);
320 * \brief Returns the state of a task
323 * \return the current \ref e_SD_task_state_t "state" of this task:
324 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING, #SD_DONE or #SD_FAILED
325 * \see e_SD_task_state_t
327 e_SD_task_state_t SD_task_get_state(SD_task_t task)
332 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
334 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
336 xbt_swag_remove(task, task->state_set);
338 case SD_NOT_SCHEDULED:
339 task->state_set = sd_global->not_scheduled_task_set;
342 task->state_set = sd_global->schedulable_task_set;
345 task->state_set = sd_global->scheduled_task_set;
348 task->state_set = sd_global->runnable_task_set;
351 task->state_set = sd_global->in_fifo_task_set;
354 task->state_set = sd_global->running_task_set;
355 task->start_time = task->surf_action->getStartTime();
358 task->state_set = sd_global->done_task_set;
359 task->finish_time = task->surf_action->getFinishTime();
362 jedule_log_sd_event(task);
366 task->state_set = sd_global->failed_task_set;
369 xbt_die( "Invalid state");
371 xbt_swag_insert(task, task->state_set);
372 task->state = new_state;
374 if (task->watch_points & new_state) {
375 XBT_VERB("Watch point reached with task '%s'!", SD_task_get_name(task));
376 sd_global->watch_point_reached = 1;
377 SD_task_unwatch(task, new_state); /* remove the watch point */
382 * \brief Returns the name of a task
385 * \return the name of this task (can be \c NULL)
387 const char *SD_task_get_name(SD_task_t task)
392 /** @brief Allows to change the name of a task */
393 void SD_task_set_name(SD_task_t task, const char *name)
395 xbt_free(task->name);
396 task->name = xbt_strdup(name);
399 /** @brief Returns the dynar of the parents of a task
402 * \return a newly allocated dynar comprising the parents of this task
405 xbt_dynar_t SD_task_get_parents(SD_task_t task)
411 parents = xbt_dynar_new(sizeof(SD_task_t), NULL);
412 xbt_dynar_foreach(task->tasks_before, i, dep) {
413 xbt_dynar_push(parents, &(dep->src));
418 /** @brief Returns the dynar of the parents of a task
421 * \return a newly allocated dynar comprising the parents of this task
423 xbt_dynar_t SD_task_get_children(SD_task_t task)
426 xbt_dynar_t children;
429 children = xbt_dynar_new(sizeof(SD_task_t), NULL);
430 xbt_dynar_foreach(task->tasks_after, i, dep) {
431 xbt_dynar_push(children, &(dep->dst));
437 * \brief Returns the amount of workstations involved in a task
439 * Only call this on already scheduled tasks!
442 int SD_task_get_workstation_count(SD_task_t task)
444 return task->workstation_nb;
448 * \brief Returns the list of workstations involved in a task
450 * Only call this on already scheduled tasks!
453 SD_workstation_t *SD_task_get_workstation_list(SD_task_t task)
455 return task->workstation_list;
459 * \brief Returns the total amount of work contained in a task
462 * \return the total amount of work (computation or data transfer) for this task
463 * \see SD_task_get_remaining_amount()
465 double SD_task_get_amount(SD_task_t task)
471 * \brief Sets the total amount of work of a task
472 * For sequential typed tasks (COMP_SEQ and COMM_E2E), it also sets the
473 * appropriate values in the flops_amount and bytes_amount arrays
474 * respectively. Nothing more than modifying task->amount is done for paralle
475 * typed tasks (COMP_PAR_AMDAHL and COMM_PAR_MXN_1D_BLOCK) as the distribution
476 * of the amount of work is done at scheduling time.
479 * \param amount the new amount of work to execute
481 void SD_task_set_amount(SD_task_t task, double amount)
483 task->amount = amount;
484 if (task->kind == SD_TASK_COMP_SEQ)
485 task->flops_amount[0] = amount;
486 if (task->kind == SD_TASK_COMM_E2E)
487 task->bytes_amount[2] = amount;
491 * \brief Returns the alpha parameter of a SD_TASK_COMP_PAR_AMDAHL task
493 * \param task a parallel task assuming Amdahl's law as speedup model
494 * \return the alpha parameter (serial part of a task in percent) for this task
496 double SD_task_get_alpha(SD_task_t task)
498 xbt_assert(SD_task_get_kind(task) == SD_TASK_COMP_PAR_AMDAHL,
499 "Alpha parameter is not defined for this kink of task");
505 * \brief Returns the remaining amount work to do till the completion of a task
508 * \return the remaining amount of work (computation or data transfer) of this task
509 * \see SD_task_get_amount()
511 double SD_task_get_remaining_amount(SD_task_t task)
513 if (task->surf_action)
514 return surf_action_get_remains(task->surf_action);
516 return task->remains;
519 int SD_task_get_kind(SD_task_t task)
524 /** @brief Displays debugging informations about a task */
525 void SD_task_dump(SD_task_t task)
527 unsigned int counter;
528 SD_dependency_t dependency;
531 XBT_INFO("Displaying task %s", SD_task_get_name(task));
532 statename = bprintf("%s %s %s %s %s %s %s %s",
533 (task->state == SD_NOT_SCHEDULED ? "not scheduled" :
535 (task->state == SD_SCHEDULABLE ? "schedulable" : ""),
536 (task->state == SD_SCHEDULED ? "scheduled" : ""),
537 (task->state == SD_RUNNABLE ? "runnable" :
539 (task->state == SD_IN_FIFO ? "in fifo" : ""),
540 (task->state == SD_RUNNING ? "running" : ""),
541 (task->state == SD_DONE ? "done" : ""),
542 (task->state == SD_FAILED ? "failed" : ""));
543 XBT_INFO(" - state: %s", statename);
546 if (task->kind != 0) {
547 switch (task->kind) {
548 case SD_TASK_COMM_E2E:
549 XBT_INFO(" - kind: end-to-end communication");
551 case SD_TASK_COMP_SEQ:
552 XBT_INFO(" - kind: sequential computation");
554 case SD_TASK_COMP_PAR_AMDAHL:
555 XBT_INFO(" - kind: parallel computation following Amdahl's law");
557 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
558 XBT_INFO(" - kind: MxN data redistribution assuming 1D block distribution");
561 XBT_INFO(" - (unknown kind %d)", task->kind);
566 XBT_INFO(" - tracing category: %s", task->category);
568 XBT_INFO(" - amount: %.0f", SD_task_get_amount(task));
569 if (task->kind == SD_TASK_COMP_PAR_AMDAHL)
570 XBT_INFO(" - alpha: %.2f", task->alpha);
571 XBT_INFO(" - Dependencies to satisfy: %d", task->unsatisfied_dependencies);
572 if (!xbt_dynar_is_empty(task->tasks_before)) {
573 XBT_INFO(" - pre-dependencies:");
574 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
575 XBT_INFO(" %s", SD_task_get_name(dependency->src));
578 if (!xbt_dynar_is_empty(task->tasks_after)) {
579 XBT_INFO(" - post-dependencies:");
580 xbt_dynar_foreach(task->tasks_after, counter, dependency) {
581 XBT_INFO(" %s", SD_task_get_name(dependency->dst));
586 /** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */
587 void SD_task_dotty(SD_task_t task, void *out)
589 unsigned int counter;
590 SD_dependency_t dependency;
591 FILE *fout = (FILE*)out;
592 fprintf(fout, " T%p [label=\"%.20s\"", task, task->name);
593 switch (task->kind) {
594 case SD_TASK_COMM_E2E:
595 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
596 fprintf(fout, ", shape=box");
598 case SD_TASK_COMP_SEQ:
599 case SD_TASK_COMP_PAR_AMDAHL:
600 fprintf(fout, ", shape=circle");
603 xbt_die("Unknown task type!");
605 fprintf(fout, "];\n");
606 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
607 fprintf(fout, " T%p -> T%p;\n", dependency->src, dependency->dst);
611 /* Destroys a dependency between two tasks.
613 static void __SD_task_dependency_destroy(void *dependency)
615 xbt_free(((SD_dependency_t)dependency)->name);
616 xbt_free(dependency);
620 * \brief Adds a dependency between two tasks
622 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
623 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_RUNNABLE.
625 * \param name the name of the new dependency (can be \c NULL)
626 * \param data the user data you want to associate with this dependency (can be \c NULL)
627 * \param src the task which must be executed first
628 * \param dst the task you want to make depend on \a src
629 * \see SD_task_dependency_remove()
631 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
635 unsigned long length;
638 SD_dependency_t dependency;
640 dynar = src->tasks_after;
641 length = xbt_dynar_length(dynar);
645 "Cannot add a dependency between task '%s' and itself",
646 SD_task_get_name(src));
648 if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_schedulable(src)
649 && !__SD_task_is_scheduled_or_runnable(src) && !__SD_task_is_running(src))
651 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE"
653 SD_task_get_name(src));
655 if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_schedulable(dst)
656 && !__SD_task_is_scheduled_or_runnable(dst))
658 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE",
659 SD_task_get_name(dst));
661 XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s",
662 SD_task_get_name(src), SD_task_get_name(dst));
663 for (i = 0; i < length && !found; i++) {
664 xbt_dynar_get_cpy(dynar, i, &dependency);
665 found = (dependency->dst == dst);
666 XBT_DEBUG("Dependency %lu: dependency->dst = %s", i,
667 SD_task_get_name(dependency->dst));
672 "A dependency already exists between task '%s' and task '%s'",
673 SD_task_get_name(src), SD_task_get_name(dst));
675 dependency = xbt_new(s_SD_dependency_t, 1);
677 dependency->name = xbt_strdup(name); /* xbt_strdup is cleaver enough to deal with NULL args itself */
678 dependency->data = data;
679 dependency->src = src;
680 dependency->dst = dst;
682 /* src must be executed before dst */
683 xbt_dynar_push(src->tasks_after, &dependency);
684 xbt_dynar_push(dst->tasks_before, &dependency);
686 dst->unsatisfied_dependencies++;
689 /* if the task was runnable, then dst->tasks_before is not empty anymore,
690 so we must go back to state SD_SCHEDULED */
691 if (__SD_task_is_runnable(dst)) {
693 ("SD_task_dependency_add: %s was runnable and becomes scheduled!",
694 SD_task_get_name(dst));
695 __SD_task_set_state(dst, SD_SCHEDULED);
699 * \brief Returns the name given as input when dependency has been created..
702 * \param dst a task depending on \a src
705 const char *SD_task_dependency_get_name(SD_task_t src, SD_task_t dst){
707 SD_dependency_t dependency;
709 xbt_dynar_foreach(src->tasks_after, i, dependency){
710 if (dependency->dst == dst)
711 return dependency->name;
717 * \brief Indicates whether there is a dependency between two tasks.
720 * \param dst a task depending on \a src
722 * If src is NULL, checks whether dst has any pre-dependency.
723 * If dst is NULL, checks whether src has any post-dependency.
725 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
727 unsigned int counter;
728 SD_dependency_t dependency;
730 xbt_assert(src != NULL
732 "Invalid parameter: both src and dst are NULL");
736 xbt_dynar_foreach(src->tasks_after, counter, dependency) {
737 if (dependency->dst == dst)
741 return xbt_dynar_length(src->tasks_after);
744 return xbt_dynar_length(dst->tasks_before);
750 * \brief Remove a dependency between two tasks
753 * \param dst a task depending on \a src
754 * \see SD_task_dependency_add()
756 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
760 unsigned long length;
763 SD_dependency_t dependency;
765 /* remove the dependency from src->tasks_after */
766 dynar = src->tasks_after;
767 length = xbt_dynar_length(dynar);
769 for (i = 0; i < length && !found; i++) {
770 xbt_dynar_get_cpy(dynar, i, &dependency);
771 if (dependency->dst == dst) {
772 xbt_dynar_remove_at(dynar, i, NULL);
778 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
779 SD_task_get_name(src), SD_task_get_name(dst),
780 SD_task_get_name(dst), SD_task_get_name(src));
782 /* remove the dependency from dst->tasks_before */
783 dynar = dst->tasks_before;
784 length = xbt_dynar_length(dynar);
787 for (i = 0; i < length && !found; i++) {
788 xbt_dynar_get_cpy(dynar, i, &dependency);
789 if (dependency->src == src) {
790 xbt_dynar_remove_at(dynar, i, NULL);
791 __SD_task_dependency_destroy(dependency);
792 dst->unsatisfied_dependencies--;
797 /* should never happen... */
799 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
800 SD_task_get_name(dst), SD_task_get_name(src),
801 SD_task_get_name(src), SD_task_get_name(dst));
803 /* if the task was scheduled and dst->tasks_before is empty now, we can make it runnable */
805 if (dst->unsatisfied_dependencies == 0) {
806 if (__SD_task_is_scheduled(dst))
807 __SD_task_set_state(dst, SD_RUNNABLE);
809 __SD_task_set_state(dst, SD_SCHEDULABLE);
812 if (dst->is_not_ready == 0)
813 __SD_task_set_state(dst, SD_SCHEDULABLE);
815 /* __SD_print_dependencies(src);
816 __SD_print_dependencies(dst); */
820 * \brief Returns the user data associated with a dependency between two tasks
823 * \param dst a task depending on \a src
824 * \return the user data associated with this dependency (can be \c NULL)
825 * \see SD_task_dependency_add()
827 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
831 unsigned long length;
834 SD_dependency_t dependency;
836 dynar = src->tasks_after;
837 length = xbt_dynar_length(dynar);
839 for (i = 0; i < length && !found; i++) {
840 xbt_dynar_get_cpy(dynar, i, &dependency);
841 found = (dependency->dst == dst);
844 THROWF(arg_error, 0, "No dependency found between task '%s' and '%s'",
845 SD_task_get_name(src), SD_task_get_name(dst));
846 return dependency->data;
849 /* temporary function for debugging */
850 static void __SD_print_watch_points(SD_task_t task)
852 static const int state_masks[] =
853 { SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNING, SD_RUNNABLE, SD_DONE,
856 static const char *state_names[] =
857 { "schedulable", "scheduled", "running", "runnable", "done",
862 XBT_INFO("Task '%s' watch points (%x): ", SD_task_get_name(task),
866 for (i = 0; i < 5; i++) {
867 if (task->watch_points & state_masks[i])
868 XBT_INFO("%s ", state_names[i]);
873 * \brief Adds a watch point to a task
875 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
876 * task becomes the one given in argument. The
877 * watch point is then automatically removed.
880 * \param state the \ref e_SD_task_state_t "state" you want to watch
881 * (cannot be #SD_NOT_SCHEDULED)
882 * \see SD_task_unwatch()
884 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
886 if (state & SD_NOT_SCHEDULED)
888 "Cannot add a watch point for state SD_NOT_SCHEDULED");
890 task->watch_points = task->watch_points | state;
891 /* __SD_print_watch_points(task); */
895 * \brief Removes a watch point from a task
898 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
899 * \see SD_task_watch()
901 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
903 xbt_assert(state != SD_NOT_SCHEDULED,
904 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
906 task->watch_points = task->watch_points & ~state;
907 /* __SD_print_watch_points(task); */
911 * \brief Returns an approximative estimation of the execution time of a task.
913 * The estimation is very approximative because the value returned is the time
914 * the task would take if it was executed now and if it was the only task.
916 * \param task the task to evaluate
917 * \param workstation_nb number of workstations on which the task would be executed
918 * \param workstation_list the workstations on which the task would be executed
919 * \param flops_amount computation amount for each workstation
920 * \param bytes_amount communication amount between each pair of workstations
923 double SD_task_get_execution_time(SD_task_t task,
925 const SD_workstation_t *
927 const double *flops_amount,
928 const double *bytes_amount)
930 double time, max_time = 0.0;
932 xbt_assert(workstation_nb > 0, "Invalid parameter");
934 /* the task execution time is the maximum execution time of the parallel tasks */
936 for (i = 0; i < workstation_nb; i++) {
938 if (flops_amount != NULL)
940 SD_workstation_get_computation_time(workstation_list[i],
943 if (bytes_amount != NULL)
944 for (j = 0; j < workstation_nb; j++) {
946 SD_route_get_communication_time(workstation_list[i],
953 if (time > max_time) {
960 static XBT_INLINE void SD_task_do_schedule(SD_task_t task)
962 if (!__SD_task_is_not_scheduled(task) && !__SD_task_is_schedulable(task))
963 THROWF(arg_error, 0, "Task '%s' has already been scheduled",
964 SD_task_get_name(task));
966 /* update the task state */
967 if (task->unsatisfied_dependencies == 0)
968 __SD_task_set_state(task, SD_RUNNABLE);
970 __SD_task_set_state(task, SD_SCHEDULED);
974 * \brief Schedules a task
976 * The task state must be #SD_NOT_SCHEDULED.
977 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
978 * i.e. when its dependencies are satisfied.
980 * \param task the task you want to schedule
981 * \param workstation_count number of workstations on which the task will be executed
982 * \param workstation_list the workstations on which the task will be executed
983 * \param flops_amount computation amount for each workstation
984 * \param bytes_amount communication amount between each pair of workstations
985 * \param rate task execution speed rate
986 * \see SD_task_unschedule()
988 void SD_task_schedule(SD_task_t task, int workstation_count,
989 const SD_workstation_t * workstation_list,
990 const double *flops_amount,
991 const double *bytes_amount, double rate)
993 xbt_assert(workstation_count > 0, "workstation_nb must be positive");
995 task->workstation_nb = workstation_count;
999 task->flops_amount = (double*)xbt_realloc(task->flops_amount,
1000 sizeof(double) * workstation_count);
1001 memcpy(task->flops_amount, flops_amount,
1002 sizeof(double) * workstation_count);
1004 xbt_free(task->flops_amount);
1005 task->flops_amount = NULL;
1008 int communication_nb = workstation_count * workstation_count;
1010 task->bytes_amount = (double*)xbt_realloc(task->bytes_amount,
1011 sizeof(double) * communication_nb);
1012 memcpy(task->bytes_amount, bytes_amount,
1013 sizeof(double) * communication_nb);
1015 xbt_free(task->bytes_amount);
1016 task->bytes_amount = NULL;
1019 task->workstation_list = (SD_workstation_t*)
1020 xbt_realloc(task->workstation_list,
1021 sizeof(SD_workstation_t) * workstation_count);
1022 memcpy(task->workstation_list, workstation_list,
1023 sizeof(SD_workstation_t) * workstation_count);
1025 SD_task_do_schedule(task);
1029 * \brief Unschedules a task
1031 * The task state must be #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING or #SD_FAILED.
1032 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
1033 * Call SD_task_schedule() to schedule it again.
1035 * \param task the task you want to unschedule
1036 * \see SD_task_schedule()
1038 void SD_task_unschedule(SD_task_t task)
1040 if (task->state_set != sd_global->scheduled_task_set &&
1041 task->state_set != sd_global->runnable_task_set &&
1042 task->state_set != sd_global->running_task_set &&
1043 task->state_set != sd_global->failed_task_set)
1044 THROWF(arg_error, 0,
1045 "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED",
1046 SD_task_get_name(task));
1048 if (__SD_task_is_scheduled_or_runnable(task) /* if the task is scheduled or runnable */
1049 && ((task->kind == SD_TASK_COMP_PAR_AMDAHL) ||
1050 (task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK))) { /* Don't free scheduling data for typed tasks */
1051 __SD_task_destroy_scheduling_data(task);
1052 xbt_free(task->workstation_list);
1053 task->workstation_list=NULL;
1054 task->workstation_nb = 0;
1057 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
1058 task->surf_action->cancel();
1060 if (task->unsatisfied_dependencies == 0)
1061 __SD_task_set_state(task, SD_SCHEDULABLE);
1063 __SD_task_set_state(task, SD_NOT_SCHEDULED);
1065 task->remains = task->amount;
1066 task->start_time = -1.0;
1069 /* Destroys the data memorized by SD_task_schedule.
1070 * Task state must be SD_SCHEDULED or SD_RUNNABLE.
1072 static void __SD_task_destroy_scheduling_data(SD_task_t task)
1074 if (!__SD_task_is_scheduled_or_runnable(task)
1075 && !__SD_task_is_in_fifo(task))
1076 THROWF(arg_error, 0,
1077 "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
1078 SD_task_get_name(task));
1080 xbt_free(task->flops_amount);
1081 xbt_free(task->bytes_amount);
1082 task->flops_amount = task->bytes_amount = NULL;
1085 /* Runs a task. This function is directly called by __SD_task_try_to_run if
1086 * the task doesn't have to wait in FIFOs. Otherwise, it is called by
1087 * __SD_task_just_done when the task gets out of its FIFOs.
1089 void __SD_task_really_run(SD_task_t task)
1095 xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
1096 "Task '%s' is not runnable or in a fifo! Task state: %d",
1097 SD_task_get_name(task), (int)SD_task_get_state(task));
1098 xbt_assert(task->workstation_list != NULL,
1099 "Task '%s': workstation_list is NULL!",
1100 SD_task_get_name(task));
1102 XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
1103 int host_nb = task->workstation_nb;
1105 /* set this task as current task for the workstations in sequential mode */
1106 for (i = 0; i < host_nb; i++) {
1107 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
1108 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1109 sg_host_sd(task->workstation_list[i])->current_task = task;
1110 xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
1111 "The workstation should be busy now");
1115 XBT_DEBUG("Task '%s' set as current task for its workstations",
1116 SD_task_get_name(task));
1118 /* start the task */
1120 /* Copy the elements of the task into the action */
1121 hosts = xbt_new(sg_host_t, host_nb);
1123 for (i = 0; i < host_nb; i++)
1124 hosts[i] = task->workstation_list[i];
1126 double *flops_amount = xbt_new0(double, host_nb);
1127 double *bytes_amount = xbt_new0(double, host_nb * host_nb);
1130 if(task->flops_amount)
1131 memcpy(flops_amount, task->flops_amount, sizeof(double) *
1133 if(task->bytes_amount)
1134 memcpy(bytes_amount, task->bytes_amount,
1135 sizeof(double) * host_nb * host_nb);
1137 task->surf_action = surf_host_model->executeParallelTask(
1138 host_nb, hosts, flops_amount, bytes_amount, task->rate);
1140 task->surf_action->setData(task);
1142 XBT_DEBUG("surf_action = %p", task->surf_action);
1145 TRACE_surf_action(task->surf_action, task->category);
1147 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
1148 __SD_task_set_state(task, SD_RUNNING);
1149 xbt_assert(__SD_task_is_running(task), "Bad state of task '%s': %d",
1150 SD_task_get_name(task), (int)SD_task_get_state(task));
1154 /* Tries to run a task. This function is called by SD_simulate() when a
1155 * scheduled task becomes SD_RUNNABLE (i.e., when its dependencies are
1157 * If one of the workstations where the task is scheduled on is busy (in
1158 * sequential mode), the task doesn't start.
1159 * Returns whether the task has started.
1161 int __SD_task_try_to_run(SD_task_t task)
1166 SD_workstation_t workstation;
1168 xbt_assert(__SD_task_is_runnable(task),
1169 "Task '%s' is not runnable! Task state: %d",
1170 SD_task_get_name(task), (int)SD_task_get_state(task));
1173 for (i = 0; i < task->workstation_nb; i++) {
1174 can_start = can_start &&
1175 !__SD_workstation_is_busy(task->workstation_list[i]);
1178 XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
1180 if (!can_start) { /* if the task cannot start and is not in the FIFOs yet */
1181 for (i = 0; i < task->workstation_nb; i++) {
1182 workstation = task->workstation_list[i];
1183 if (sg_host_sd(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1184 XBT_DEBUG("Pushing task '%s' in the FIFO of workstation '%s'",
1185 SD_task_get_name(task),
1186 SD_workstation_get_name(workstation));
1187 xbt_fifo_push(sg_host_sd(workstation)->task_fifo, task);
1190 __SD_task_set_state(task, SD_IN_FIFO);
1191 xbt_assert(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
1192 SD_task_get_name(task), (int)SD_task_get_state(task));
1193 XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
1195 __SD_task_really_run(task);
1201 /* This function is called by SD_simulate when a task is done.
1202 * It updates task->state and task->action and executes if necessary the tasks
1203 * which were waiting in FIFOs for the end of `task'
1205 void __SD_task_just_done(SD_task_t task)
1208 SD_workstation_t workstation;
1210 SD_task_t candidate;
1211 int candidate_nb = 0;
1212 int candidate_capacity = 8;
1213 SD_task_t *candidates;
1216 xbt_assert(__SD_task_is_running(task),
1217 "The task must be running! Task state: %d",
1218 (int)SD_task_get_state(task));
1219 xbt_assert(task->workstation_list != NULL,
1220 "Task '%s': workstation_list is NULL!",
1221 SD_task_get_name(task));
1224 candidates = xbt_new(SD_task_t, 8);
1226 __SD_task_set_state(task, SD_DONE);
1227 task->surf_action->unref();
1228 task->surf_action = NULL;
1230 XBT_DEBUG("Looking for candidates");
1232 /* if the task was executed on sequential workstations,
1233 maybe we can execute the next task of the FIFO for each workstation */
1234 for (i = 0; i < task->workstation_nb; i++) {
1235 workstation = task->workstation_list[i];
1236 XBT_DEBUG("Workstation '%s': access_mode = %d",
1237 SD_workstation_get_name(workstation), (int)sg_host_sd(workstation)->access_mode);
1238 if (sg_host_sd(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1239 xbt_assert(sg_host_sd(workstation)->task_fifo != NULL,
1240 "Workstation '%s' has sequential access but no FIFO!",
1241 SD_workstation_get_name(workstation));
1242 xbt_assert(sg_host_sd(workstation)->current_task =
1243 task, "Workstation '%s': current task should be '%s'",
1244 SD_workstation_get_name(workstation),
1245 SD_task_get_name(task));
1247 /* the task is over so we can release the workstation */
1248 sg_host_sd(workstation)->current_task = NULL;
1250 XBT_DEBUG("Getting candidate in FIFO");
1251 candidate = (SD_task_t)
1252 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1253 (sg_host_sd(workstation)->task_fifo));
1255 if (candidate != NULL) {
1256 XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
1257 xbt_assert(__SD_task_is_in_fifo(candidate),
1258 "Bad state of candidate '%s': %d",
1259 SD_task_get_name(candidate),
1260 (int)SD_task_get_state(candidate));
1263 XBT_DEBUG("Candidate in fifo: %p", candidate);
1265 /* if there was a task waiting for my place */
1266 if (candidate != NULL) {
1267 /* Unfortunately, we are not sure yet that we can execute the task now,
1268 because the task can be waiting more deeply in some other
1269 workstation's FIFOs ...
1270 So we memorize all candidate tasks, and then we will check for each
1271 candidate whether or not all its workstations are available. */
1273 /* realloc if necessary */
1274 if (candidate_nb == candidate_capacity) {
1275 candidate_capacity *= 2;
1276 candidates = (SD_task_t*)
1277 xbt_realloc(candidates,
1278 sizeof(SD_task_t) * candidate_capacity);
1281 /* register the candidate */
1282 candidates[candidate_nb++] = candidate;
1283 candidate->fifo_checked = 0;
1288 XBT_DEBUG("Candidates found: %d", candidate_nb);
1290 /* now we check every candidate task */
1291 for (i = 0; i < candidate_nb; i++) {
1292 candidate = candidates[i];
1294 if (candidate->fifo_checked) {
1295 continue; /* we have already evaluated that task */
1298 xbt_assert(__SD_task_is_in_fifo(candidate),
1299 "Bad state of candidate '%s': %d",
1300 SD_task_get_name(candidate), (int)SD_task_get_state(candidate));
1302 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1303 workstation = candidate->workstation_list[j];
1305 /* I can start on this workstation if the workstation is shared
1306 or if I am the first task in the FIFO */
1307 can_start = sg_host_sd(workstation)->access_mode == SD_WORKSTATION_SHARED_ACCESS
1309 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1310 (sg_host_sd(workstation)->task_fifo));
1313 XBT_DEBUG("Candidate '%s' can start: %d", SD_task_get_name(candidate),
1316 /* now we are sure that I can start! */
1318 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1319 workstation = candidate->workstation_list[j];
1321 /* update the FIFO */
1322 if (sg_host_sd(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1323 candidate = (SD_task_t)xbt_fifo_shift(sg_host_sd(workstation)->task_fifo); /* the return value is stored just for debugging */
1324 XBT_DEBUG("Head of the FIFO: '%s'",
1326 NULL) ? SD_task_get_name(candidate) : "NULL");
1327 xbt_assert(candidate == candidates[i],
1328 "Error in __SD_task_just_done: bad first task in the FIFO");
1330 } /* for each workstation */
1332 /* finally execute the task */
1333 XBT_DEBUG("Task '%s' state: %d", SD_task_get_name(candidate),
1334 (int)SD_task_get_state(candidate));
1335 __SD_task_really_run(candidate);
1338 ("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
1339 SD_task_get_name(candidate), candidate->state_set,
1340 sd_global->running_task_set, __SD_task_is_running(candidate));
1341 xbt_assert(__SD_task_is_running(candidate),
1342 "Bad state of task '%s': %d",
1343 SD_task_get_name(candidate),
1344 (int)SD_task_get_state(candidate));
1345 XBT_DEBUG("Okay, the task is running.");
1348 candidate->fifo_checked = 1;
1349 } /* for each candidate */
1351 xbt_free(candidates);
1355 * Remove all dependencies associated with a task. This function is called
1356 * when the task is destroyed.
1358 static void __SD_task_remove_dependencies(SD_task_t task)
1360 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
1361 because each one is stored twice */
1362 SD_dependency_t dependency;
1363 while (!xbt_dynar_is_empty(task->tasks_before)) {
1364 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
1365 SD_task_dependency_remove(dependency->src, dependency->dst);
1368 while (!xbt_dynar_is_empty(task->tasks_after)) {
1369 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
1370 SD_task_dependency_remove(dependency->src, dependency->dst);
1375 * \brief Returns the start time of a task
1377 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1379 * \param task: a task
1380 * \return the start time of this task
1382 double SD_task_get_start_time(SD_task_t task)
1384 if (task->surf_action)
1385 return task->surf_action->getStartTime();
1387 return task->start_time;
1391 * \brief Returns the finish time of a task
1393 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1394 * If the state is not completed yet, the returned value is an
1395 * estimation of the task finish time. This value can fluctuate
1396 * until the task is completed.
1398 * \param task: a task
1399 * \return the start time of this task
1401 double SD_task_get_finish_time(SD_task_t task)
1403 if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
1404 return task->surf_action->getFinishTime();
1406 return task->finish_time;
1411 void SD_task_distribute_comp_amdahl(SD_task_t task, int ws_count)
1414 xbt_assert(task->kind == SD_TASK_COMP_PAR_AMDAHL,
1415 "Task %s is not a SD_TASK_COMP_PAR_AMDAHL typed task."
1416 "Cannot use this function.",
1417 SD_task_get_name(task));
1418 task->flops_amount = xbt_new0(double, ws_count);
1419 task->bytes_amount = xbt_new0(double, ws_count * ws_count);
1420 xbt_free(task->workstation_list);
1421 task->workstation_nb = ws_count;
1422 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
1424 for(i=0;i<ws_count;i++){
1425 task->flops_amount[i] =
1426 (task->alpha + (1 - task->alpha)/ws_count) * task->amount;
1431 /** @brief Auto-schedules a task.
1433 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1434 * allows to specify the task costs at creation, and decouple them from the
1435 * scheduling process where you just specify which resource should deliver the
1438 * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e()
1439 * or SD_task_create_comp_seq(). Check their definitions for the exact semantic
1443 * We should create tasks kind for the following categories:
1444 * - Point to point communication (done)
1445 * - Sequential computation (done)
1446 * - group communication (redistribution, several kinds)
1447 * - parallel tasks with no internal communication (one kind per speedup
1448 * model such as Amdahl)
1449 * - idem+ internal communication. Task type not enough since we cannot store
1450 * comm cost alongside to comp one)
1452 void SD_task_schedulev(SD_task_t task, int count,
1453 const SD_workstation_t * list)
1456 SD_dependency_t dep;
1458 xbt_assert(task->kind != 0,
1459 "Task %s is not typed. Cannot automatically schedule it.",
1460 SD_task_get_name(task));
1461 switch (task->kind) {
1462 case SD_TASK_COMP_PAR_AMDAHL:
1463 SD_task_distribute_comp_amdahl(task, count);
1464 case SD_TASK_COMM_E2E:
1465 case SD_TASK_COMP_SEQ:
1466 xbt_assert(task->workstation_nb == count,
1467 "Got %d locations, but were expecting %d locations",
1468 count,task->workstation_nb);
1469 for (i = 0; i < count; i++)
1470 task->workstation_list[i] = list[i];
1471 if (SD_task_get_kind(task)== SD_TASK_COMP_SEQ && !task->flops_amount){
1472 /*This task has failed and is rescheduled. Reset the flops_amount*/
1473 task->flops_amount = xbt_new0(double, 1);
1474 task->flops_amount[0] = task->remains;
1476 SD_task_do_schedule(task);
1479 xbt_die("Kind of task %s not supported by SD_task_schedulev()",
1480 SD_task_get_name(task));
1482 if (task->kind == SD_TASK_COMM_E2E) {
1483 XBT_VERB("Schedule comm task %s between %s -> %s. It costs %.f bytes",
1484 SD_task_get_name(task),
1485 SD_workstation_get_name(task->workstation_list[0]),
1486 SD_workstation_get_name(task->workstation_list[1]),
1487 task->bytes_amount[2]);
1491 /* Iterate over all children and parents being COMM_E2E to say where I am
1492 * located (and start them if runnable) */
1493 if (task->kind == SD_TASK_COMP_SEQ) {
1494 XBT_VERB("Schedule computation task %s on %s. It costs %.f flops",
1495 SD_task_get_name(task),
1496 SD_workstation_get_name(task->workstation_list[0]),
1497 task->flops_amount[0]);
1499 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1500 SD_task_t before = dep->src;
1501 if (before->kind == SD_TASK_COMM_E2E) {
1502 before->workstation_list[1] = task->workstation_list[0];
1504 if (before->workstation_list[0] &&
1505 (__SD_task_is_schedulable(before)
1506 || __SD_task_is_not_scheduled(before))) {
1507 SD_task_do_schedule(before);
1509 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1510 SD_task_get_name(before),
1511 SD_workstation_get_name(before->workstation_list[0]),
1512 SD_workstation_get_name(before->workstation_list[1]),
1513 before->bytes_amount[2]);
1517 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1518 SD_task_t after = dep->dst;
1519 if (after->kind == SD_TASK_COMM_E2E) {
1520 after->workstation_list[0] = task->workstation_list[0];
1521 if (after->workstation_list[1]
1522 && (__SD_task_is_not_scheduled(after)
1523 || __SD_task_is_schedulable(after))) {
1524 SD_task_do_schedule(after);
1526 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1527 SD_task_get_name(after),
1528 SD_workstation_get_name(after->workstation_list[0]),
1529 SD_workstation_get_name(after->workstation_list[1]),
1530 after->bytes_amount[2]);
1536 /* Iterate over all children and parents being MXN_1D_BLOCK to say where I am
1537 * located (and start them if runnable) */
1538 if (task->kind == SD_TASK_COMP_PAR_AMDAHL) {
1539 XBT_VERB("Schedule computation task %s on %d workstations. %.f flops"
1540 " will be distributed following Amdahl's Law",
1541 SD_task_get_name(task), task->workstation_nb,
1542 task->flops_amount[0]);
1543 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1544 SD_task_t before = dep->src;
1545 if (before->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1546 if (!before->workstation_list){
1547 XBT_VERB("Sender side of Task %s is not scheduled yet",
1548 SD_task_get_name(before));
1549 before->workstation_list = xbt_new0(SD_workstation_t, count);
1550 before->workstation_nb = count;
1551 XBT_VERB("Fill the workstation list with list of Task '%s'",
1552 SD_task_get_name(task));
1553 for (i=0;i<count;i++)
1554 before->workstation_list[i] = task->workstation_list[i];
1556 XBT_VERB("Build communication matrix for task '%s'",
1557 SD_task_get_name(before));
1559 double src_start, src_end, dst_start, dst_end;
1560 src_nb = before->workstation_nb;
1562 before->workstation_list = (SD_workstation_t*) xbt_realloc(
1563 before->workstation_list,
1564 (before->workstation_nb+count)*sizeof(s_SD_workstation_t));
1565 for(i=0; i<count; i++)
1566 before->workstation_list[before->workstation_nb+i] =
1567 task->workstation_list[i];
1569 before->workstation_nb += count;
1570 xbt_free(before->flops_amount);
1571 xbt_free(before->bytes_amount);
1572 before->flops_amount = xbt_new0(double,
1573 before->workstation_nb);
1574 before->bytes_amount = xbt_new0(double,
1575 before->workstation_nb*
1576 before->workstation_nb);
1578 for(i=0;i<src_nb;i++){
1579 src_start = i*before->amount/src_nb;
1580 src_end = src_start + before->amount/src_nb;
1581 for(j=0; j<dst_nb; j++){
1582 dst_start = j*before->amount/dst_nb;
1583 dst_end = dst_start + before->amount/dst_nb;
1584 XBT_VERB("(%s->%s): (%.2f, %.2f)-> (%.2f, %.2f)",
1585 SD_workstation_get_name(before->workstation_list[i]),
1586 SD_workstation_get_name(before->workstation_list[src_nb+j]),
1587 src_start, src_end, dst_start, dst_end);
1588 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1589 before->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1591 before->bytes_amount[i*(src_nb+dst_nb)+src_nb+j] =
1592 MIN(src_end, dst_end) - MAX(src_start, dst_start);
1594 XBT_VERB("==> %.2f",
1595 before->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]);
1599 if (__SD_task_is_schedulable(before) ||
1600 __SD_task_is_not_scheduled(before)) {
1601 SD_task_do_schedule(before);
1603 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1604 SD_task_get_name(before),before->amount, src_nb, dst_nb);
1609 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1610 SD_task_t after = dep->dst;
1611 if (after->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1612 if (!after->workstation_list){
1613 XBT_VERB("Receiver side of Task '%s' is not scheduled yet",
1614 SD_task_get_name(after));
1615 after->workstation_list = xbt_new0(SD_workstation_t, count);
1616 after->workstation_nb = count;
1617 XBT_VERB("Fill the workstation list with list of Task '%s'",
1618 SD_task_get_name(task));
1619 for (i=0;i<count;i++)
1620 after->workstation_list[i] = task->workstation_list[i];
1623 double src_start, src_end, dst_start, dst_end;
1625 dst_nb = after->workstation_nb;
1626 after->workstation_list = (SD_workstation_t*) xbt_realloc(
1627 after->workstation_list,
1628 (after->workstation_nb+count)*sizeof(s_SD_workstation_t));
1629 for(i=after->workstation_nb - 1; i>=0; i--)
1630 after->workstation_list[count+i] = after->workstation_list[i];
1631 for(i=0; i<count; i++)
1632 after->workstation_list[i] = task->workstation_list[i];
1634 after->workstation_nb += count;
1636 xbt_free(after->flops_amount);
1637 xbt_free(after->bytes_amount);
1639 after->flops_amount = xbt_new0(double, after->workstation_nb);
1640 after->bytes_amount = xbt_new0(double,
1641 after->workstation_nb*
1642 after->workstation_nb);
1644 for(i=0;i<src_nb;i++){
1645 src_start = i*after->amount/src_nb;
1646 src_end = src_start + after->amount/src_nb;
1647 for(j=0; j<dst_nb; j++){
1648 dst_start = j*after->amount/dst_nb;
1649 dst_end = dst_start + after->amount/dst_nb;
1650 XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)",
1651 i, j, src_start, src_end, dst_start, dst_end);
1652 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1653 after->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1655 after->bytes_amount[i*(src_nb+dst_nb)+src_nb+j] =
1656 MIN(src_end, dst_end)- MAX(src_start, dst_start);
1658 XBT_VERB("==> %.2f",
1659 after->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]);
1663 if (__SD_task_is_schedulable(after) ||
1664 __SD_task_is_not_scheduled(after)) {
1665 SD_task_do_schedule(after);
1667 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1668 SD_task_get_name(after),after->amount, src_nb, dst_nb);
1676 /** @brief autoschedule a task on a list of workstations
1678 * This function is very similar to SD_task_schedulev(),
1679 * but takes the list of workstations to schedule onto as separate parameters.
1680 * It builds a proper vector of workstations and then call SD_task_schedulev()
1682 void SD_task_schedulel(SD_task_t task, int count, ...)
1685 SD_workstation_t *list = xbt_new(SD_workstation_t, count);
1687 va_start(ap, count);
1688 for (i = 0; i < count; i++) {
1689 list[i] = va_arg(ap, SD_workstation_t);
1692 SD_task_schedulev(task, count, list);