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= SD_NOT_SCHEDULED;
37 xbt_dynar_push(sd_global->initial_task_set,&task);
38 task->return_hookup.prev = NULL;
39 task->return_hookup.next = NULL;
43 task->start_time = -1.0;
44 task->finish_time = -1.0;
45 task->surf_action = NULL;
46 task->watch_points = 0;
49 xbt_dynar_reset(task->tasks_before);
50 xbt_dynar_reset(task->tasks_after);
51 task->unsatisfied_dependencies = 0;
52 task->is_not_ready = 0;
54 /* scheduling parameters */
55 task->workstation_nb = 0;
56 task->workstation_list = NULL;
57 task->flops_amount = NULL;
58 task->bytes_amount = NULL;
62 void SD_task_free_f(void *t)
64 SD_task_t task = (SD_task_t)t;
66 xbt_dynar_free(&task->tasks_before);
67 xbt_dynar_free(&task->tasks_after);
72 * \brief Creates a new task.
74 * \param name the name of the task (can be \c NULL)
75 * \param data the user data you want to associate with the task (can be \c NULL)
76 * \param amount amount of the task
77 * \return the new task
78 * \see SD_task_destroy()
80 SD_task_t SD_task_create(const char *name, void *data, double amount)
82 SD_task_t task = (SD_task_t)xbt_mallocator_get(sd_global->task_mallocator);
84 /* general information */
85 task->data = data; /* user data */
86 task->name = xbt_strdup(name);
87 task->amount = amount;
88 task->remains = amount;
90 sd_global->task_number++;
92 TRACE_sd_task_create(task);
97 static XBT_INLINE SD_task_t SD_task_create_sized(const char *name,
98 void *data, double amount,
101 SD_task_t task = SD_task_create(name, data, amount);
102 task->bytes_amount = xbt_new0(double, ws_count * ws_count);
103 task->flops_amount = xbt_new0(double, ws_count);
104 task->workstation_nb = ws_count;
105 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
109 /** @brief create a end-to-end communication task that can then be auto-scheduled
111 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
112 * allows to specify the task costs at creation, and decouple them from the
113 * scheduling process where you just specify which resource should deliver the
116 * A end-to-end communication must be scheduled on 2 hosts, and the amount
117 * specified at creation is sent from hosts[0] to hosts[1].
119 SD_task_t SD_task_create_comm_e2e(const char *name, void *data,
122 SD_task_t res = SD_task_create_sized(name, data, amount, 2);
123 res->bytes_amount[2] = amount;
124 res->kind = SD_TASK_COMM_E2E;
126 TRACE_category("COMM_E2E");
127 TRACE_sd_set_task_category(res, "COMM_E2E");
132 /** @brief create a sequential computation task that can then be auto-scheduled
134 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
135 * allows to specify the task costs at creation, and decouple them from the
136 * scheduling process where you just specify which resource should deliver the
139 * A sequential computation must be scheduled on 1 host, and the amount
140 * specified at creation to be run on hosts[0].
142 * \param name the name of the task (can be \c NULL)
143 * \param data the user data you want to associate with the task (can be \c NULL)
144 * \param flops_amount amount of compute work to be done by the task
145 * \return the new SD_TASK_COMP_SEQ typed task
147 SD_task_t SD_task_create_comp_seq(const char *name, void *data,
150 SD_task_t res = SD_task_create_sized(name, data, flops_amount, 1);
151 res->flops_amount[0] = flops_amount;
152 res->kind = SD_TASK_COMP_SEQ;
154 TRACE_category("COMP_SEQ");
155 TRACE_sd_set_task_category(res, "COMP_SEQ");
160 /** @brief create a parallel computation task that can then be auto-scheduled
162 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
163 * allows to specify the task costs at creation, and decouple them from the
164 * scheduling process where you just specify which resource should deliver the
167 * A parallel computation can be scheduled on any number of host.
168 * The underlying speedup model is Amdahl's law.
169 * To be auto-scheduled, \see SD_task_distribute_comp_amdahl has to be called
171 * \param name the name of the task (can be \c NULL)
172 * \param data the user data you want to associate with the task (can be \c NULL)
173 * \param flops_amount amount of compute work to be done by the task
174 * \param alpha purely serial fraction of the work to be done (in [0.;1.[)
175 * \return the new task
177 SD_task_t SD_task_create_comp_par_amdahl(const char *name, void *data,
178 double flops_amount, double alpha)
180 xbt_assert(alpha < 1. && alpha >= 0.,
181 "Invalid parameter: alpha must be in [0.;1.[");
183 SD_task_t res = SD_task_create(name, data, flops_amount);
185 res->kind = SD_TASK_COMP_PAR_AMDAHL;
187 TRACE_category("COMP_PAR_AMDAHL");
188 TRACE_sd_set_task_category(res, "COMP_PAR_AMDAHL");
193 /** @brief create a complex data redistribution task that can then be
196 * Auto-scheduling mean that the task can be used with SD_task_schedulev().
197 * This allows to specify the task costs at creation, and decouple them from
198 * the scheduling process where you just specify which resource should
201 * A data redistribution can be scheduled on any number of host.
202 * The assumed distribution is a 1D block distribution. Each host owns the same
203 * share of the \see amount.
204 * To be auto-scheduled, \see SD_task_distribute_comm_mxn_1d_block has to be
206 * \param name the name of the task (can be \c NULL)
207 * \param data the user data you want to associate with the task (can be
209 * \param amount amount of data to redistribute by the task
210 * \return the new task
212 SD_task_t SD_task_create_comm_par_mxn_1d_block(const char *name, void *data,
215 SD_task_t res = SD_task_create(name, data, amount);
216 res->workstation_list=NULL;
217 res->kind = SD_TASK_COMM_PAR_MXN_1D_BLOCK;
219 TRACE_category("COMM_PAR_MXN_1D_BLOCK");
220 TRACE_sd_set_task_category(res, "COMM_PAR_MXN_1D_BLOCK");
226 * \brief Destroys a task.
228 * The user data (if any) should have been destroyed first.
230 * \param task the task you want to destroy
231 * \see SD_task_create()
233 void SD_task_destroy(SD_task_t task)
235 XBT_DEBUG("Destroying task %s...", SD_task_get_name(task));
237 __SD_task_remove_dependencies(task);
238 /* if the task was scheduled or runnable we have to free the scheduling parameters */
239 if (__SD_task_is_scheduled_or_runnable(task))
240 __SD_task_destroy_scheduling_data(task);
242 xbt_swag_remove(task, sd_global->return_set);
244 xbt_free(task->name);
246 if (task->surf_action != NULL)
247 task->surf_action->unref();
249 xbt_free(task->workstation_list);
250 xbt_free(task->bytes_amount);
251 xbt_free(task->flops_amount);
253 TRACE_sd_task_destroy(task);
255 xbt_mallocator_release(sd_global->task_mallocator,task);
256 sd_global->task_number--;
258 XBT_DEBUG("Task destroyed.");
262 * \brief Returns the user data of a task
265 * \return the user data associated with this task (can be \c NULL)
266 * \see SD_task_set_data()
268 void *SD_task_get_data(SD_task_t task)
274 * \brief Sets the user data of a task
276 * The new data can be \c NULL. The old data should have been freed first
277 * if it was not \c NULL.
280 * \param data the new data you want to associate with this task
281 * \see SD_task_get_data()
283 void SD_task_set_data(SD_task_t task, void *data)
289 * \brief Sets the rate of a task
291 * This will change the network bandwidth a task can use. This rate
292 * cannot be dynamically changed. Once the task has started, this call
293 * is ineffective. This rate depends on both the nominal bandwidth on
294 * the route onto which the task is scheduled (\see
295 * SD_task_get_current_bandwidth) and the amount of data to transfer.
297 * To divide the nominal bandwidth by 2, the rate then has to be :
298 * rate = bandwidth/(2*amount)
300 * \param task a \see SD_TASK_COMM_E2E task (end-to-end communication)
301 * \param rate the new rate you want to associate with this task.
303 void SD_task_set_rate(SD_task_t task, double rate)
305 xbt_assert(task->kind == SD_TASK_COMM_E2E,
306 "The rate can be modified for end-to-end communications only.");
307 if(task->start_time<0) {
310 XBT_WARN("Task %p has started. Changing rate is ineffective.", task);
315 * \brief Returns the state of a task
318 * \return the current \ref e_SD_task_state_t "state" of this task:
319 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING, #SD_DONE or #SD_FAILED
320 * \see e_SD_task_state_t
322 e_SD_task_state_t SD_task_get_state(SD_task_t task)
327 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
329 void SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
333 case SD_NOT_SCHEDULED:
335 if (SD_task_get_state(task) == SD_FAILED){
336 xbt_dynar_remove_at(sd_global->completed_task_set,
337 xbt_dynar_search(sd_global->completed_task_set, &task), &task);
338 xbt_dynar_push(sd_global->initial_task_set,&task);
342 if (SD_task_get_state(task) == SD_RUNNABLE){
343 xbt_dynar_remove_at(sd_global->executable_task_set,
344 xbt_dynar_search(sd_global->executable_task_set, &task), &task);
345 xbt_dynar_push(sd_global->initial_task_set,&task);
349 xbt_dynar_remove_at(sd_global->executable_task_set,
350 xbt_dynar_search(sd_global->executable_task_set, &task), &task);
351 xbt_dynar_push(sd_global->initial_task_set,&task);
354 idx = xbt_dynar_search_or_negative(sd_global->initial_task_set, &task);
356 xbt_dynar_remove_at(sd_global->initial_task_set, idx, &task);
357 xbt_dynar_push(sd_global->executable_task_set,&task);
361 if (SD_task_get_state(task) == SD_RUNNABLE){
362 xbt_dynar_remove_at(sd_global->executable_task_set,
363 xbt_dynar_search(sd_global->executable_task_set, &task), &task);
365 if (SD_task_get_state(task) == SD_IN_FIFO){
366 xbt_dynar_remove_at(sd_global->initial_task_set,
367 xbt_dynar_search(sd_global->initial_task_set, &task), &task);
372 xbt_dynar_push(sd_global->completed_task_set,&task);
373 task->finish_time = task->surf_action->getFinishTime();
376 jedule_log_sd_event(task);
380 xbt_dynar_push(sd_global->completed_task_set,&task);
383 xbt_die( "Invalid state");
386 task->state = new_state;
388 if (task->watch_points & new_state) {
389 XBT_VERB("Watch point reached with task '%s'!", SD_task_get_name(task));
390 sd_global->watch_point_reached = 1;
391 SD_task_unwatch(task, new_state); /* remove the watch point */
396 * \brief Returns the name of a task
399 * \return the name of this task (can be \c NULL)
401 const char *SD_task_get_name(SD_task_t task)
406 /** @brief Allows to change the name of a task */
407 void SD_task_set_name(SD_task_t task, const char *name)
409 xbt_free(task->name);
410 task->name = xbt_strdup(name);
413 /** @brief Returns the dynar of the parents of a task
416 * \return a newly allocated dynar comprising the parents of this task
419 xbt_dynar_t SD_task_get_parents(SD_task_t task)
425 parents = xbt_dynar_new(sizeof(SD_task_t), NULL);
426 xbt_dynar_foreach(task->tasks_before, i, dep) {
427 xbt_dynar_push(parents, &(dep->src));
432 /** @brief Returns the dynar of the parents of a task
435 * \return a newly allocated dynar comprising the parents of this task
437 xbt_dynar_t SD_task_get_children(SD_task_t task)
440 xbt_dynar_t children;
443 children = xbt_dynar_new(sizeof(SD_task_t), NULL);
444 xbt_dynar_foreach(task->tasks_after, i, dep) {
445 xbt_dynar_push(children, &(dep->dst));
451 * \brief Returns the amount of workstations involved in a task
453 * Only call this on already scheduled tasks!
456 int SD_task_get_workstation_count(SD_task_t task)
458 return task->workstation_nb;
462 * \brief Returns the list of workstations involved in a task
464 * Only call this on already scheduled tasks!
467 SD_workstation_t *SD_task_get_workstation_list(SD_task_t task)
469 return task->workstation_list;
473 * \brief Returns the total amount of work contained in a task
476 * \return the total amount of work (computation or data transfer) for this task
477 * \see SD_task_get_remaining_amount()
479 double SD_task_get_amount(SD_task_t task)
485 * \brief Sets the total amount of work of a task
486 * For sequential typed tasks (COMP_SEQ and COMM_E2E), it also sets the
487 * appropriate values in the flops_amount and bytes_amount arrays
488 * respectively. Nothing more than modifying task->amount is done for paralle
489 * typed tasks (COMP_PAR_AMDAHL and COMM_PAR_MXN_1D_BLOCK) as the distribution
490 * of the amount of work is done at scheduling time.
493 * \param amount the new amount of work to execute
495 void SD_task_set_amount(SD_task_t task, double amount)
497 task->amount = amount;
498 if (task->kind == SD_TASK_COMP_SEQ)
499 task->flops_amount[0] = amount;
500 if (task->kind == SD_TASK_COMM_E2E)
501 task->bytes_amount[2] = amount;
505 * \brief Returns the alpha parameter of a SD_TASK_COMP_PAR_AMDAHL task
507 * \param task a parallel task assuming Amdahl's law as speedup model
508 * \return the alpha parameter (serial part of a task in percent) for this task
510 double SD_task_get_alpha(SD_task_t task)
512 xbt_assert(SD_task_get_kind(task) == SD_TASK_COMP_PAR_AMDAHL,
513 "Alpha parameter is not defined for this kink of task");
519 * \brief Returns the remaining amount work to do till the completion of a task
522 * \return the remaining amount of work (computation or data transfer) of this task
523 * \see SD_task_get_amount()
525 double SD_task_get_remaining_amount(SD_task_t task)
527 if (task->surf_action)
528 return surf_action_get_remains(task->surf_action);
530 return task->remains;
533 int SD_task_get_kind(SD_task_t task)
538 /** @brief Displays debugging informations about a task */
539 void SD_task_dump(SD_task_t task)
541 unsigned int counter;
542 SD_dependency_t dependency;
545 XBT_INFO("Displaying task %s", SD_task_get_name(task));
546 statename = bprintf("%s %s %s %s %s %s %s %s",
547 (task->state == SD_NOT_SCHEDULED ? "not scheduled" :
549 (task->state == SD_SCHEDULABLE ? "schedulable" : ""),
550 (task->state == SD_SCHEDULED ? "scheduled" : ""),
551 (task->state == SD_RUNNABLE ? "runnable" :
553 (task->state == SD_IN_FIFO ? "in fifo" : ""),
554 (task->state == SD_RUNNING ? "running" : ""),
555 (task->state == SD_DONE ? "done" : ""),
556 (task->state == SD_FAILED ? "failed" : ""));
557 XBT_INFO(" - state: %s", statename);
560 if (task->kind != 0) {
561 switch (task->kind) {
562 case SD_TASK_COMM_E2E:
563 XBT_INFO(" - kind: end-to-end communication");
565 case SD_TASK_COMP_SEQ:
566 XBT_INFO(" - kind: sequential computation");
568 case SD_TASK_COMP_PAR_AMDAHL:
569 XBT_INFO(" - kind: parallel computation following Amdahl's law");
571 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
572 XBT_INFO(" - kind: MxN data redistribution assuming 1D block distribution");
575 XBT_INFO(" - (unknown kind %d)", task->kind);
580 XBT_INFO(" - tracing category: %s", task->category);
582 XBT_INFO(" - amount: %.0f", SD_task_get_amount(task));
583 if (task->kind == SD_TASK_COMP_PAR_AMDAHL)
584 XBT_INFO(" - alpha: %.2f", task->alpha);
585 XBT_INFO(" - Dependencies to satisfy: %d", task->unsatisfied_dependencies);
586 if (!xbt_dynar_is_empty(task->tasks_before)) {
587 XBT_INFO(" - pre-dependencies:");
588 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
589 XBT_INFO(" %s", SD_task_get_name(dependency->src));
592 if (!xbt_dynar_is_empty(task->tasks_after)) {
593 XBT_INFO(" - post-dependencies:");
594 xbt_dynar_foreach(task->tasks_after, counter, dependency) {
595 XBT_INFO(" %s", SD_task_get_name(dependency->dst));
600 /** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */
601 void SD_task_dotty(SD_task_t task, void *out)
603 unsigned int counter;
604 SD_dependency_t dependency;
605 FILE *fout = (FILE*)out;
606 fprintf(fout, " T%p [label=\"%.20s\"", task, task->name);
607 switch (task->kind) {
608 case SD_TASK_COMM_E2E:
609 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
610 fprintf(fout, ", shape=box");
612 case SD_TASK_COMP_SEQ:
613 case SD_TASK_COMP_PAR_AMDAHL:
614 fprintf(fout, ", shape=circle");
617 xbt_die("Unknown task type!");
619 fprintf(fout, "];\n");
620 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
621 fprintf(fout, " T%p -> T%p;\n", dependency->src, dependency->dst);
625 /* Destroys a dependency between two tasks.
627 static void __SD_task_dependency_destroy(void *dependency)
629 xbt_free(((SD_dependency_t)dependency)->name);
630 xbt_free(dependency);
634 * \brief Adds a dependency between two tasks
636 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
637 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_RUNNABLE.
639 * \param name the name of the new dependency (can be \c NULL)
640 * \param data the user data you want to associate with this dependency (can be \c NULL)
641 * \param src the task which must be executed first
642 * \param dst the task you want to make depend on \a src
643 * \see SD_task_dependency_remove()
645 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
649 unsigned long length;
652 SD_dependency_t dependency;
653 e_SD_task_state_t state;
655 dynar = src->tasks_after;
656 length = xbt_dynar_length(dynar);
660 "Cannot add a dependency between task '%s' and itself",
661 SD_task_get_name(src));
663 state = SD_task_get_state(src);
664 if (state != SD_NOT_SCHEDULED && state != SD_SCHEDULABLE &&
665 state != SD_RUNNING && !__SD_task_is_scheduled_or_runnable(src))
667 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED,"
668 " SD_RUNNABLE or SD_RUNNING", SD_task_get_name(src));
670 state = SD_task_get_state(dst);
671 if (state != SD_NOT_SCHEDULED && state != SD_SCHEDULABLE &&
672 !__SD_task_is_scheduled_or_runnable(dst))
674 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED,"
675 "or SD_RUNNABLE", SD_task_get_name(dst));
677 XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s",
678 SD_task_get_name(src), SD_task_get_name(dst));
679 for (i = 0; i < length && !found; i++) {
680 xbt_dynar_get_cpy(dynar, i, &dependency);
681 found = (dependency->dst == dst);
682 XBT_DEBUG("Dependency %lu: dependency->dst = %s", i,
683 SD_task_get_name(dependency->dst));
688 "A dependency already exists between task '%s' and task '%s'",
689 SD_task_get_name(src), SD_task_get_name(dst));
691 dependency = xbt_new(s_SD_dependency_t, 1);
693 dependency->name = xbt_strdup(name); /* xbt_strdup is cleaver enough to deal with NULL args itself */
694 dependency->data = data;
695 dependency->src = src;
696 dependency->dst = dst;
698 /* src must be executed before dst */
699 xbt_dynar_push(src->tasks_after, &dependency);
700 xbt_dynar_push(dst->tasks_before, &dependency);
702 dst->unsatisfied_dependencies++;
705 /* if the task was runnable, then dst->tasks_before is not empty anymore,
706 so we must go back to state SD_SCHEDULED */
707 if (SD_task_get_state(dst) == SD_RUNNABLE) {
709 ("SD_task_dependency_add: %s was runnable and becomes scheduled!",
710 SD_task_get_name(dst));
711 SD_task_set_state(dst, SD_SCHEDULED);
715 * \brief Returns the name given as input when dependency has been created..
718 * \param dst a task depending on \a src
721 const char *SD_task_dependency_get_name(SD_task_t src, SD_task_t dst){
723 SD_dependency_t dependency;
725 xbt_dynar_foreach(src->tasks_after, i, dependency){
726 if (dependency->dst == dst)
727 return dependency->name;
733 * \brief Indicates whether there is a dependency between two tasks.
736 * \param dst a task depending on \a src
738 * If src is NULL, checks whether dst has any pre-dependency.
739 * If dst is NULL, checks whether src has any post-dependency.
741 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
743 unsigned int counter;
744 SD_dependency_t dependency;
746 xbt_assert(src != NULL
748 "Invalid parameter: both src and dst are NULL");
752 xbt_dynar_foreach(src->tasks_after, counter, dependency) {
753 if (dependency->dst == dst)
757 return xbt_dynar_length(src->tasks_after);
760 return xbt_dynar_length(dst->tasks_before);
766 * \brief Remove a dependency between two tasks
769 * \param dst a task depending on \a src
770 * \see SD_task_dependency_add()
772 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
776 unsigned long length;
779 SD_dependency_t dependency;
781 /* remove the dependency from src->tasks_after */
782 dynar = src->tasks_after;
783 length = xbt_dynar_length(dynar);
785 for (i = 0; i < length && !found; i++) {
786 xbt_dynar_get_cpy(dynar, i, &dependency);
787 if (dependency->dst == dst) {
788 xbt_dynar_remove_at(dynar, i, NULL);
794 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
795 SD_task_get_name(src), SD_task_get_name(dst),
796 SD_task_get_name(dst), SD_task_get_name(src));
798 /* remove the dependency from dst->tasks_before */
799 dynar = dst->tasks_before;
800 length = xbt_dynar_length(dynar);
803 for (i = 0; i < length && !found; i++) {
804 xbt_dynar_get_cpy(dynar, i, &dependency);
805 if (dependency->src == src) {
806 xbt_dynar_remove_at(dynar, i, NULL);
807 __SD_task_dependency_destroy(dependency);
808 dst->unsatisfied_dependencies--;
813 /* should never happen... */
815 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
816 SD_task_get_name(dst), SD_task_get_name(src),
817 SD_task_get_name(src), SD_task_get_name(dst));
819 /* if the task was scheduled and dst->tasks_before is empty now, we can make it runnable */
821 if (dst->unsatisfied_dependencies == 0) {
822 if (SD_task_get_state(dst) == SD_SCHEDULED)
823 SD_task_set_state(dst, SD_RUNNABLE);
825 SD_task_set_state(dst, SD_SCHEDULABLE);
828 if (dst->is_not_ready == 0)
829 SD_task_set_state(dst, SD_SCHEDULABLE);
831 /* __SD_print_dependencies(src);
832 __SD_print_dependencies(dst); */
836 * \brief Returns the user data associated with a dependency between two tasks
839 * \param dst a task depending on \a src
840 * \return the user data associated with this dependency (can be \c NULL)
841 * \see SD_task_dependency_add()
843 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
847 unsigned long length;
850 SD_dependency_t dependency;
852 dynar = src->tasks_after;
853 length = xbt_dynar_length(dynar);
855 for (i = 0; i < length && !found; i++) {
856 xbt_dynar_get_cpy(dynar, i, &dependency);
857 found = (dependency->dst == dst);
860 THROWF(arg_error, 0, "No dependency found between task '%s' and '%s'",
861 SD_task_get_name(src), SD_task_get_name(dst));
862 return dependency->data;
866 * \brief Adds a watch point to a task
868 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
869 * task becomes the one given in argument. The
870 * watch point is then automatically removed.
873 * \param state the \ref e_SD_task_state_t "state" you want to watch
874 * (cannot be #SD_NOT_SCHEDULED)
875 * \see SD_task_unwatch()
877 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
879 if (state & SD_NOT_SCHEDULED)
881 "Cannot add a watch point for state SD_NOT_SCHEDULED");
883 task->watch_points = task->watch_points | state;
887 * \brief Removes a watch point from a task
890 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
891 * \see SD_task_watch()
893 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
895 xbt_assert(state != SD_NOT_SCHEDULED,
896 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
898 task->watch_points = task->watch_points & ~state;
902 * \brief Returns an approximative estimation of the execution time of a task.
904 * The estimation is very approximative because the value returned is the time
905 * the task would take if it was executed now and if it was the only task.
907 * \param task the task to evaluate
908 * \param workstation_nb number of workstations on which the task would be executed
909 * \param workstation_list the workstations on which the task would be executed
910 * \param flops_amount computation amount for each workstation
911 * \param bytes_amount communication amount between each pair of workstations
914 double SD_task_get_execution_time(SD_task_t task,
916 const SD_workstation_t *
918 const double *flops_amount,
919 const double *bytes_amount)
921 double time, max_time = 0.0;
923 xbt_assert(workstation_nb > 0, "Invalid parameter");
925 /* the task execution time is the maximum execution time of the parallel tasks */
927 for (i = 0; i < workstation_nb; i++) {
929 if (flops_amount != NULL)
931 SD_workstation_get_computation_time(workstation_list[i],
934 if (bytes_amount != NULL)
935 for (j = 0; j < workstation_nb; j++) {
937 SD_route_get_communication_time(workstation_list[i],
944 if (time > max_time) {
951 static XBT_INLINE void SD_task_do_schedule(SD_task_t task)
953 if (SD_task_get_state(task) > SD_SCHEDULABLE)
954 THROWF(arg_error, 0, "Task '%s' has already been scheduled",
955 SD_task_get_name(task));
957 /* update the task state */
958 if (task->unsatisfied_dependencies == 0)
959 SD_task_set_state(task, SD_RUNNABLE);
961 SD_task_set_state(task, SD_SCHEDULED);
965 * \brief Schedules a task
967 * The task state must be #SD_NOT_SCHEDULED.
968 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
969 * i.e. when its dependencies are satisfied.
971 * \param task the task you want to schedule
972 * \param workstation_count number of workstations on which the task will be executed
973 * \param workstation_list the workstations on which the task will be executed
974 * \param flops_amount computation amount for each workstation
975 * \param bytes_amount communication amount between each pair of workstations
976 * \param rate task execution speed rate
977 * \see SD_task_unschedule()
979 void SD_task_schedule(SD_task_t task, int workstation_count,
980 const SD_workstation_t * workstation_list,
981 const double *flops_amount,
982 const double *bytes_amount, double rate)
984 xbt_assert(workstation_count > 0, "workstation_nb must be positive");
986 task->workstation_nb = workstation_count;
990 task->flops_amount = (double*)xbt_realloc(task->flops_amount,
991 sizeof(double) * workstation_count);
992 memcpy(task->flops_amount, flops_amount,
993 sizeof(double) * workstation_count);
995 xbt_free(task->flops_amount);
996 task->flops_amount = NULL;
999 int communication_nb = workstation_count * workstation_count;
1001 task->bytes_amount = (double*)xbt_realloc(task->bytes_amount,
1002 sizeof(double) * communication_nb);
1003 memcpy(task->bytes_amount, bytes_amount,
1004 sizeof(double) * communication_nb);
1006 xbt_free(task->bytes_amount);
1007 task->bytes_amount = NULL;
1010 task->workstation_list = (SD_workstation_t*)
1011 xbt_realloc(task->workstation_list,
1012 sizeof(SD_workstation_t) * workstation_count);
1013 memcpy(task->workstation_list, workstation_list,
1014 sizeof(SD_workstation_t) * workstation_count);
1016 SD_task_do_schedule(task);
1020 * \brief Unschedules a task
1022 * The task state must be #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING or #SD_FAILED.
1023 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
1024 * Call SD_task_schedule() to schedule it again.
1026 * \param task the task you want to unschedule
1027 * \see SD_task_schedule()
1029 void SD_task_unschedule(SD_task_t task)
1031 if (task->state != SD_SCHEDULED &&
1032 task->state != SD_RUNNABLE &&
1033 task->state != SD_RUNNING &&
1034 task->state != SD_FAILED)
1035 THROWF(arg_error, 0,
1036 "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED",
1037 SD_task_get_name(task));
1039 if (__SD_task_is_scheduled_or_runnable(task) /* if the task is scheduled or runnable */
1040 && ((task->kind == SD_TASK_COMP_PAR_AMDAHL) ||
1041 (task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK))) { /* Don't free scheduling data for typed tasks */
1042 __SD_task_destroy_scheduling_data(task);
1043 xbt_free(task->workstation_list);
1044 task->workstation_list=NULL;
1045 task->workstation_nb = 0;
1048 if (SD_task_get_state(task) == SD_RUNNING)
1049 /* the task should become SD_FAILED */
1050 task->surf_action->cancel();
1052 if (task->unsatisfied_dependencies == 0)
1053 SD_task_set_state(task, SD_SCHEDULABLE);
1055 SD_task_set_state(task, SD_NOT_SCHEDULED);
1057 task->remains = task->amount;
1058 task->start_time = -1.0;
1061 /* Destroys the data memorized by SD_task_schedule.
1062 * Task state must be SD_SCHEDULED or SD_RUNNABLE.
1064 static void __SD_task_destroy_scheduling_data(SD_task_t task)
1066 if (!__SD_task_is_scheduled_or_runnable(task)
1067 && SD_task_get_state(task) != SD_IN_FIFO)
1068 THROWF(arg_error, 0,
1069 "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
1070 SD_task_get_name(task));
1072 xbt_free(task->flops_amount);
1073 xbt_free(task->bytes_amount);
1074 task->flops_amount = task->bytes_amount = NULL;
1077 /* Runs a task. This function is directly called by __SD_task_try_to_run if
1078 * the task doesn't have to wait in FIFOs. Otherwise, it is called by
1079 * __SD_task_just_done when the task gets out of its FIFOs.
1081 void __SD_task_really_run(SD_task_t task)
1087 xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
1088 "Task '%s' is not runnable or in a fifo! Task state: %d",
1089 SD_task_get_name(task), (int)SD_task_get_state(task));
1090 xbt_assert(task->workstation_list != NULL,
1091 "Task '%s': workstation_list is NULL!",
1092 SD_task_get_name(task));
1094 XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
1095 int host_nb = task->workstation_nb;
1097 /* set this task as current task for the workstations in sequential mode */
1098 for (i = 0; i < host_nb; i++) {
1099 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
1100 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1101 sg_host_sd(task->workstation_list[i])->current_task = task;
1102 xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
1103 "The workstation should be busy now");
1107 XBT_DEBUG("Task '%s' set as current task for its workstations",
1108 SD_task_get_name(task));
1110 /* start the task */
1112 /* Copy the elements of the task into the action */
1113 hosts = xbt_new(sg_host_t, host_nb);
1115 for (i = 0; i < host_nb; i++)
1116 hosts[i] = task->workstation_list[i];
1118 double *flops_amount = xbt_new0(double, host_nb);
1119 double *bytes_amount = xbt_new0(double, host_nb * host_nb);
1122 if(task->flops_amount)
1123 memcpy(flops_amount, task->flops_amount, sizeof(double) *
1125 if(task->bytes_amount)
1126 memcpy(bytes_amount, task->bytes_amount,
1127 sizeof(double) * host_nb * host_nb);
1129 task->surf_action = surf_host_model->executeParallelTask(
1130 host_nb, hosts, flops_amount, bytes_amount, task->rate);
1132 task->surf_action->setData(task);
1134 XBT_DEBUG("surf_action = %p", task->surf_action);
1137 TRACE_surf_action(task->surf_action, task->category);
1139 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
1140 SD_task_set_state(task, SD_RUNNING);
1141 xbt_assert(SD_task_get_state(task) == SD_RUNNING,
1142 "Bad state of task '%s': %d",
1143 SD_task_get_name(task), (int)SD_task_get_state(task));
1147 /* Tries to run a task. This function is called by SD_simulate() when a
1148 * scheduled task becomes SD_RUNNABLE (i.e., when its dependencies are
1150 * If one of the workstations where the task is scheduled on is busy (in
1151 * sequential mode), the task doesn't start.
1152 * Returns whether the task has started.
1154 int __SD_task_try_to_run(SD_task_t task)
1159 SD_workstation_t workstation;
1161 xbt_assert(SD_task_get_state(task) == SD_RUNNABLE,
1162 "Task '%s' is not runnable! Task state: %d",
1163 SD_task_get_name(task), (int)SD_task_get_state(task));
1166 for (i = 0; i < task->workstation_nb; i++) {
1167 can_start = can_start &&
1168 !__SD_workstation_is_busy(task->workstation_list[i]);
1171 XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
1173 if (!can_start) { /* if the task cannot start and is not in the FIFOs yet */
1174 for (i = 0; i < task->workstation_nb; i++) {
1175 workstation = task->workstation_list[i];
1176 if (sg_host_sd(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1177 XBT_DEBUG("Pushing task '%s' in the FIFO of workstation '%s'",
1178 SD_task_get_name(task),
1179 SD_workstation_get_name(workstation));
1180 xbt_fifo_push(sg_host_sd(workstation)->task_fifo, task);
1183 SD_task_set_state(task, SD_IN_FIFO);
1184 XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
1186 __SD_task_really_run(task);
1192 /* This function is called by SD_simulate when a task is done.
1193 * It updates task->state and task->action and executes if necessary the tasks
1194 * which were waiting in FIFOs for the end of `task'
1196 void __SD_task_just_done(SD_task_t task)
1199 SD_workstation_t workstation;
1201 SD_task_t candidate;
1202 int candidate_nb = 0;
1203 int candidate_capacity = 8;
1204 SD_task_t *candidates;
1207 xbt_assert(SD_task_get_state(task)== SD_RUNNING,
1208 "The task must be running! Task state: %d",
1209 (int)SD_task_get_state(task));
1210 xbt_assert(task->workstation_list != NULL,
1211 "Task '%s': workstation_list is NULL!",
1212 SD_task_get_name(task));
1215 candidates = xbt_new(SD_task_t, 8);
1217 SD_task_set_state(task, SD_DONE);
1218 task->surf_action->unref();
1219 task->surf_action = NULL;
1221 XBT_DEBUG("Looking for candidates");
1223 /* if the task was executed on sequential workstations,
1224 maybe we can execute the next task of the FIFO for each workstation */
1225 for (i = 0; i < task->workstation_nb; i++) {
1226 workstation = task->workstation_list[i];
1227 XBT_DEBUG("Workstation '%s': access_mode = %d",
1228 SD_workstation_get_name(workstation),
1229 (int)sg_host_sd(workstation)->access_mode);
1230 if (sg_host_sd(workstation)->access_mode ==
1231 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1232 xbt_assert(sg_host_sd(workstation)->task_fifo != NULL,
1233 "Workstation '%s' has sequential access but no FIFO!",
1234 SD_workstation_get_name(workstation));
1235 xbt_assert(sg_host_sd(workstation)->current_task =
1236 task, "Workstation '%s': current task should be '%s'",
1237 SD_workstation_get_name(workstation),
1238 SD_task_get_name(task));
1240 /* the task is over so we can release the workstation */
1241 sg_host_sd(workstation)->current_task = NULL;
1243 XBT_DEBUG("Getting candidate in FIFO");
1244 candidate = (SD_task_t)
1245 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1246 (sg_host_sd(workstation)->task_fifo));
1248 if (candidate != NULL) {
1249 XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
1250 xbt_assert(SD_task_get_state(candidate) == SD_IN_FIFO,
1251 "Bad state of candidate '%s': %d",
1252 SD_task_get_name(candidate),
1253 (int)SD_task_get_state(candidate));
1256 XBT_DEBUG("Candidate in fifo: %p", candidate);
1258 /* if there was a task waiting for my place */
1259 if (candidate != NULL) {
1260 /* Unfortunately, we are not sure yet that we can execute the task now,
1261 because the task can be waiting more deeply in some other
1262 workstation's FIFOs ...
1263 So we memorize all candidate tasks, and then we will check for each
1264 candidate whether or not all its workstations are available. */
1266 /* realloc if necessary */
1267 if (candidate_nb == candidate_capacity) {
1268 candidate_capacity *= 2;
1269 candidates = (SD_task_t*)
1270 xbt_realloc(candidates,
1271 sizeof(SD_task_t) * candidate_capacity);
1274 /* register the candidate */
1275 candidates[candidate_nb++] = candidate;
1276 candidate->fifo_checked = 0;
1281 XBT_DEBUG("Candidates found: %d", candidate_nb);
1283 /* now we check every candidate task */
1284 for (i = 0; i < candidate_nb; i++) {
1285 candidate = candidates[i];
1287 if (candidate->fifo_checked) {
1288 continue; /* we have already evaluated that task */
1291 xbt_assert(SD_task_get_state(candidate) == SD_IN_FIFO,
1292 "Bad state of candidate '%s': %d",
1293 SD_task_get_name(candidate), (int)SD_task_get_state(candidate));
1295 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1296 workstation = candidate->workstation_list[j];
1298 /* I can start on this workstation if the workstation is shared
1299 or if I am the first task in the FIFO */
1300 can_start = sg_host_sd(workstation)->access_mode == SD_WORKSTATION_SHARED_ACCESS
1302 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1303 (sg_host_sd(workstation)->task_fifo));
1306 XBT_DEBUG("Candidate '%s' can start: %d", SD_task_get_name(candidate),
1309 /* now we are sure that I can start! */
1311 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1312 workstation = candidate->workstation_list[j];
1314 /* update the FIFO */
1315 if (sg_host_sd(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1316 candidate = (SD_task_t)xbt_fifo_shift(sg_host_sd(workstation)->task_fifo); /* the return value is stored just for debugging */
1317 XBT_DEBUG("Head of the FIFO: '%s' on workstation %s (%d task left)",
1319 NULL) ? SD_task_get_name(candidate) : "NULL",
1320 SD_workstation_get_name(workstation),
1321 xbt_fifo_size(sg_host_sd(workstation)->task_fifo));
1322 xbt_assert(candidate == candidates[i],
1323 "Error in __SD_task_just_done: bad first task in the FIFO");
1326 } /* for each workstation */
1328 /* finally execute the task */
1329 XBT_DEBUG("Task '%s' state: %d", SD_task_get_name(candidate),
1330 (int)SD_task_get_state(candidate));
1331 __SD_task_really_run(candidate);
1334 ("Calling __SD_task_is_running: task '%s', state set: %d",
1335 SD_task_get_name(candidate), candidate->state);
1336 xbt_assert(SD_task_get_state(candidate) == SD_RUNNING,
1337 "Bad state of task '%s': %d",
1338 SD_task_get_name(candidate),
1339 (int)SD_task_get_state(candidate));
1340 XBT_DEBUG("Okay, the task is running.");
1343 candidate->fifo_checked = 1;
1344 } /* for each candidate */
1346 xbt_free(candidates);
1350 * Remove all dependencies associated with a task. This function is called
1351 * when the task is destroyed.
1353 static void __SD_task_remove_dependencies(SD_task_t task)
1355 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
1356 because each one is stored twice */
1357 SD_dependency_t dependency;
1358 while (!xbt_dynar_is_empty(task->tasks_before)) {
1359 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
1360 SD_task_dependency_remove(dependency->src, dependency->dst);
1363 while (!xbt_dynar_is_empty(task->tasks_after)) {
1364 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
1365 SD_task_dependency_remove(dependency->src, dependency->dst);
1370 * \brief Returns the start time of a task
1372 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1374 * \param task: a task
1375 * \return the start time of this task
1377 double SD_task_get_start_time(SD_task_t task)
1379 if (task->surf_action)
1380 return task->surf_action->getStartTime();
1382 return task->start_time;
1386 * \brief Returns the finish time of a task
1388 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1389 * If the state is not completed yet, the returned value is an
1390 * estimation of the task finish time. This value can fluctuate
1391 * until the task is completed.
1393 * \param task: a task
1394 * \return the start time of this task
1396 double SD_task_get_finish_time(SD_task_t task)
1398 if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
1399 return task->surf_action->getFinishTime();
1401 return task->finish_time;
1406 void SD_task_distribute_comp_amdahl(SD_task_t task, int ws_count)
1409 xbt_assert(task->kind == SD_TASK_COMP_PAR_AMDAHL,
1410 "Task %s is not a SD_TASK_COMP_PAR_AMDAHL typed task."
1411 "Cannot use this function.",
1412 SD_task_get_name(task));
1413 task->flops_amount = xbt_new0(double, ws_count);
1414 task->bytes_amount = xbt_new0(double, ws_count * ws_count);
1415 xbt_free(task->workstation_list);
1416 task->workstation_nb = ws_count;
1417 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
1419 for(i=0;i<ws_count;i++){
1420 task->flops_amount[i] =
1421 (task->alpha + (1 - task->alpha)/ws_count) * task->amount;
1426 /** @brief Auto-schedules a task.
1428 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1429 * allows to specify the task costs at creation, and decouple them from the
1430 * scheduling process where you just specify which resource should deliver the
1433 * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e()
1434 * or SD_task_create_comp_seq(). Check their definitions for the exact semantic
1438 * We should create tasks kind for the following categories:
1439 * - Point to point communication (done)
1440 * - Sequential computation (done)
1441 * - group communication (redistribution, several kinds)
1442 * - parallel tasks with no internal communication (one kind per speedup
1443 * model such as Amdahl)
1444 * - idem+ internal communication. Task type not enough since we cannot store
1445 * comm cost alongside to comp one)
1447 void SD_task_schedulev(SD_task_t task, int count,
1448 const SD_workstation_t * list)
1451 SD_dependency_t dep;
1453 xbt_assert(task->kind != 0,
1454 "Task %s is not typed. Cannot automatically schedule it.",
1455 SD_task_get_name(task));
1456 switch (task->kind) {
1457 case SD_TASK_COMP_PAR_AMDAHL:
1458 SD_task_distribute_comp_amdahl(task, count);
1459 case SD_TASK_COMM_E2E:
1460 case SD_TASK_COMP_SEQ:
1461 xbt_assert(task->workstation_nb == count,
1462 "Got %d locations, but were expecting %d locations",
1463 count,task->workstation_nb);
1464 for (i = 0; i < count; i++)
1465 task->workstation_list[i] = list[i];
1466 if (SD_task_get_kind(task)== SD_TASK_COMP_SEQ && !task->flops_amount){
1467 /*This task has failed and is rescheduled. Reset the flops_amount*/
1468 task->flops_amount = xbt_new0(double, 1);
1469 task->flops_amount[0] = task->remains;
1471 SD_task_do_schedule(task);
1474 xbt_die("Kind of task %s not supported by SD_task_schedulev()",
1475 SD_task_get_name(task));
1477 if (task->kind == SD_TASK_COMM_E2E) {
1478 XBT_VERB("Schedule comm task %s between %s -> %s. It costs %.f bytes",
1479 SD_task_get_name(task),
1480 SD_workstation_get_name(task->workstation_list[0]),
1481 SD_workstation_get_name(task->workstation_list[1]),
1482 task->bytes_amount[2]);
1486 /* Iterate over all children and parents being COMM_E2E to say where I am
1487 * located (and start them if runnable) */
1488 if (task->kind == SD_TASK_COMP_SEQ) {
1489 XBT_VERB("Schedule computation task %s on %s. It costs %.f flops",
1490 SD_task_get_name(task),
1491 SD_workstation_get_name(task->workstation_list[0]),
1492 task->flops_amount[0]);
1494 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1495 SD_task_t before = dep->src;
1496 if (before->kind == SD_TASK_COMM_E2E) {
1497 before->workstation_list[1] = task->workstation_list[0];
1499 if (before->workstation_list[0] &&
1500 (SD_task_get_state(before)< SD_SCHEDULED)) {
1501 SD_task_do_schedule(before);
1503 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1504 SD_task_get_name(before),
1505 SD_workstation_get_name(before->workstation_list[0]),
1506 SD_workstation_get_name(before->workstation_list[1]),
1507 before->bytes_amount[2]);
1511 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1512 SD_task_t after = dep->dst;
1513 if (after->kind == SD_TASK_COMM_E2E) {
1514 after->workstation_list[0] = task->workstation_list[0];
1515 if (after->workstation_list[1]
1516 && (SD_task_get_state(after)< SD_SCHEDULED)) {
1517 SD_task_do_schedule(after);
1519 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1520 SD_task_get_name(after),
1521 SD_workstation_get_name(after->workstation_list[0]),
1522 SD_workstation_get_name(after->workstation_list[1]),
1523 after->bytes_amount[2]);
1529 /* Iterate over all children and parents being MXN_1D_BLOCK to say where I am
1530 * located (and start them if runnable) */
1531 if (task->kind == SD_TASK_COMP_PAR_AMDAHL) {
1532 XBT_VERB("Schedule computation task %s on %d workstations. %.f flops"
1533 " will be distributed following Amdahl's Law",
1534 SD_task_get_name(task), task->workstation_nb,
1535 task->flops_amount[0]);
1536 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1537 SD_task_t before = dep->src;
1538 if (before->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1539 if (!before->workstation_list){
1540 XBT_VERB("Sender side of Task %s is not scheduled yet",
1541 SD_task_get_name(before));
1542 before->workstation_list = xbt_new0(SD_workstation_t, count);
1543 before->workstation_nb = count;
1544 XBT_VERB("Fill the workstation list with list of Task '%s'",
1545 SD_task_get_name(task));
1546 for (i=0;i<count;i++)
1547 before->workstation_list[i] = task->workstation_list[i];
1549 XBT_VERB("Build communication matrix for task '%s'",
1550 SD_task_get_name(before));
1552 double src_start, src_end, dst_start, dst_end;
1553 src_nb = before->workstation_nb;
1555 before->workstation_list = (SD_workstation_t*) xbt_realloc(
1556 before->workstation_list,
1557 (before->workstation_nb+count)*sizeof(s_SD_workstation_t));
1558 for(i=0; i<count; i++)
1559 before->workstation_list[before->workstation_nb+i] =
1560 task->workstation_list[i];
1562 before->workstation_nb += count;
1563 xbt_free(before->flops_amount);
1564 xbt_free(before->bytes_amount);
1565 before->flops_amount = xbt_new0(double,
1566 before->workstation_nb);
1567 before->bytes_amount = xbt_new0(double,
1568 before->workstation_nb*
1569 before->workstation_nb);
1571 for(i=0;i<src_nb;i++){
1572 src_start = i*before->amount/src_nb;
1573 src_end = src_start + before->amount/src_nb;
1574 for(j=0; j<dst_nb; j++){
1575 dst_start = j*before->amount/dst_nb;
1576 dst_end = dst_start + before->amount/dst_nb;
1577 XBT_VERB("(%s->%s): (%.2f, %.2f)-> (%.2f, %.2f)",
1578 SD_workstation_get_name(before->workstation_list[i]),
1579 SD_workstation_get_name(before->workstation_list[src_nb+j]),
1580 src_start, src_end, dst_start, dst_end);
1581 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1582 before->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1584 before->bytes_amount[i*(src_nb+dst_nb)+src_nb+j] =
1585 MIN(src_end, dst_end) - MAX(src_start, dst_start);
1587 XBT_VERB("==> %.2f",
1588 before->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]);
1592 if (SD_task_get_state(before)< SD_SCHEDULED) {
1593 SD_task_do_schedule(before);
1595 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1596 SD_task_get_name(before),before->amount, src_nb, dst_nb);
1601 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1602 SD_task_t after = dep->dst;
1603 if (after->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1604 if (!after->workstation_list){
1605 XBT_VERB("Receiver side of Task '%s' is not scheduled yet",
1606 SD_task_get_name(after));
1607 after->workstation_list = xbt_new0(SD_workstation_t, count);
1608 after->workstation_nb = count;
1609 XBT_VERB("Fill the workstation list with list of Task '%s'",
1610 SD_task_get_name(task));
1611 for (i=0;i<count;i++)
1612 after->workstation_list[i] = task->workstation_list[i];
1615 double src_start, src_end, dst_start, dst_end;
1617 dst_nb = after->workstation_nb;
1618 after->workstation_list = (SD_workstation_t*) xbt_realloc(
1619 after->workstation_list,
1620 (after->workstation_nb+count)*sizeof(s_SD_workstation_t));
1621 for(i=after->workstation_nb - 1; i>=0; i--)
1622 after->workstation_list[count+i] = after->workstation_list[i];
1623 for(i=0; i<count; i++)
1624 after->workstation_list[i] = task->workstation_list[i];
1626 after->workstation_nb += count;
1628 xbt_free(after->flops_amount);
1629 xbt_free(after->bytes_amount);
1631 after->flops_amount = xbt_new0(double, after->workstation_nb);
1632 after->bytes_amount = xbt_new0(double,
1633 after->workstation_nb*
1634 after->workstation_nb);
1636 for(i=0;i<src_nb;i++){
1637 src_start = i*after->amount/src_nb;
1638 src_end = src_start + after->amount/src_nb;
1639 for(j=0; j<dst_nb; j++){
1640 dst_start = j*after->amount/dst_nb;
1641 dst_end = dst_start + after->amount/dst_nb;
1642 XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)",
1643 i, j, src_start, src_end, dst_start, dst_end);
1644 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1645 after->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1647 after->bytes_amount[i*(src_nb+dst_nb)+src_nb+j] =
1648 MIN(src_end, dst_end)- MAX(src_start, dst_start);
1650 XBT_VERB("==> %.2f",
1651 after->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]);
1655 if (SD_task_get_state(after)< SD_SCHEDULED) {
1656 SD_task_do_schedule(after);
1658 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1659 SD_task_get_name(after),after->amount, src_nb, dst_nb);
1667 /** @brief autoschedule a task on a list of workstations
1669 * This function is very similar to SD_task_schedulev(),
1670 * but takes the list of workstations to schedule onto as separate parameters.
1671 * It builds a proper vector of workstations and then call SD_task_schedulev()
1673 void SD_task_schedulel(SD_task_t task, int count, ...)
1676 SD_workstation_t *list = xbt_new(SD_workstation_t, count);
1678 va_start(ap, count);
1679 for (i = 0; i < count; i++) {
1680 list[i] = va_arg(ap, SD_workstation_t);
1683 SD_task_schedulev(task, count, list);