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);
41 task->start_time = -1.0;
42 task->finish_time = -1.0;
43 task->surf_action = NULL;
44 task->watch_points = 0;
47 xbt_dynar_reset(task->tasks_before);
48 xbt_dynar_reset(task->tasks_after);
49 task->unsatisfied_dependencies = 0;
50 task->is_not_ready = 0;
52 /* scheduling parameters */
53 task->workstation_nb = 0;
54 task->workstation_list = NULL;
55 task->flops_amount = NULL;
56 task->bytes_amount = NULL;
60 void SD_task_free_f(void *t)
62 SD_task_t task = (SD_task_t)t;
64 xbt_dynar_free(&task->tasks_before);
65 xbt_dynar_free(&task->tasks_after);
70 * \brief Creates a new task.
72 * \param name the name of the task (can be \c NULL)
73 * \param data the user data you want to associate with the task (can be \c NULL)
74 * \param amount amount of the task
75 * \return the new task
76 * \see SD_task_destroy()
78 SD_task_t SD_task_create(const char *name, void *data, double amount)
80 SD_task_t task = (SD_task_t)xbt_mallocator_get(sd_global->task_mallocator);
82 /* general information */
83 task->data = data; /* user data */
84 task->name = xbt_strdup(name);
85 task->amount = amount;
86 task->remains = amount;
88 sd_global->task_number++;
90 TRACE_sd_task_create(task);
95 static XBT_INLINE SD_task_t SD_task_create_sized(const char *name,
96 void *data, double amount,
99 SD_task_t task = SD_task_create(name, data, amount);
100 task->bytes_amount = xbt_new0(double, ws_count * ws_count);
101 task->flops_amount = xbt_new0(double, ws_count);
102 task->workstation_nb = ws_count;
103 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
107 /** @brief create a end-to-end communication task that can then be auto-scheduled
109 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
110 * allows to specify the task costs at creation, and decouple them from the
111 * scheduling process where you just specify which resource should deliver the
114 * A end-to-end communication must be scheduled on 2 hosts, and the amount
115 * specified at creation is sent from hosts[0] to hosts[1].
117 SD_task_t SD_task_create_comm_e2e(const char *name, void *data,
120 SD_task_t res = SD_task_create_sized(name, data, amount, 2);
121 res->bytes_amount[2] = amount;
122 res->kind = SD_TASK_COMM_E2E;
124 TRACE_category("COMM_E2E");
125 TRACE_sd_set_task_category(res, "COMM_E2E");
130 /** @brief create a sequential computation task that can then be auto-scheduled
132 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
133 * allows to specify the task costs at creation, and decouple them from the
134 * scheduling process where you just specify which resource should deliver the
137 * A sequential computation must be scheduled on 1 host, and the amount
138 * specified at creation to be run on hosts[0].
140 * \param name the name of the task (can be \c NULL)
141 * \param data the user data you want to associate with the task (can be \c NULL)
142 * \param flops_amount amount of compute work to be done by the task
143 * \return the new SD_TASK_COMP_SEQ typed task
145 SD_task_t SD_task_create_comp_seq(const char *name, void *data,
148 SD_task_t res = SD_task_create_sized(name, data, flops_amount, 1);
149 res->flops_amount[0] = flops_amount;
150 res->kind = SD_TASK_COMP_SEQ;
152 TRACE_category("COMP_SEQ");
153 TRACE_sd_set_task_category(res, "COMP_SEQ");
158 /** @brief create a parallel computation task that can then be auto-scheduled
160 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
161 * allows to specify the task costs at creation, and decouple them from the
162 * scheduling process where you just specify which resource should deliver the
165 * A parallel computation can be scheduled on any number of host.
166 * The underlying speedup model is Amdahl's law.
167 * To be auto-scheduled, \see SD_task_distribute_comp_amdahl has to be called
169 * \param name the name of the task (can be \c NULL)
170 * \param data the user data you want to associate with the task (can be \c NULL)
171 * \param flops_amount amount of compute work to be done by the task
172 * \param alpha purely serial fraction of the work to be done (in [0.;1.[)
173 * \return the new task
175 SD_task_t SD_task_create_comp_par_amdahl(const char *name, void *data,
176 double flops_amount, double alpha)
178 xbt_assert(alpha < 1. && alpha >= 0.,
179 "Invalid parameter: alpha must be in [0.;1.[");
181 SD_task_t res = SD_task_create(name, data, flops_amount);
183 res->kind = SD_TASK_COMP_PAR_AMDAHL;
185 TRACE_category("COMP_PAR_AMDAHL");
186 TRACE_sd_set_task_category(res, "COMP_PAR_AMDAHL");
191 /** @brief create a complex data redistribution task that can then be
194 * Auto-scheduling mean that the task can be used with SD_task_schedulev().
195 * This allows to specify the task costs at creation, and decouple them from
196 * the scheduling process where you just specify which resource should
199 * A data redistribution can be scheduled on any number of host.
200 * The assumed distribution is a 1D block distribution. Each host owns the same
201 * share of the \see amount.
202 * To be auto-scheduled, \see SD_task_distribute_comm_mxn_1d_block has to be
204 * \param name the name of the task (can be \c NULL)
205 * \param data the user data you want to associate with the task (can be
207 * \param amount amount of data to redistribute by the task
208 * \return the new task
210 SD_task_t SD_task_create_comm_par_mxn_1d_block(const char *name, void *data,
213 SD_task_t res = SD_task_create(name, data, amount);
214 res->workstation_list=NULL;
215 res->kind = SD_TASK_COMM_PAR_MXN_1D_BLOCK;
217 TRACE_category("COMM_PAR_MXN_1D_BLOCK");
218 TRACE_sd_set_task_category(res, "COMM_PAR_MXN_1D_BLOCK");
224 * \brief Destroys a task.
226 * The user data (if any) should have been destroyed first.
228 * \param task the task you want to destroy
229 * \see SD_task_create()
231 void SD_task_destroy(SD_task_t task)
234 XBT_DEBUG("Destroying task %s...", SD_task_get_name(task));
236 __SD_task_remove_dependencies(task);
237 /* if the task was scheduled or runnable we have to free the scheduling parameters */
238 if (__SD_task_is_scheduled_or_runnable(task))
239 __SD_task_destroy_scheduling_data(task);
241 idx = xbt_dynar_search_or_negative(sd_global->return_set, &task);
243 xbt_dynar_remove_at(sd_global->return_set, idx, NULL);
246 xbt_free(task->name);
248 if (task->surf_action != NULL)
249 task->surf_action->unref();
251 xbt_free(task->workstation_list);
252 xbt_free(task->bytes_amount);
253 xbt_free(task->flops_amount);
255 TRACE_sd_task_destroy(task);
257 xbt_mallocator_release(sd_global->task_mallocator,task);
258 sd_global->task_number--;
260 XBT_DEBUG("Task destroyed.");
264 * \brief Returns the user data of a task
267 * \return the user data associated with this task (can be \c NULL)
268 * \see SD_task_set_data()
270 void *SD_task_get_data(SD_task_t task)
276 * \brief Sets the user data of a task
278 * The new data can be \c NULL. The old data should have been freed first
279 * if it was not \c NULL.
282 * \param data the new data you want to associate with this task
283 * \see SD_task_get_data()
285 void SD_task_set_data(SD_task_t task, void *data)
291 * \brief Sets the rate of a task
293 * This will change the network bandwidth a task can use. This rate
294 * cannot be dynamically changed. Once the task has started, this call
295 * is ineffective. This rate depends on both the nominal bandwidth on
296 * the route onto which the task is scheduled (\see
297 * SD_task_get_current_bandwidth) and the amount of data to transfer.
299 * To divide the nominal bandwidth by 2, the rate then has to be :
300 * rate = bandwidth/(2*amount)
302 * \param task a \see SD_TASK_COMM_E2E task (end-to-end communication)
303 * \param rate the new rate you want to associate with this task.
305 void SD_task_set_rate(SD_task_t task, double rate)
307 xbt_assert(task->kind == SD_TASK_COMM_E2E,
308 "The rate can be modified for end-to-end communications only.");
309 if(task->start_time<0) {
312 XBT_WARN("Task %p has started. Changing rate is ineffective.", task);
317 * \brief Returns the state of a task
320 * \return the current \ref e_SD_task_state_t "state" of this task:
321 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING, #SD_DONE or #SD_FAILED
322 * \see e_SD_task_state_t
324 e_SD_task_state_t SD_task_get_state(SD_task_t task)
329 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
331 void SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
335 case SD_NOT_SCHEDULED:
337 if (SD_task_get_state(task) == SD_FAILED){
338 xbt_dynar_remove_at(sd_global->completed_task_set,
339 xbt_dynar_search(sd_global->completed_task_set, &task), NULL);
340 xbt_dynar_push(sd_global->initial_task_set,&task);
344 if (SD_task_get_state(task) == SD_RUNNABLE){
345 xbt_dynar_remove_at(sd_global->executable_task_set,
346 xbt_dynar_search(sd_global->executable_task_set, &task), NULL);
347 xbt_dynar_push(sd_global->initial_task_set,&task);
351 xbt_dynar_remove_at(sd_global->executable_task_set,
352 xbt_dynar_search(sd_global->executable_task_set, &task), NULL);
353 xbt_dynar_push(sd_global->initial_task_set,&task);
356 idx = xbt_dynar_search_or_negative(sd_global->initial_task_set, &task);
358 xbt_dynar_remove_at(sd_global->initial_task_set, idx, NULL);
359 xbt_dynar_push(sd_global->executable_task_set,&task);
363 if (SD_task_get_state(task) == SD_RUNNABLE){
364 xbt_dynar_remove_at(sd_global->executable_task_set,
365 xbt_dynar_search(sd_global->executable_task_set, &task), NULL);
367 if (SD_task_get_state(task) == SD_IN_FIFO){
368 xbt_dynar_remove_at(sd_global->initial_task_set,
369 xbt_dynar_search(sd_global->initial_task_set, &task), NULL);
374 xbt_dynar_push(sd_global->completed_task_set,&task);
375 task->finish_time = task->surf_action->getFinishTime();
378 jedule_log_sd_event(task);
382 xbt_dynar_push(sd_global->completed_task_set,&task);
385 xbt_die( "Invalid state");
388 task->state = new_state;
390 if (task->watch_points & new_state) {
391 XBT_VERB("Watch point reached with task '%s'!", SD_task_get_name(task));
392 sd_global->watch_point_reached = 1;
393 SD_task_unwatch(task, new_state); /* remove the watch point */
398 * \brief Returns the name of a task
401 * \return the name of this task (can be \c NULL)
403 const char *SD_task_get_name(SD_task_t task)
408 /** @brief Allows to change the name of a task */
409 void SD_task_set_name(SD_task_t task, const char *name)
411 xbt_free(task->name);
412 task->name = xbt_strdup(name);
415 /** @brief Returns the dynar of the parents of a task
418 * \return a newly allocated dynar comprising the parents of this task
421 xbt_dynar_t SD_task_get_parents(SD_task_t task)
427 parents = xbt_dynar_new(sizeof(SD_task_t), NULL);
428 xbt_dynar_foreach(task->tasks_before, i, dep) {
429 xbt_dynar_push(parents, &(dep->src));
434 /** @brief Returns the dynar of the parents of a task
437 * \return a newly allocated dynar comprising the parents of this task
439 xbt_dynar_t SD_task_get_children(SD_task_t task)
442 xbt_dynar_t children;
445 children = xbt_dynar_new(sizeof(SD_task_t), NULL);
446 xbt_dynar_foreach(task->tasks_after, i, dep) {
447 xbt_dynar_push(children, &(dep->dst));
453 * \brief Returns the amount of workstations involved in a task
455 * Only call this on already scheduled tasks!
458 int SD_task_get_workstation_count(SD_task_t task)
460 return task->workstation_nb;
464 * \brief Returns the list of workstations involved in a task
466 * Only call this on already scheduled tasks!
469 SD_workstation_t *SD_task_get_workstation_list(SD_task_t task)
471 return task->workstation_list;
475 * \brief Returns the total amount of work contained in a task
478 * \return the total amount of work (computation or data transfer) for this task
479 * \see SD_task_get_remaining_amount()
481 double SD_task_get_amount(SD_task_t task)
487 * \brief Sets the total amount of work of a task
488 * For sequential typed tasks (COMP_SEQ and COMM_E2E), it also sets the
489 * appropriate values in the flops_amount and bytes_amount arrays
490 * respectively. Nothing more than modifying task->amount is done for paralle
491 * typed tasks (COMP_PAR_AMDAHL and COMM_PAR_MXN_1D_BLOCK) as the distribution
492 * of the amount of work is done at scheduling time.
495 * \param amount the new amount of work to execute
497 void SD_task_set_amount(SD_task_t task, double amount)
499 task->amount = amount;
500 if (task->kind == SD_TASK_COMP_SEQ)
501 task->flops_amount[0] = amount;
502 if (task->kind == SD_TASK_COMM_E2E)
503 task->bytes_amount[2] = amount;
507 * \brief Returns the alpha parameter of a SD_TASK_COMP_PAR_AMDAHL task
509 * \param task a parallel task assuming Amdahl's law as speedup model
510 * \return the alpha parameter (serial part of a task in percent) for this task
512 double SD_task_get_alpha(SD_task_t task)
514 xbt_assert(SD_task_get_kind(task) == SD_TASK_COMP_PAR_AMDAHL,
515 "Alpha parameter is not defined for this kink of task");
521 * \brief Returns the remaining amount work to do till the completion of a task
524 * \return the remaining amount of work (computation or data transfer) of this task
525 * \see SD_task_get_amount()
527 double SD_task_get_remaining_amount(SD_task_t task)
529 if (task->surf_action)
530 return surf_action_get_remains(task->surf_action);
532 return task->remains;
535 e_SD_task_kind_t SD_task_get_kind(SD_task_t task)
540 /** @brief Displays debugging informations about a task */
541 void SD_task_dump(SD_task_t task)
543 unsigned int counter;
544 SD_dependency_t dependency;
547 XBT_INFO("Displaying task %s", SD_task_get_name(task));
548 statename = bprintf("%s %s %s %s %s %s %s %s",
549 (task->state == SD_NOT_SCHEDULED ? "not scheduled" :
551 (task->state == SD_SCHEDULABLE ? "schedulable" : ""),
552 (task->state == SD_SCHEDULED ? "scheduled" : ""),
553 (task->state == SD_RUNNABLE ? "runnable" :
555 (task->state == SD_IN_FIFO ? "in fifo" : ""),
556 (task->state == SD_RUNNING ? "running" : ""),
557 (task->state == SD_DONE ? "done" : ""),
558 (task->state == SD_FAILED ? "failed" : ""));
559 XBT_INFO(" - state: %s", statename);
562 if (task->kind != 0) {
563 switch (task->kind) {
564 case SD_TASK_COMM_E2E:
565 XBT_INFO(" - kind: end-to-end communication");
567 case SD_TASK_COMP_SEQ:
568 XBT_INFO(" - kind: sequential computation");
570 case SD_TASK_COMP_PAR_AMDAHL:
571 XBT_INFO(" - kind: parallel computation following Amdahl's law");
573 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
574 XBT_INFO(" - kind: MxN data redistribution assuming 1D block distribution");
577 XBT_INFO(" - (unknown kind %d)", task->kind);
582 XBT_INFO(" - tracing category: %s", task->category);
584 XBT_INFO(" - amount: %.0f", SD_task_get_amount(task));
585 if (task->kind == SD_TASK_COMP_PAR_AMDAHL)
586 XBT_INFO(" - alpha: %.2f", task->alpha);
587 XBT_INFO(" - Dependencies to satisfy: %d", task->unsatisfied_dependencies);
588 if (!xbt_dynar_is_empty(task->tasks_before)) {
589 XBT_INFO(" - pre-dependencies:");
590 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
591 XBT_INFO(" %s", SD_task_get_name(dependency->src));
594 if (!xbt_dynar_is_empty(task->tasks_after)) {
595 XBT_INFO(" - post-dependencies:");
596 xbt_dynar_foreach(task->tasks_after, counter, dependency) {
597 XBT_INFO(" %s", SD_task_get_name(dependency->dst));
602 /** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */
603 void SD_task_dotty(SD_task_t task, void *out)
605 unsigned int counter;
606 SD_dependency_t dependency;
607 FILE *fout = (FILE*)out;
608 fprintf(fout, " T%p [label=\"%.20s\"", task, task->name);
609 switch (task->kind) {
610 case SD_TASK_COMM_E2E:
611 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
612 fprintf(fout, ", shape=box");
614 case SD_TASK_COMP_SEQ:
615 case SD_TASK_COMP_PAR_AMDAHL:
616 fprintf(fout, ", shape=circle");
619 xbt_die("Unknown task type!");
621 fprintf(fout, "];\n");
622 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
623 fprintf(fout, " T%p -> T%p;\n", dependency->src, dependency->dst);
627 /* Destroys a dependency between two tasks.
629 static void __SD_task_dependency_destroy(void *dependency)
631 xbt_free(((SD_dependency_t)dependency)->name);
632 xbt_free(dependency);
636 * \brief Adds a dependency between two tasks
638 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
639 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_RUNNABLE.
641 * \param name the name of the new dependency (can be \c NULL)
642 * \param data the user data you want to associate with this dependency (can be \c NULL)
643 * \param src the task which must be executed first
644 * \param dst the task you want to make depend on \a src
645 * \see SD_task_dependency_remove()
647 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
651 unsigned long length;
654 SD_dependency_t dependency;
655 e_SD_task_state_t state;
657 dynar = src->tasks_after;
658 length = xbt_dynar_length(dynar);
662 "Cannot add a dependency between task '%s' and itself",
663 SD_task_get_name(src));
665 state = SD_task_get_state(src);
666 if (state != SD_NOT_SCHEDULED && state != SD_SCHEDULABLE &&
667 state != SD_RUNNING && !__SD_task_is_scheduled_or_runnable(src))
669 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED,"
670 " SD_RUNNABLE or SD_RUNNING", SD_task_get_name(src));
672 state = SD_task_get_state(dst);
673 if (state != SD_NOT_SCHEDULED && state != SD_SCHEDULABLE &&
674 !__SD_task_is_scheduled_or_runnable(dst))
676 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED,"
677 "or SD_RUNNABLE", SD_task_get_name(dst));
679 XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s",
680 SD_task_get_name(src), SD_task_get_name(dst));
681 for (i = 0; i < length && !found; i++) {
682 xbt_dynar_get_cpy(dynar, i, &dependency);
683 found = (dependency->dst == dst);
684 XBT_DEBUG("Dependency %lu: dependency->dst = %s", i,
685 SD_task_get_name(dependency->dst));
690 "A dependency already exists between task '%s' and task '%s'",
691 SD_task_get_name(src), SD_task_get_name(dst));
693 dependency = xbt_new(s_SD_dependency_t, 1);
695 dependency->name = xbt_strdup(name); /* xbt_strdup is cleaver enough to deal with NULL args itself */
696 dependency->data = data;
697 dependency->src = src;
698 dependency->dst = dst;
700 /* src must be executed before dst */
701 xbt_dynar_push(src->tasks_after, &dependency);
702 xbt_dynar_push(dst->tasks_before, &dependency);
704 dst->unsatisfied_dependencies++;
707 /* if the task was runnable, then dst->tasks_before is not empty anymore,
708 so we must go back to state SD_SCHEDULED */
709 if (SD_task_get_state(dst) == SD_RUNNABLE) {
711 ("SD_task_dependency_add: %s was runnable and becomes scheduled!",
712 SD_task_get_name(dst));
713 SD_task_set_state(dst, SD_SCHEDULED);
717 * \brief Returns the name given as input when dependency has been created..
720 * \param dst a task depending on \a src
723 const char *SD_task_dependency_get_name(SD_task_t src, SD_task_t dst){
725 SD_dependency_t dependency;
727 xbt_dynar_foreach(src->tasks_after, i, dependency){
728 if (dependency->dst == dst)
729 return dependency->name;
735 * \brief Indicates whether there is a dependency between two tasks.
738 * \param dst a task depending on \a src
740 * If src is NULL, checks whether dst has any pre-dependency.
741 * If dst is NULL, checks whether src has any post-dependency.
743 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
745 unsigned int counter;
746 SD_dependency_t dependency;
748 xbt_assert(src != NULL
750 "Invalid parameter: both src and dst are NULL");
754 xbt_dynar_foreach(src->tasks_after, counter, dependency) {
755 if (dependency->dst == dst)
759 return xbt_dynar_length(src->tasks_after);
762 return xbt_dynar_length(dst->tasks_before);
768 * \brief Remove a dependency between two tasks
771 * \param dst a task depending on \a src
772 * \see SD_task_dependency_add()
774 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
778 unsigned long length;
781 SD_dependency_t dependency;
783 /* remove the dependency from src->tasks_after */
784 dynar = src->tasks_after;
785 length = xbt_dynar_length(dynar);
787 for (i = 0; i < length && !found; i++) {
788 xbt_dynar_get_cpy(dynar, i, &dependency);
789 if (dependency->dst == dst) {
790 xbt_dynar_remove_at(dynar, i, NULL);
796 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
797 SD_task_get_name(src), SD_task_get_name(dst),
798 SD_task_get_name(dst), SD_task_get_name(src));
800 /* remove the dependency from dst->tasks_before */
801 dynar = dst->tasks_before;
802 length = xbt_dynar_length(dynar);
805 for (i = 0; i < length && !found; i++) {
806 xbt_dynar_get_cpy(dynar, i, &dependency);
807 if (dependency->src == src) {
808 xbt_dynar_remove_at(dynar, i, NULL);
809 __SD_task_dependency_destroy(dependency);
810 dst->unsatisfied_dependencies--;
815 /* should never happen... */
817 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
818 SD_task_get_name(dst), SD_task_get_name(src),
819 SD_task_get_name(src), SD_task_get_name(dst));
821 /* if the task was scheduled and dst->tasks_before is empty now, we can make it runnable */
823 if (dst->unsatisfied_dependencies == 0) {
824 if (SD_task_get_state(dst) == SD_SCHEDULED)
825 SD_task_set_state(dst, SD_RUNNABLE);
827 SD_task_set_state(dst, SD_SCHEDULABLE);
830 if (dst->is_not_ready == 0)
831 SD_task_set_state(dst, SD_SCHEDULABLE);
833 /* __SD_print_dependencies(src);
834 __SD_print_dependencies(dst); */
838 * \brief Returns the user data associated with a dependency between two tasks
841 * \param dst a task depending on \a src
842 * \return the user data associated with this dependency (can be \c NULL)
843 * \see SD_task_dependency_add()
845 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
849 unsigned long length;
852 SD_dependency_t dependency;
854 dynar = src->tasks_after;
855 length = xbt_dynar_length(dynar);
857 for (i = 0; i < length && !found; i++) {
858 xbt_dynar_get_cpy(dynar, i, &dependency);
859 found = (dependency->dst == dst);
862 THROWF(arg_error, 0, "No dependency found between task '%s' and '%s'",
863 SD_task_get_name(src), SD_task_get_name(dst));
864 return dependency->data;
868 * \brief Adds a watch point to a task
870 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
871 * task becomes the one given in argument. The
872 * watch point is then automatically removed.
875 * \param state the \ref e_SD_task_state_t "state" you want to watch
876 * (cannot be #SD_NOT_SCHEDULED)
877 * \see SD_task_unwatch()
879 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
881 if (state & SD_NOT_SCHEDULED)
883 "Cannot add a watch point for state SD_NOT_SCHEDULED");
885 task->watch_points = task->watch_points | state;
889 * \brief Removes a watch point from a task
892 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
893 * \see SD_task_watch()
895 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
897 xbt_assert(state != SD_NOT_SCHEDULED,
898 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
900 task->watch_points = task->watch_points & ~state;
904 * \brief Returns an approximative estimation of the execution time of a task.
906 * The estimation is very approximative because the value returned is the time
907 * the task would take if it was executed now and if it was the only task.
909 * \param task the task to evaluate
910 * \param workstation_nb number of workstations on which the task would be executed
911 * \param workstation_list the workstations on which the task would be executed
912 * \param flops_amount computation amount for each workstation
913 * \param bytes_amount communication amount between each pair of workstations
916 double SD_task_get_execution_time(SD_task_t task,
918 const SD_workstation_t *
920 const double *flops_amount,
921 const double *bytes_amount)
923 double time, max_time = 0.0;
925 xbt_assert(workstation_nb > 0, "Invalid parameter");
927 /* the task execution time is the maximum execution time of the parallel tasks */
929 for (i = 0; i < workstation_nb; i++) {
931 if (flops_amount != NULL)
933 SD_workstation_get_computation_time(workstation_list[i],
936 if (bytes_amount != NULL)
937 for (j = 0; j < workstation_nb; j++) {
939 SD_route_get_communication_time(workstation_list[i],
946 if (time > max_time) {
953 static XBT_INLINE void SD_task_do_schedule(SD_task_t task)
955 if (SD_task_get_state(task) > SD_SCHEDULABLE)
956 THROWF(arg_error, 0, "Task '%s' has already been scheduled",
957 SD_task_get_name(task));
959 /* update the task state */
960 if (task->unsatisfied_dependencies == 0)
961 SD_task_set_state(task, SD_RUNNABLE);
963 SD_task_set_state(task, SD_SCHEDULED);
967 * \brief Schedules a task
969 * The task state must be #SD_NOT_SCHEDULED.
970 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
971 * i.e. when its dependencies are satisfied.
973 * \param task the task you want to schedule
974 * \param workstation_count number of workstations on which the task will be executed
975 * \param workstation_list the workstations on which the task will be executed
976 * \param flops_amount computation amount for each workstation
977 * \param bytes_amount communication amount between each pair of workstations
978 * \param rate task execution speed rate
979 * \see SD_task_unschedule()
981 void SD_task_schedule(SD_task_t task, int workstation_count,
982 const SD_workstation_t * workstation_list,
983 const double *flops_amount,
984 const double *bytes_amount, double rate)
986 xbt_assert(workstation_count > 0, "workstation_nb must be positive");
988 task->workstation_nb = workstation_count;
992 task->flops_amount = (double*)xbt_realloc(task->flops_amount,
993 sizeof(double) * workstation_count);
994 memcpy(task->flops_amount, flops_amount,
995 sizeof(double) * workstation_count);
997 xbt_free(task->flops_amount);
998 task->flops_amount = NULL;
1001 int communication_nb = workstation_count * workstation_count;
1003 task->bytes_amount = (double*)xbt_realloc(task->bytes_amount,
1004 sizeof(double) * communication_nb);
1005 memcpy(task->bytes_amount, bytes_amount,
1006 sizeof(double) * communication_nb);
1008 xbt_free(task->bytes_amount);
1009 task->bytes_amount = NULL;
1012 task->workstation_list = (SD_workstation_t*)
1013 xbt_realloc(task->workstation_list,
1014 sizeof(SD_workstation_t) * workstation_count);
1015 memcpy(task->workstation_list, workstation_list,
1016 sizeof(SD_workstation_t) * workstation_count);
1018 SD_task_do_schedule(task);
1022 * \brief Unschedules a task
1024 * The task state must be #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING or #SD_FAILED.
1025 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
1026 * Call SD_task_schedule() to schedule it again.
1028 * \param task the task you want to unschedule
1029 * \see SD_task_schedule()
1031 void SD_task_unschedule(SD_task_t task)
1033 if (task->state != SD_SCHEDULED &&
1034 task->state != SD_RUNNABLE &&
1035 task->state != SD_RUNNING &&
1036 task->state != SD_FAILED)
1037 THROWF(arg_error, 0,
1038 "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED",
1039 SD_task_get_name(task));
1041 if (__SD_task_is_scheduled_or_runnable(task) /* if the task is scheduled or runnable */
1042 && ((task->kind == SD_TASK_COMP_PAR_AMDAHL) ||
1043 (task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK))) { /* Don't free scheduling data for typed tasks */
1044 __SD_task_destroy_scheduling_data(task);
1045 xbt_free(task->workstation_list);
1046 task->workstation_list=NULL;
1047 task->workstation_nb = 0;
1050 if (SD_task_get_state(task) == SD_RUNNING)
1051 /* the task should become SD_FAILED */
1052 task->surf_action->cancel();
1054 if (task->unsatisfied_dependencies == 0)
1055 SD_task_set_state(task, SD_SCHEDULABLE);
1057 SD_task_set_state(task, SD_NOT_SCHEDULED);
1059 task->remains = task->amount;
1060 task->start_time = -1.0;
1063 /* Destroys the data memorized by SD_task_schedule.
1064 * Task state must be SD_SCHEDULED or SD_RUNNABLE.
1066 static void __SD_task_destroy_scheduling_data(SD_task_t task)
1068 if (!__SD_task_is_scheduled_or_runnable(task)
1069 && SD_task_get_state(task) != SD_IN_FIFO)
1070 THROWF(arg_error, 0,
1071 "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
1072 SD_task_get_name(task));
1074 xbt_free(task->flops_amount);
1075 xbt_free(task->bytes_amount);
1076 task->flops_amount = task->bytes_amount = NULL;
1079 /* Runs a task. This function is directly called by __SD_task_try_to_run if
1080 * the task doesn't have to wait in FIFOs. Otherwise, it is called by
1081 * __SD_task_just_done when the task gets out of its FIFOs.
1083 void __SD_task_really_run(SD_task_t task)
1089 xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
1090 "Task '%s' is not runnable or in a fifo! Task state: %d",
1091 SD_task_get_name(task), (int)SD_task_get_state(task));
1092 xbt_assert(task->workstation_list != NULL,
1093 "Task '%s': workstation_list is NULL!",
1094 SD_task_get_name(task));
1096 XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
1097 int host_nb = task->workstation_nb;
1099 /* set this task as current task for the workstations in sequential mode */
1100 for (i = 0; i < host_nb; i++) {
1101 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
1102 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1103 sg_host_sd(task->workstation_list[i])->current_task = task;
1104 xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
1105 "The workstation should be busy now");
1109 XBT_DEBUG("Task '%s' set as current task for its workstations",
1110 SD_task_get_name(task));
1112 /* start the task */
1114 /* Copy the elements of the task into the action */
1115 hosts = xbt_new(sg_host_t, host_nb);
1117 for (i = 0; i < host_nb; i++)
1118 hosts[i] = task->workstation_list[i];
1120 double *flops_amount = xbt_new0(double, host_nb);
1121 double *bytes_amount = xbt_new0(double, host_nb * host_nb);
1124 if(task->flops_amount)
1125 memcpy(flops_amount, task->flops_amount, sizeof(double) *
1127 if(task->bytes_amount)
1128 memcpy(bytes_amount, task->bytes_amount,
1129 sizeof(double) * host_nb * host_nb);
1131 task->surf_action = surf_host_model->executeParallelTask(
1132 host_nb, hosts, flops_amount, bytes_amount, task->rate);
1134 task->surf_action->setData(task);
1136 XBT_DEBUG("surf_action = %p", task->surf_action);
1139 TRACE_surf_action(task->surf_action, task->category);
1141 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
1142 SD_task_set_state(task, SD_RUNNING);
1143 xbt_assert(SD_task_get_state(task) == SD_RUNNING,
1144 "Bad state of task '%s': %d",
1145 SD_task_get_name(task), (int)SD_task_get_state(task));
1149 /* Tries to run a task. This function is called by SD_simulate() when a
1150 * scheduled task becomes SD_RUNNABLE (i.e., when its dependencies are
1152 * If one of the workstations where the task is scheduled on is busy (in
1153 * sequential mode), the task doesn't start.
1154 * Returns whether the task has started.
1156 int __SD_task_try_to_run(SD_task_t task)
1161 SD_workstation_t workstation;
1163 xbt_assert(SD_task_get_state(task) == SD_RUNNABLE,
1164 "Task '%s' is not runnable! Task state: %d",
1165 SD_task_get_name(task), (int)SD_task_get_state(task));
1168 for (i = 0; i < task->workstation_nb; i++) {
1169 can_start = can_start &&
1170 !__SD_workstation_is_busy(task->workstation_list[i]);
1173 XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
1175 if (!can_start) { /* if the task cannot start and is not in the FIFOs yet */
1176 for (i = 0; i < task->workstation_nb; i++) {
1177 workstation = task->workstation_list[i];
1178 if (sg_host_sd(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1179 XBT_DEBUG("Pushing task '%s' in the FIFO of workstation '%s'",
1180 SD_task_get_name(task),
1181 SD_workstation_get_name(workstation));
1182 xbt_fifo_push(sg_host_sd(workstation)->task_fifo, task);
1185 SD_task_set_state(task, SD_IN_FIFO);
1186 XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
1188 __SD_task_really_run(task);
1194 /* This function is called by SD_simulate when a task is done.
1195 * It updates task->state and task->action and executes if necessary the tasks
1196 * which were waiting in FIFOs for the end of `task'
1198 void __SD_task_just_done(SD_task_t task)
1201 SD_workstation_t workstation;
1203 SD_task_t candidate;
1204 int candidate_nb = 0;
1205 int candidate_capacity = 8;
1206 SD_task_t *candidates;
1209 xbt_assert(SD_task_get_state(task)== SD_RUNNING,
1210 "The task must be running! Task state: %d",
1211 (int)SD_task_get_state(task));
1212 xbt_assert(task->workstation_list != NULL,
1213 "Task '%s': workstation_list is NULL!",
1214 SD_task_get_name(task));
1217 candidates = xbt_new(SD_task_t, 8);
1219 SD_task_set_state(task, SD_DONE);
1220 task->surf_action->unref();
1221 task->surf_action = NULL;
1223 XBT_DEBUG("Looking for candidates");
1225 /* if the task was executed on sequential workstations,
1226 maybe we can execute the next task of the FIFO for each workstation */
1227 for (i = 0; i < task->workstation_nb; i++) {
1228 workstation = task->workstation_list[i];
1229 XBT_DEBUG("Workstation '%s': access_mode = %d",
1230 SD_workstation_get_name(workstation),
1231 (int)sg_host_sd(workstation)->access_mode);
1232 if (sg_host_sd(workstation)->access_mode ==
1233 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1234 xbt_assert(sg_host_sd(workstation)->task_fifo != NULL,
1235 "Workstation '%s' has sequential access but no FIFO!",
1236 SD_workstation_get_name(workstation));
1237 xbt_assert(sg_host_sd(workstation)->current_task =
1238 task, "Workstation '%s': current task should be '%s'",
1239 SD_workstation_get_name(workstation),
1240 SD_task_get_name(task));
1242 /* the task is over so we can release the workstation */
1243 sg_host_sd(workstation)->current_task = NULL;
1245 XBT_DEBUG("Getting candidate in FIFO");
1246 candidate = (SD_task_t)
1247 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1248 (sg_host_sd(workstation)->task_fifo));
1250 if (candidate != NULL) {
1251 XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
1252 xbt_assert(SD_task_get_state(candidate) == SD_IN_FIFO,
1253 "Bad state of candidate '%s': %d",
1254 SD_task_get_name(candidate),
1255 (int)SD_task_get_state(candidate));
1258 XBT_DEBUG("Candidate in fifo: %p", candidate);
1260 /* if there was a task waiting for my place */
1261 if (candidate != NULL) {
1262 /* Unfortunately, we are not sure yet that we can execute the task now,
1263 because the task can be waiting more deeply in some other
1264 workstation's FIFOs ...
1265 So we memorize all candidate tasks, and then we will check for each
1266 candidate whether or not all its workstations are available. */
1268 /* realloc if necessary */
1269 if (candidate_nb == candidate_capacity) {
1270 candidate_capacity *= 2;
1271 candidates = (SD_task_t*)
1272 xbt_realloc(candidates,
1273 sizeof(SD_task_t) * candidate_capacity);
1276 /* register the candidate */
1277 candidates[candidate_nb++] = candidate;
1278 candidate->fifo_checked = 0;
1283 XBT_DEBUG("Candidates found: %d", candidate_nb);
1285 /* now we check every candidate task */
1286 for (i = 0; i < candidate_nb; i++) {
1287 candidate = candidates[i];
1289 if (candidate->fifo_checked) {
1290 continue; /* we have already evaluated that task */
1293 xbt_assert(SD_task_get_state(candidate) == SD_IN_FIFO,
1294 "Bad state of candidate '%s': %d",
1295 SD_task_get_name(candidate), (int)SD_task_get_state(candidate));
1297 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1298 workstation = candidate->workstation_list[j];
1300 /* I can start on this workstation if the workstation is shared
1301 or if I am the first task in the FIFO */
1302 can_start = sg_host_sd(workstation)->access_mode == SD_WORKSTATION_SHARED_ACCESS
1304 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1305 (sg_host_sd(workstation)->task_fifo));
1308 XBT_DEBUG("Candidate '%s' can start: %d", SD_task_get_name(candidate),
1311 /* now we are sure that I can start! */
1313 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1314 workstation = candidate->workstation_list[j];
1316 /* update the FIFO */
1317 if (sg_host_sd(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1318 candidate = (SD_task_t)xbt_fifo_shift(sg_host_sd(workstation)->task_fifo); /* the return value is stored just for debugging */
1319 XBT_DEBUG("Head of the FIFO: '%s' on workstation %s (%d task left)",
1321 NULL) ? SD_task_get_name(candidate) : "NULL",
1322 SD_workstation_get_name(workstation),
1323 xbt_fifo_size(sg_host_sd(workstation)->task_fifo));
1324 xbt_assert(candidate == candidates[i],
1325 "Error in __SD_task_just_done: bad first task in the FIFO");
1328 } /* for each workstation */
1330 /* finally execute the task */
1331 XBT_DEBUG("Task '%s' state: %d", SD_task_get_name(candidate),
1332 (int)SD_task_get_state(candidate));
1333 __SD_task_really_run(candidate);
1336 ("Calling __SD_task_is_running: task '%s', state set: %d",
1337 SD_task_get_name(candidate), candidate->state);
1338 xbt_assert(SD_task_get_state(candidate) == SD_RUNNING,
1339 "Bad state of task '%s': %d",
1340 SD_task_get_name(candidate),
1341 (int)SD_task_get_state(candidate));
1342 XBT_DEBUG("Okay, the task is running.");
1345 candidate->fifo_checked = 1;
1346 } /* for each candidate */
1348 xbt_free(candidates);
1352 * Remove all dependencies associated with a task. This function is called
1353 * when the task is destroyed.
1355 static void __SD_task_remove_dependencies(SD_task_t task)
1357 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
1358 because each one is stored twice */
1359 SD_dependency_t dependency;
1360 while (!xbt_dynar_is_empty(task->tasks_before)) {
1361 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
1362 SD_task_dependency_remove(dependency->src, dependency->dst);
1365 while (!xbt_dynar_is_empty(task->tasks_after)) {
1366 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
1367 SD_task_dependency_remove(dependency->src, dependency->dst);
1372 * \brief Returns the start time of a task
1374 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1376 * \param task: a task
1377 * \return the start time of this task
1379 double SD_task_get_start_time(SD_task_t task)
1381 if (task->surf_action)
1382 return task->surf_action->getStartTime();
1384 return task->start_time;
1388 * \brief Returns the finish time of a task
1390 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1391 * If the state is not completed yet, the returned value is an
1392 * estimation of the task finish time. This value can fluctuate
1393 * until the task is completed.
1395 * \param task: a task
1396 * \return the start time of this task
1398 double SD_task_get_finish_time(SD_task_t task)
1400 if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
1401 return task->surf_action->getFinishTime();
1403 return task->finish_time;
1408 void SD_task_distribute_comp_amdahl(SD_task_t task, int ws_count)
1411 xbt_assert(task->kind == SD_TASK_COMP_PAR_AMDAHL,
1412 "Task %s is not a SD_TASK_COMP_PAR_AMDAHL typed task."
1413 "Cannot use this function.",
1414 SD_task_get_name(task));
1415 task->flops_amount = xbt_new0(double, ws_count);
1416 task->bytes_amount = xbt_new0(double, ws_count * ws_count);
1417 xbt_free(task->workstation_list);
1418 task->workstation_nb = ws_count;
1419 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
1421 for(i=0;i<ws_count;i++){
1422 task->flops_amount[i] =
1423 (task->alpha + (1 - task->alpha)/ws_count) * task->amount;
1428 /** @brief Auto-schedules a task.
1430 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1431 * allows to specify the task costs at creation, and decouple them from the
1432 * scheduling process where you just specify which resource should deliver the
1435 * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e()
1436 * or SD_task_create_comp_seq(). Check their definitions for the exact semantic
1440 * We should create tasks kind for the following categories:
1441 * - Point to point communication (done)
1442 * - Sequential computation (done)
1443 * - group communication (redistribution, several kinds)
1444 * - parallel tasks with no internal communication (one kind per speedup
1445 * model such as Amdahl)
1446 * - idem+ internal communication. Task type not enough since we cannot store
1447 * comm cost alongside to comp one)
1449 void SD_task_schedulev(SD_task_t task, int count,
1450 const SD_workstation_t * list)
1453 SD_dependency_t dep;
1455 xbt_assert(task->kind != 0,
1456 "Task %s is not typed. Cannot automatically schedule it.",
1457 SD_task_get_name(task));
1458 switch (task->kind) {
1459 case SD_TASK_COMP_PAR_AMDAHL:
1460 SD_task_distribute_comp_amdahl(task, count);
1461 case SD_TASK_COMM_E2E:
1462 case SD_TASK_COMP_SEQ:
1463 xbt_assert(task->workstation_nb == count,
1464 "Got %d locations, but were expecting %d locations",
1465 count,task->workstation_nb);
1466 for (i = 0; i < count; i++)
1467 task->workstation_list[i] = list[i];
1468 if (SD_task_get_kind(task)== SD_TASK_COMP_SEQ && !task->flops_amount){
1469 /*This task has failed and is rescheduled. Reset the flops_amount*/
1470 task->flops_amount = xbt_new0(double, 1);
1471 task->flops_amount[0] = task->remains;
1473 SD_task_do_schedule(task);
1476 xbt_die("Kind of task %s not supported by SD_task_schedulev()",
1477 SD_task_get_name(task));
1479 if (task->kind == SD_TASK_COMM_E2E) {
1480 XBT_VERB("Schedule comm task %s between %s -> %s. It costs %.f bytes",
1481 SD_task_get_name(task),
1482 SD_workstation_get_name(task->workstation_list[0]),
1483 SD_workstation_get_name(task->workstation_list[1]),
1484 task->bytes_amount[2]);
1488 /* Iterate over all children and parents being COMM_E2E to say where I am
1489 * located (and start them if runnable) */
1490 if (task->kind == SD_TASK_COMP_SEQ) {
1491 XBT_VERB("Schedule computation task %s on %s. It costs %.f flops",
1492 SD_task_get_name(task),
1493 SD_workstation_get_name(task->workstation_list[0]),
1494 task->flops_amount[0]);
1496 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1497 SD_task_t before = dep->src;
1498 if (before->kind == SD_TASK_COMM_E2E) {
1499 before->workstation_list[1] = task->workstation_list[0];
1501 if (before->workstation_list[0] &&
1502 (SD_task_get_state(before)< SD_SCHEDULED)) {
1503 SD_task_do_schedule(before);
1505 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1506 SD_task_get_name(before),
1507 SD_workstation_get_name(before->workstation_list[0]),
1508 SD_workstation_get_name(before->workstation_list[1]),
1509 before->bytes_amount[2]);
1513 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1514 SD_task_t after = dep->dst;
1515 if (after->kind == SD_TASK_COMM_E2E) {
1516 after->workstation_list[0] = task->workstation_list[0];
1517 if (after->workstation_list[1]
1518 && (SD_task_get_state(after)< SD_SCHEDULED)) {
1519 SD_task_do_schedule(after);
1521 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1522 SD_task_get_name(after),
1523 SD_workstation_get_name(after->workstation_list[0]),
1524 SD_workstation_get_name(after->workstation_list[1]),
1525 after->bytes_amount[2]);
1531 /* Iterate over all children and parents being MXN_1D_BLOCK to say where I am
1532 * located (and start them if runnable) */
1533 if (task->kind == SD_TASK_COMP_PAR_AMDAHL) {
1534 XBT_VERB("Schedule computation task %s on %d workstations. %.f flops"
1535 " will be distributed following Amdahl's Law",
1536 SD_task_get_name(task), task->workstation_nb,
1537 task->flops_amount[0]);
1538 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1539 SD_task_t before = dep->src;
1540 if (before->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1541 if (!before->workstation_list){
1542 XBT_VERB("Sender side of Task %s is not scheduled yet",
1543 SD_task_get_name(before));
1544 before->workstation_list = xbt_new0(SD_workstation_t, count);
1545 before->workstation_nb = count;
1546 XBT_VERB("Fill the workstation list with list of Task '%s'",
1547 SD_task_get_name(task));
1548 for (i=0;i<count;i++)
1549 before->workstation_list[i] = task->workstation_list[i];
1551 XBT_VERB("Build communication matrix for task '%s'",
1552 SD_task_get_name(before));
1554 double src_start, src_end, dst_start, dst_end;
1555 src_nb = before->workstation_nb;
1557 before->workstation_list = (SD_workstation_t*) xbt_realloc(
1558 before->workstation_list,
1559 (before->workstation_nb+count)*sizeof(s_SD_workstation_t));
1560 for(i=0; i<count; i++)
1561 before->workstation_list[before->workstation_nb+i] =
1562 task->workstation_list[i];
1564 before->workstation_nb += count;
1565 xbt_free(before->flops_amount);
1566 xbt_free(before->bytes_amount);
1567 before->flops_amount = xbt_new0(double,
1568 before->workstation_nb);
1569 before->bytes_amount = xbt_new0(double,
1570 before->workstation_nb*
1571 before->workstation_nb);
1573 for(i=0;i<src_nb;i++){
1574 src_start = i*before->amount/src_nb;
1575 src_end = src_start + before->amount/src_nb;
1576 for(j=0; j<dst_nb; j++){
1577 dst_start = j*before->amount/dst_nb;
1578 dst_end = dst_start + before->amount/dst_nb;
1579 XBT_VERB("(%s->%s): (%.2f, %.2f)-> (%.2f, %.2f)",
1580 SD_workstation_get_name(before->workstation_list[i]),
1581 SD_workstation_get_name(before->workstation_list[src_nb+j]),
1582 src_start, src_end, dst_start, dst_end);
1583 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1584 before->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1586 before->bytes_amount[i*(src_nb+dst_nb)+src_nb+j] =
1587 MIN(src_end, dst_end) - MAX(src_start, dst_start);
1589 XBT_VERB("==> %.2f",
1590 before->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]);
1594 if (SD_task_get_state(before)< SD_SCHEDULED) {
1595 SD_task_do_schedule(before);
1597 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1598 SD_task_get_name(before),before->amount, src_nb, dst_nb);
1603 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1604 SD_task_t after = dep->dst;
1605 if (after->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1606 if (!after->workstation_list){
1607 XBT_VERB("Receiver side of Task '%s' is not scheduled yet",
1608 SD_task_get_name(after));
1609 after->workstation_list = xbt_new0(SD_workstation_t, count);
1610 after->workstation_nb = count;
1611 XBT_VERB("Fill the workstation list with list of Task '%s'",
1612 SD_task_get_name(task));
1613 for (i=0;i<count;i++)
1614 after->workstation_list[i] = task->workstation_list[i];
1617 double src_start, src_end, dst_start, dst_end;
1619 dst_nb = after->workstation_nb;
1620 after->workstation_list = (SD_workstation_t*) xbt_realloc(
1621 after->workstation_list,
1622 (after->workstation_nb+count)*sizeof(s_SD_workstation_t));
1623 for(i=after->workstation_nb - 1; i>=0; i--)
1624 after->workstation_list[count+i] = after->workstation_list[i];
1625 for(i=0; i<count; i++)
1626 after->workstation_list[i] = task->workstation_list[i];
1628 after->workstation_nb += count;
1630 xbt_free(after->flops_amount);
1631 xbt_free(after->bytes_amount);
1633 after->flops_amount = xbt_new0(double, after->workstation_nb);
1634 after->bytes_amount = xbt_new0(double,
1635 after->workstation_nb*
1636 after->workstation_nb);
1638 for(i=0;i<src_nb;i++){
1639 src_start = i*after->amount/src_nb;
1640 src_end = src_start + after->amount/src_nb;
1641 for(j=0; j<dst_nb; j++){
1642 dst_start = j*after->amount/dst_nb;
1643 dst_end = dst_start + after->amount/dst_nb;
1644 XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)",
1645 i, j, src_start, src_end, dst_start, dst_end);
1646 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1647 after->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1649 after->bytes_amount[i*(src_nb+dst_nb)+src_nb+j] =
1650 MIN(src_end, dst_end)- MAX(src_start, dst_start);
1652 XBT_VERB("==> %.2f",
1653 after->bytes_amount[i*(src_nb+dst_nb)+src_nb+j]);
1657 if (SD_task_get_state(after)< SD_SCHEDULED) {
1658 SD_task_do_schedule(after);
1660 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1661 SD_task_get_name(after),after->amount, src_nb, dst_nb);
1669 /** @brief autoschedule a task on a list of workstations
1671 * This function is very similar to SD_task_schedulev(),
1672 * but takes the list of workstations to schedule onto as separate parameters.
1673 * It builds a proper vector of workstations and then call SD_task_schedulev()
1675 void SD_task_schedulel(SD_task_t task, int count, ...)
1678 SD_workstation_t *list = xbt_new(SD_workstation_t, count);
1680 va_start(ap, count);
1681 for (i = 0; i < count; i++) {
1682 list[i] = va_arg(ap, SD_workstation_t);
1685 SD_task_schedulev(task, count, list);