1 /* Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011. The SimGrid Team.
2 * All rights reserved. */
4 /* This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
8 #include "simdag/simdag.h"
9 #include "xbt/sysdep.h"
10 #include "xbt/dynar.h"
11 #include "instr/instr_private.h"
13 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_task, sd,
14 "Logging specific to SimDag (task)");
16 static void __SD_task_remove_dependencies(SD_task_t task);
17 static void __SD_task_destroy_scheduling_data(SD_task_t task);
19 void* SD_task_new_f(void)
21 SD_task_t task = xbt_new0(s_SD_task_t, 1);
22 task->tasks_before = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
23 task->tasks_after = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
28 void SD_task_recycle_f(void *t)
30 SD_task_t task = (SD_task_t) t;
32 /* Reset the content */
33 task->kind = SD_TASK_NOT_TYPED;
34 task->state_hookup.prev = NULL;
35 task->state_hookup.next = NULL;
36 task->state_set = sd_global->not_scheduled_task_set;
37 xbt_swag_insert(task, task->state_set);
38 task->state = SD_NOT_SCHEDULED;
39 task->return_hookup.prev = NULL;
40 task->return_hookup.next = NULL;
44 task->start_time = -1.0;
45 task->finish_time = -1.0;
46 task->surf_action = NULL;
47 task->watch_points = 0;
50 xbt_dynar_reset(task->tasks_before);
51 xbt_dynar_reset(task->tasks_after);
52 task->unsatisfied_dependencies = 0;
53 task->is_not_ready = 0;
55 /* scheduling parameters */
56 task->workstation_nb = 0;
57 task->workstation_list = NULL;
58 task->computation_amount = NULL;
59 task->communication_amount = NULL;
63 void SD_task_free_f(void *t)
65 SD_task_t task = (SD_task_t)t;
67 xbt_dynar_free(&task->tasks_before);
68 xbt_dynar_free(&task->tasks_after);
73 * \brief Creates a new task.
75 * \param name the name of the task (can be \c NULL)
76 * \param data the user data you want to associate with the task (can be \c NULL)
77 * \param amount amount of the task
78 * \return the new task
79 * \see SD_task_destroy()
81 SD_task_t SD_task_create(const char *name, void *data, double amount)
83 SD_task_t task = xbt_mallocator_get(sd_global->task_mallocator);
85 /* general information */
86 task->data = data; /* user data */
87 task->name = xbt_strdup(name);
88 task->amount = amount;
89 task->remains = amount;
91 sd_global->task_number++;
94 task->category = NULL;
100 static XBT_INLINE SD_task_t SD_task_create_sized(const char *name,
101 void *data, double amount,
104 SD_task_t task = SD_task_create(name, data, amount);
105 task->communication_amount = xbt_new0(double, ws_count * ws_count);
106 task->computation_amount = xbt_new0(double, ws_count);
107 task->workstation_nb = ws_count;
108 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
112 /** @brief create a end-to-end communication task that can then be auto-scheduled
114 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
115 * allows to specify the task costs at creation, and decouple them from the
116 * scheduling process where you just specify which resource should deliver the
119 * A end-to-end communication must be scheduled on 2 hosts, and the amount
120 * specified at creation is sent from hosts[0] to hosts[1].
122 SD_task_t SD_task_create_comm_e2e(const char *name, void *data,
125 SD_task_t res = SD_task_create_sized(name, data, amount, 2);
126 res->communication_amount[2] = amount;
127 res->kind = SD_TASK_COMM_E2E;
131 /** @brief create a sequential computation task that can then be auto-scheduled
133 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
134 * allows to specify the task costs at creation, and decouple them from the
135 * scheduling process where you just specify which resource should deliver the
138 * A sequential computation must be scheduled on 1 host, and the amount
139 * specified at creation to be run on hosts[0].
141 * \param name the name of the task (can be \c NULL)
142 * \param data the user data you want to associate with the task (can be \c NULL)
143 * \param amount amount of compute work to be done by the task
144 * \return the new SD_TASK_COMP_SEQ typed task
146 SD_task_t SD_task_create_comp_seq(const char *name, void *data,
149 SD_task_t res = SD_task_create_sized(name, data, amount, 1);
150 res->computation_amount[0] = amount;
151 res->kind = SD_TASK_COMP_SEQ;
155 /** @brief create a parallel computation task that can then be auto-scheduled
157 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
158 * allows to specify the task costs at creation, and decouple them from the
159 * scheduling process where you just specify which resource should deliver the
162 * A parallel computation can be scheduled on any number of host.
163 * The underlying speedup model is Amdahl's law.
164 * To be auto-scheduled, \see SD_task_distribute_comp_amdhal has to be called
166 * \param name the name of the task (can be \c NULL)
167 * \param data the user data you want to associate with the task (can be \c NULL)
168 * \param amount amount of compute work to be done by the task
169 * \param alpha purely serial fraction of the work to be done (in [0.;1.[)
170 * \return the new task
172 SD_task_t SD_task_create_comp_par_amdahl(const char *name, void *data,
173 double amount, double alpha)
175 xbt_assert(alpha < 1. && alpha >= 0.,
176 "Invalid parameter: alpha must be in [0.;1.[");
178 SD_task_t res = SD_task_create(name, data, amount);
180 res->kind = SD_TASK_COMP_PAR_AMDAHL;
184 /** @brief create a complex data redistribution task that can then be
187 * Auto-scheduling mean that the task can be used with SD_task_schedulev().
188 * This allows to specify the task costs at creation, and decouple them from
189 * the scheduling process where you just specify which resource should
192 * A data redistribution can be scheduled on any number of host.
193 * The assumed distribution is a 1D block distribution. Each host owns the same
194 * share of the \see amount.
195 * To be auto-scheduled, \see SD_task_distribute_comm_mxn_1d_block has to be
197 * \param name the name of the task (can be \c NULL)
198 * \param data the user data you want to associate with the task (can be
200 * \param amount amount of data to redistribute by the task
201 * \return the new task
203 SD_task_t SD_task_create_comm_par_mxn_1d_block(const char *name, void *data,
206 SD_task_t res = SD_task_create(name, data, amount);
207 res->workstation_list=NULL;
208 res->kind = SD_TASK_COMM_PAR_MXN_1D_BLOCK;
213 * \brief Destroys a task.
215 * The user data (if any) should have been destroyed first.
217 * \param task the task you want to destroy
218 * \see SD_task_create()
220 void SD_task_destroy(SD_task_t task)
222 XBT_DEBUG("Destroying task %s...", SD_task_get_name(task));
224 __SD_task_remove_dependencies(task);
225 /* if the task was scheduled or runnable we have to free the scheduling parameters */
226 if (__SD_task_is_scheduled_or_runnable(task))
227 __SD_task_destroy_scheduling_data(task);
228 if (task->state_set != NULL) /* would be null if just created */
229 xbt_swag_remove(task, task->state_set);
231 xbt_swag_remove(task, sd_global->return_set);
233 xbt_free(task->name);
235 if (task->surf_action != NULL)
236 surf_workstation_model->action_unref(task->surf_action);
238 xbt_free(task->workstation_list);
239 xbt_free(task->communication_amount);
240 xbt_free(task->computation_amount);
243 if (task->category) xbt_free(task->category);
246 xbt_mallocator_release(sd_global->task_mallocator,task);
247 sd_global->task_number--;
249 XBT_DEBUG("Task destroyed.");
253 * \brief Returns the user data of a task
256 * \return the user data associated with this task (can be \c NULL)
257 * \see SD_task_set_data()
259 void *SD_task_get_data(SD_task_t task)
265 * \brief Sets the user data of a task
267 * The new data can be \c NULL. The old data should have been freed first
268 * if it was not \c NULL.
271 * \param data the new data you want to associate with this task
272 * \see SD_task_get_data()
274 void SD_task_set_data(SD_task_t task, void *data)
280 * \brief Sets the rate of a task
282 * This will change the network bandwidth a task can use. This rate
283 * depends on both the nominal bandwidth on the route onto which the task is
284 * scheduled (\see SD_task_get_current_bandwidth) and the amount of data to
287 * To divide the nominal bandwidth by 2, the rate then has to be :
288 * rate = bandwidth/(2*amount)
290 * \param task a \see SD_TASK_COMM_E2E task (end-to-end communication)
291 * \param rate the new rate you want to associate with this task.
293 void SD_task_set_rate(SD_task_t task, double rate)
295 xbt_assert(task->kind == SD_TASK_COMM_E2E,
296 "The rate can be modified for end-to-end communications only.");
302 * \brief Returns the state of a task
305 * \return the current \ref e_SD_task_state_t "state" of this task:
306 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING, #SD_DONE or #SD_FAILED
307 * \see e_SD_task_state_t
309 e_SD_task_state_t SD_task_get_state(SD_task_t task)
314 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
316 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
318 xbt_swag_remove(task, task->state_set);
320 case SD_NOT_SCHEDULED:
321 task->state_set = sd_global->not_scheduled_task_set;
324 task->state_set = sd_global->schedulable_task_set;
327 task->state_set = sd_global->scheduled_task_set;
330 task->state_set = sd_global->runnable_task_set;
333 task->state_set = sd_global->in_fifo_task_set;
336 task->state_set = sd_global->running_task_set;
338 surf_workstation_model->action_get_start_time(task->surf_action);
341 task->state_set = sd_global->done_task_set;
343 surf_workstation_model->action_get_finish_time(task->surf_action);
346 jedule_log_sd_event(task);
350 task->state_set = sd_global->failed_task_set;
353 xbt_die( "Invalid state");
355 xbt_swag_insert(task, task->state_set);
356 task->state = new_state;
358 if (task->watch_points & new_state) {
359 XBT_VERB("Watch point reached with task '%s'!", SD_task_get_name(task));
360 sd_global->watch_point_reached = 1;
361 SD_task_unwatch(task, new_state); /* remove the watch point */
366 * \brief Returns the name of a task
369 * \return the name of this task (can be \c NULL)
371 const char *SD_task_get_name(SD_task_t task)
376 /** @brief Allows to change the name of a task */
377 void SD_task_set_name(SD_task_t task, const char *name)
379 xbt_free(task->name);
380 task->name = xbt_strdup(name);
383 /** @brief Returns the dynar of the parents of a task
386 * \return a newly allocated dynar comprising the parents of this task
389 xbt_dynar_t SD_task_get_parents(SD_task_t task)
395 parents = xbt_dynar_new(sizeof(SD_task_t), NULL);
396 xbt_dynar_foreach(task->tasks_before, i, dep) {
397 xbt_dynar_push(parents, &(dep->src));
402 /** @brief Returns the dynar of the parents of a task
405 * \return a newly allocated dynar comprising the parents of this task
407 xbt_dynar_t SD_task_get_children(SD_task_t task)
410 xbt_dynar_t children;
413 children = xbt_dynar_new(sizeof(SD_task_t), NULL);
414 xbt_dynar_foreach(task->tasks_after, i, dep) {
415 xbt_dynar_push(children, &(dep->dst));
421 * \brief Returns the amount of workstations involved in a task
423 * Only call this on already scheduled tasks!
426 int SD_task_get_workstation_count(SD_task_t task)
428 return task->workstation_nb;
432 * \brief Returns the list of workstations involved in a task
434 * Only call this on already scheduled tasks!
437 SD_workstation_t *SD_task_get_workstation_list(SD_task_t task)
439 return task->workstation_list;
443 * \brief Returns the total amount of work contained in a task
446 * \return the total amount of work (computation or data transfer) for this task
447 * \see SD_task_get_remaining_amount()
449 double SD_task_get_amount(SD_task_t task)
455 * \brief Returns the remaining amount work to do till the completion of a task
458 * \return the remaining amount of work (computation or data transfer) of this task
459 * \see SD_task_get_amount()
461 double SD_task_get_remaining_amount(SD_task_t task)
463 if (task->surf_action)
464 return surf_workstation_model->get_remains(task->surf_action);
466 return task->remains;
469 int SD_task_get_kind(SD_task_t task)
474 /** @brief Displays debugging informations about a task */
475 void SD_task_dump(SD_task_t task)
477 unsigned int counter;
478 SD_dependency_t dependency;
481 XBT_INFO("Displaying task %s", SD_task_get_name(task));
482 statename = bprintf("%s %s %s %s %s %s %s %s",
483 (task->state & SD_NOT_SCHEDULED ? "not scheduled" :
485 (task->state & SD_SCHEDULABLE ? "schedulable" : ""),
486 (task->state & SD_SCHEDULED ? "scheduled" : ""),
487 (task->state & SD_RUNNABLE ? "runnable" :
489 (task->state & SD_IN_FIFO ? "in fifo" : ""),
490 (task->state & SD_RUNNING ? "running" : ""),
491 (task->state & SD_DONE ? "done" : ""),
492 (task->state & SD_FAILED ? "failed" : ""));
493 XBT_INFO(" - state: %s", statename);
496 if (task->kind != 0) {
497 switch (task->kind) {
498 case SD_TASK_COMM_E2E:
499 XBT_INFO(" - kind: end-to-end communication");
501 case SD_TASK_COMP_SEQ:
502 XBT_INFO(" - kind: sequential computation");
504 case SD_TASK_COMP_PAR_AMDAHL:
505 XBT_INFO(" - kind: parallel computation following Amdahl's law");
507 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
508 XBT_INFO(" - kind: MxN data redistribution assuming 1D block distribution");
511 XBT_INFO(" - (unknown kind %d)", task->kind);
514 XBT_INFO(" - amount: %.0f", SD_task_get_amount(task));
515 if (task->kind == SD_TASK_COMP_PAR_AMDAHL)
516 XBT_INFO(" - alpha: %.2f", task->alpha);
517 XBT_INFO(" - Dependencies to satisfy: %d", task->unsatisfied_dependencies);
518 if (!xbt_dynar_is_empty(task->tasks_before)) {
519 XBT_INFO(" - pre-dependencies:");
520 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
521 XBT_INFO(" %s", SD_task_get_name(dependency->src));
524 if (!xbt_dynar_is_empty(task->tasks_after)) {
525 XBT_INFO(" - post-dependencies:");
526 xbt_dynar_foreach(task->tasks_after, counter, dependency) {
527 XBT_INFO(" %s", SD_task_get_name(dependency->dst));
532 /** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */
533 void SD_task_dotty(SD_task_t task, void *out)
535 unsigned int counter;
536 SD_dependency_t dependency;
537 fprintf(out, " T%p [label=\"%.20s\"", task, task->name);
538 switch (task->kind) {
539 case SD_TASK_COMM_E2E:
540 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
541 fprintf(out, ", shape=box");
543 case SD_TASK_COMP_SEQ:
544 case SD_TASK_COMP_PAR_AMDAHL:
545 fprintf(out, ", shape=circle");
548 xbt_die("Unknown task type!");
550 fprintf(out, "];\n");
551 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
552 fprintf(out, " T%p -> T%p;\n", dependency->src, dependency->dst);
556 /* Destroys a dependency between two tasks.
558 static void __SD_task_dependency_destroy(void *dependency)
560 xbt_free(((SD_dependency_t)dependency)->name);
561 xbt_free(dependency);
565 * \brief Adds a dependency between two tasks
567 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
568 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_RUNNABLE.
570 * \param name the name of the new dependency (can be \c NULL)
571 * \param data the user data you want to associate with this dependency (can be \c NULL)
572 * \param src the task which must be executed first
573 * \param dst the task you want to make depend on \a src
574 * \see SD_task_dependency_remove()
576 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
583 SD_dependency_t dependency;
585 dynar = src->tasks_after;
586 length = xbt_dynar_length(dynar);
590 "Cannot add a dependency between task '%s' and itself",
591 SD_task_get_name(src));
593 if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_schedulable(src)
594 && !__SD_task_is_scheduled_or_runnable(src) && !__SD_task_is_running(src))
596 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE"
598 SD_task_get_name(src));
600 if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_schedulable(dst)
601 && !__SD_task_is_scheduled_or_runnable(dst))
603 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE",
604 SD_task_get_name(dst));
606 XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s",
607 SD_task_get_name(src), SD_task_get_name(dst));
608 for (i = 0; i < length && !found; i++) {
609 xbt_dynar_get_cpy(dynar, i, &dependency);
610 found = (dependency->dst == dst);
611 XBT_DEBUG("Dependency %d: dependency->dst = %s", i,
612 SD_task_get_name(dependency->dst));
617 "A dependency already exists between task '%s' and task '%s'",
618 SD_task_get_name(src), SD_task_get_name(dst));
620 dependency = xbt_new(s_SD_dependency_t, 1);
622 dependency->name = xbt_strdup(name); /* xbt_strdup is cleaver enough to deal with NULL args itself */
623 dependency->data = data;
624 dependency->src = src;
625 dependency->dst = dst;
627 /* src must be executed before dst */
628 xbt_dynar_push(src->tasks_after, &dependency);
629 xbt_dynar_push(dst->tasks_before, &dependency);
631 dst->unsatisfied_dependencies++;
634 /* if the task was runnable, then dst->tasks_before is not empty anymore,
635 so we must go back to state SD_SCHEDULED */
636 if (__SD_task_is_runnable(dst)) {
638 ("SD_task_dependency_add: %s was runnable and becomes scheduled!",
639 SD_task_get_name(dst));
640 __SD_task_set_state(dst, SD_SCHEDULED);
645 * \brief Indicates whether there is a dependency between two tasks.
648 * \param dst a task depending on \a src
650 * If src is NULL, checks whether dst has any pre-dependency.
651 * If dst is NULL, checks whether src has any post-dependency.
653 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
655 unsigned int counter;
656 SD_dependency_t dependency;
658 xbt_assert(src != NULL
660 "Invalid parameter: both src and dst are NULL");
664 xbt_dynar_foreach(src->tasks_after, counter, dependency) {
665 if (dependency->dst == dst)
669 return xbt_dynar_length(src->tasks_after);
672 return xbt_dynar_length(dst->tasks_before);
678 * \brief Remove a dependency between two tasks
681 * \param dst a task depending on \a src
682 * \see SD_task_dependency_add()
684 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
691 SD_dependency_t dependency;
693 /* remove the dependency from src->tasks_after */
694 dynar = src->tasks_after;
695 length = xbt_dynar_length(dynar);
697 for (i = 0; i < length && !found; i++) {
698 xbt_dynar_get_cpy(dynar, i, &dependency);
699 if (dependency->dst == dst) {
700 xbt_dynar_remove_at(dynar, i, NULL);
706 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
707 SD_task_get_name(src), SD_task_get_name(dst),
708 SD_task_get_name(dst), SD_task_get_name(src));
710 /* remove the dependency from dst->tasks_before */
711 dynar = dst->tasks_before;
712 length = xbt_dynar_length(dynar);
715 for (i = 0; i < length && !found; i++) {
716 xbt_dynar_get_cpy(dynar, i, &dependency);
717 if (dependency->src == src) {
718 xbt_dynar_remove_at(dynar, i, NULL);
719 __SD_task_dependency_destroy(dependency);
720 dst->unsatisfied_dependencies--;
725 /* should never happen... */
727 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
728 SD_task_get_name(dst), SD_task_get_name(src),
729 SD_task_get_name(src), SD_task_get_name(dst));
731 /* if the task was scheduled and dst->tasks_before is empty now, we can make it runnable */
733 if (dst->unsatisfied_dependencies == 0) {
734 if (__SD_task_is_scheduled(dst))
735 __SD_task_set_state(dst, SD_RUNNABLE);
737 __SD_task_set_state(dst, SD_SCHEDULABLE);
740 if (dst->is_not_ready == 0)
741 __SD_task_set_state(dst, SD_SCHEDULABLE);
743 /* __SD_print_dependencies(src);
744 __SD_print_dependencies(dst); */
748 * \brief Returns the user data associated with a dependency between two tasks
751 * \param dst a task depending on \a src
752 * \return the user data associated with this dependency (can be \c NULL)
753 * \see SD_task_dependency_add()
755 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
762 SD_dependency_t dependency;
764 dynar = src->tasks_after;
765 length = xbt_dynar_length(dynar);
767 for (i = 0; i < length && !found; i++) {
768 xbt_dynar_get_cpy(dynar, i, &dependency);
769 found = (dependency->dst == dst);
772 THROWF(arg_error, 0, "No dependency found between task '%s' and '%s'",
773 SD_task_get_name(src), SD_task_get_name(dst));
774 return dependency->data;
777 /* temporary function for debugging */
778 static void __SD_print_watch_points(SD_task_t task)
780 static const int state_masks[] =
781 { SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNING, SD_RUNNABLE, SD_DONE,
784 static const char *state_names[] =
785 { "schedulable", "scheduled", "running", "runnable", "done",
790 XBT_INFO("Task '%s' watch points (%x): ", SD_task_get_name(task),
794 for (i = 0; i < 5; i++) {
795 if (task->watch_points & state_masks[i])
796 XBT_INFO("%s ", state_names[i]);
801 * \brief Adds a watch point to a task
803 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
804 * task becomes the one given in argument. The
805 * watch point is then automatically removed.
808 * \param state the \ref e_SD_task_state_t "state" you want to watch
809 * (cannot be #SD_NOT_SCHEDULED)
810 * \see SD_task_unwatch()
812 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
814 if (state & SD_NOT_SCHEDULED)
816 "Cannot add a watch point for state SD_NOT_SCHEDULED");
818 task->watch_points = task->watch_points | state;
819 /* __SD_print_watch_points(task); */
823 * \brief Removes a watch point from a task
826 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
827 * \see SD_task_watch()
829 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
831 xbt_assert(state != SD_NOT_SCHEDULED,
832 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
834 task->watch_points = task->watch_points & ~state;
835 /* __SD_print_watch_points(task); */
839 * \brief Returns an approximative estimation of the execution time of a task.
841 * The estimation is very approximative because the value returned is the time
842 * the task would take if it was executed now and if it was the only task.
844 * \param task the task to evaluate
845 * \param workstation_nb number of workstations on which the task would be executed
846 * \param workstation_list the workstations on which the task would be executed
847 * \param computation_amount computation amount for each workstation
848 * \param communication_amount communication amount between each pair of workstations
851 double SD_task_get_execution_time(SD_task_t task,
853 const SD_workstation_t *
855 const double *computation_amount,
856 const double *communication_amount)
858 double time, max_time = 0.0;
860 xbt_assert(workstation_nb > 0, "Invalid parameter");
862 /* the task execution time is the maximum execution time of the parallel tasks */
864 for (i = 0; i < workstation_nb; i++) {
866 if (computation_amount != NULL)
868 SD_workstation_get_computation_time(workstation_list[i],
869 computation_amount[i]);
871 if (communication_amount != NULL)
872 for (j = 0; j < workstation_nb; j++) {
874 SD_route_get_communication_time(workstation_list[i],
876 communication_amount[i *
881 if (time > max_time) {
888 static XBT_INLINE void SD_task_do_schedule(SD_task_t task)
890 if (!__SD_task_is_not_scheduled(task) && !__SD_task_is_schedulable(task))
891 THROWF(arg_error, 0, "Task '%s' has already been scheduled",
892 SD_task_get_name(task));
894 /* update the task state */
895 if (task->unsatisfied_dependencies == 0)
896 __SD_task_set_state(task, SD_RUNNABLE);
898 __SD_task_set_state(task, SD_SCHEDULED);
902 * \brief Schedules a task
904 * The task state must be #SD_NOT_SCHEDULED.
905 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
906 * i.e. when its dependencies are satisfied.
908 * \param task the task you want to schedule
909 * \param workstation_count number of workstations on which the task will be executed
910 * \param workstation_list the workstations on which the task will be executed
911 * \param computation_amount computation amount for each workstation
912 * \param communication_amount communication amount between each pair of workstations
913 * \param rate task execution speed rate
914 * \see SD_task_unschedule()
916 void SD_task_schedule(SD_task_t task, int workstation_count,
917 const SD_workstation_t * workstation_list,
918 const double *computation_amount,
919 const double *communication_amount, double rate)
921 int communication_nb;
922 task->workstation_nb = 0;
924 xbt_assert(workstation_count > 0, "workstation_nb must be positive");
926 task->workstation_nb = workstation_count;
929 if (computation_amount) {
930 task->computation_amount = xbt_realloc(task->computation_amount,
931 sizeof(double) * workstation_count);
932 memcpy(task->computation_amount, computation_amount,
933 sizeof(double) * workstation_count);
935 xbt_free(task->computation_amount);
936 task->computation_amount = NULL;
939 communication_nb = workstation_count * workstation_count;
940 if (communication_amount) {
941 task->communication_amount = xbt_realloc(task->communication_amount,
942 sizeof(double) * communication_nb);
943 memcpy(task->communication_amount, communication_amount,
944 sizeof(double) * communication_nb);
946 xbt_free(task->communication_amount);
947 task->communication_amount = NULL;
950 task->workstation_list =
951 xbt_realloc(task->workstation_list,
952 sizeof(SD_workstation_t) * workstation_count);
953 memcpy(task->workstation_list, workstation_list,
954 sizeof(SD_workstation_t) * workstation_count);
956 SD_task_do_schedule(task);
960 * \brief Unschedules a task
962 * The task state must be #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING or #SD_FAILED.
963 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
964 * Call SD_task_schedule() to schedule it again.
966 * \param task the task you want to unschedule
967 * \see SD_task_schedule()
969 void SD_task_unschedule(SD_task_t task)
971 if (task->state_set != sd_global->scheduled_task_set &&
972 task->state_set != sd_global->runnable_task_set &&
973 task->state_set != sd_global->running_task_set &&
974 task->state_set != sd_global->failed_task_set)
976 "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED",
977 SD_task_get_name(task));
979 if (__SD_task_is_scheduled_or_runnable(task) /* if the task is scheduled or runnable */
980 && ((task->kind == SD_TASK_COMP_PAR_AMDAHL) ||
981 (task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK))) { /* Don't free scheduling data for typed tasks */
982 __SD_task_destroy_scheduling_data(task);
983 task->workstation_list=NULL;
984 task->workstation_nb = 0;
987 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
988 surf_workstation_model->action_cancel(task->surf_action);
990 if (task->unsatisfied_dependencies == 0)
991 __SD_task_set_state(task, SD_SCHEDULABLE);
993 __SD_task_set_state(task, SD_NOT_SCHEDULED);
995 task->remains = task->amount;
996 task->start_time = -1.0;
999 /* Destroys the data memorized by SD_task_schedule.
1000 * Task state must be SD_SCHEDULED or SD_RUNNABLE.
1002 static void __SD_task_destroy_scheduling_data(SD_task_t task)
1004 if (!__SD_task_is_scheduled_or_runnable(task)
1005 && !__SD_task_is_in_fifo(task))
1006 THROWF(arg_error, 0,
1007 "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
1008 SD_task_get_name(task));
1010 xbt_free(task->computation_amount);
1011 xbt_free(task->communication_amount);
1012 task->computation_amount = task->communication_amount = NULL;
1015 /* Runs a task. This function is directly called by __SD_task_try_to_run if
1016 * the task doesn't have to wait in FIFOs. Otherwise, it is called by
1017 * __SD_task_just_done when the task gets out of its FIFOs.
1019 void __SD_task_really_run(SD_task_t task)
1023 void **surf_workstations;
1025 xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
1026 "Task '%s' is not runnable or in a fifo! Task state: %d",
1027 SD_task_get_name(task), (int)SD_task_get_state(task));
1028 xbt_assert(task->workstation_list != NULL,
1029 "Task '%s': workstation_list is NULL!",
1030 SD_task_get_name(task));
1032 XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
1033 int workstation_nb = task->workstation_nb;
1035 /* set this task as current task for the workstations in sequential mode */
1036 for (i = 0; i < workstation_nb; i++) {
1037 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
1038 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1039 task->workstation_list[i]->current_task = task;
1040 xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
1041 "The workstation should be busy now");
1045 XBT_DEBUG("Task '%s' set as current task for its workstations",
1046 SD_task_get_name(task));
1048 /* start the task */
1050 /* we have to create a Surf workstation array instead of the SimDag
1051 * workstation array */
1052 surf_workstations = xbt_new(void *, workstation_nb);
1054 for (i = 0; i < workstation_nb; i++)
1055 surf_workstations[i] = task->workstation_list[i]->surf_workstation;
1057 double *computation_amount = xbt_new0(double, workstation_nb);
1058 double *communication_amount = xbt_new0(double, workstation_nb * workstation_nb);
1061 if(task->computation_amount)
1062 memcpy(computation_amount, task->computation_amount, sizeof(double) *
1064 if(task->communication_amount)
1065 memcpy(communication_amount, task->communication_amount,
1066 sizeof(double) * workstation_nb * workstation_nb);
1069 surf_workstation_model->extension.
1070 workstation.execute_parallel_task(workstation_nb,
1073 communication_amount,
1076 surf_workstation_model->action_data_set(task->surf_action, task);
1078 XBT_DEBUG("surf_action = %p", task->surf_action);
1082 TRACE_surf_action(task->surf_action, task->category);
1085 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
1086 __SD_task_set_state(task, SD_RUNNING);
1087 xbt_assert(__SD_task_is_running(task), "Bad state of task '%s': %d",
1088 SD_task_get_name(task), (int)SD_task_get_state(task));
1092 /* Tries to run a task. This function is called by SD_simulate() when a
1093 * scheduled task becomes SD_RUNNABLE (i.e., when its dependencies are
1095 * If one of the workstations where the task is scheduled on is busy (in
1096 * sequential mode), the task doesn't start.
1097 * Returns whether the task has started.
1099 int __SD_task_try_to_run(SD_task_t task)
1104 SD_workstation_t workstation;
1106 xbt_assert(__SD_task_is_runnable(task),
1107 "Task '%s' is not runnable! Task state: %d",
1108 SD_task_get_name(task), (int)SD_task_get_state(task));
1111 for (i = 0; i < task->workstation_nb; i++) {
1112 can_start = can_start &&
1113 !__SD_workstation_is_busy(task->workstation_list[i]);
1116 XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
1118 if (!can_start) { /* if the task cannot start and is not in the FIFOs yet */
1119 for (i = 0; i < task->workstation_nb; i++) {
1120 workstation = task->workstation_list[i];
1121 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1122 XBT_DEBUG("Pushing task '%s' in the FIFO of workstation '%s'",
1123 SD_task_get_name(task),
1124 SD_workstation_get_name(workstation));
1125 xbt_fifo_push(workstation->task_fifo, task);
1128 __SD_task_set_state(task, SD_IN_FIFO);
1129 xbt_assert(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
1130 SD_task_get_name(task), (int)SD_task_get_state(task));
1131 XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
1133 __SD_task_really_run(task);
1139 /* This function is called by SD_simulate when a task is done.
1140 * It updates task->state and task->action and executes if necessary the tasks
1141 * which were waiting in FIFOs for the end of `task'
1143 void __SD_task_just_done(SD_task_t task)
1146 SD_workstation_t workstation;
1148 SD_task_t candidate;
1149 int candidate_nb = 0;
1150 int candidate_capacity = 8;
1151 SD_task_t *candidates;
1154 xbt_assert(__SD_task_is_running(task),
1155 "The task must be running! Task state: %d",
1156 (int)SD_task_get_state(task));
1157 xbt_assert(task->workstation_list != NULL,
1158 "Task '%s': workstation_list is NULL!",
1159 SD_task_get_name(task));
1162 candidates = xbt_new(SD_task_t, 8);
1164 __SD_task_set_state(task, SD_DONE);
1165 surf_workstation_model->action_unref(task->surf_action);
1166 task->surf_action = NULL;
1168 XBT_DEBUG("Looking for candidates");
1170 /* if the task was executed on sequential workstations,
1171 maybe we can execute the next task of the FIFO for each workstation */
1172 for (i = 0; i < task->workstation_nb; i++) {
1173 workstation = task->workstation_list[i];
1174 XBT_DEBUG("Workstation '%s': access_mode = %d",
1175 SD_workstation_get_name(workstation), (int)workstation->access_mode);
1176 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1177 xbt_assert(workstation->task_fifo != NULL,
1178 "Workstation '%s' has sequential access but no FIFO!",
1179 SD_workstation_get_name(workstation));
1180 xbt_assert(workstation->current_task =
1181 task, "Workstation '%s': current task should be '%s'",
1182 SD_workstation_get_name(workstation),
1183 SD_task_get_name(task));
1185 /* the task is over so we can release the workstation */
1186 workstation->current_task = NULL;
1188 XBT_DEBUG("Getting candidate in FIFO");
1190 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1191 (workstation->task_fifo));
1193 if (candidate != NULL) {
1194 XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
1195 xbt_assert(__SD_task_is_in_fifo(candidate),
1196 "Bad state of candidate '%s': %d",
1197 SD_task_get_name(candidate),
1198 (int)SD_task_get_state(candidate));
1201 XBT_DEBUG("Candidate in fifo: %p", candidate);
1203 /* if there was a task waiting for my place */
1204 if (candidate != NULL) {
1205 /* Unfortunately, we are not sure yet that we can execute the task now,
1206 because the task can be waiting more deeply in some other
1207 workstation's FIFOs ...
1208 So we memorize all candidate tasks, and then we will check for each
1209 candidate whether or not all its workstations are available. */
1211 /* realloc if necessary */
1212 if (candidate_nb == candidate_capacity) {
1213 candidate_capacity *= 2;
1215 xbt_realloc(candidates,
1216 sizeof(SD_task_t) * candidate_capacity);
1219 /* register the candidate */
1220 candidates[candidate_nb++] = candidate;
1221 candidate->fifo_checked = 0;
1226 XBT_DEBUG("Candidates found: %d", candidate_nb);
1228 /* now we check every candidate task */
1229 for (i = 0; i < candidate_nb; i++) {
1230 candidate = candidates[i];
1232 if (candidate->fifo_checked) {
1233 continue; /* we have already evaluated that task */
1236 xbt_assert(__SD_task_is_in_fifo(candidate),
1237 "Bad state of candidate '%s': %d",
1238 SD_task_get_name(candidate), (int)SD_task_get_state(candidate));
1240 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1241 workstation = candidate->workstation_list[j];
1243 /* I can start on this workstation if the workstation is shared
1244 or if I am the first task in the FIFO */
1245 can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS
1247 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1248 (workstation->task_fifo));
1251 XBT_DEBUG("Candidate '%s' can start: %d", SD_task_get_name(candidate),
1254 /* now we are sure that I can start! */
1256 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1257 workstation = candidate->workstation_list[j];
1259 /* update the FIFO */
1260 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1261 candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */
1262 XBT_DEBUG("Head of the FIFO: '%s'",
1264 NULL) ? SD_task_get_name(candidate) : "NULL");
1265 xbt_assert(candidate == candidates[i],
1266 "Error in __SD_task_just_done: bad first task in the FIFO");
1268 } /* for each workstation */
1270 /* finally execute the task */
1271 XBT_DEBUG("Task '%s' state: %d", SD_task_get_name(candidate),
1272 (int)SD_task_get_state(candidate));
1273 __SD_task_really_run(candidate);
1276 ("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
1277 SD_task_get_name(candidate), candidate->state_set,
1278 sd_global->running_task_set, __SD_task_is_running(candidate));
1279 xbt_assert(__SD_task_is_running(candidate),
1280 "Bad state of task '%s': %d",
1281 SD_task_get_name(candidate),
1282 (int)SD_task_get_state(candidate));
1283 XBT_DEBUG("Okay, the task is running.");
1286 candidate->fifo_checked = 1;
1287 } /* for each candidate */
1289 xbt_free(candidates);
1293 * Remove all dependencies associated with a task. This function is called
1294 * when the task is destroyed.
1296 static void __SD_task_remove_dependencies(SD_task_t task)
1298 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
1299 because each one is stored twice */
1300 SD_dependency_t dependency;
1301 while (!xbt_dynar_is_empty(task->tasks_before)) {
1302 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
1303 SD_task_dependency_remove(dependency->src, dependency->dst);
1306 while (!xbt_dynar_is_empty(task->tasks_after)) {
1307 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
1308 SD_task_dependency_remove(dependency->src, dependency->dst);
1313 * \brief Returns the start time of a task
1315 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1317 * \param task: a task
1318 * \return the start time of this task
1320 double SD_task_get_start_time(SD_task_t task)
1322 if (task->surf_action)
1323 return surf_workstation_model->
1324 action_get_start_time(task->surf_action);
1326 return task->start_time;
1330 * \brief Returns the finish time of a task
1332 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1333 * If the state is not completed yet, the returned value is an
1334 * estimation of the task finish time. This value can fluctuate
1335 * until the task is completed.
1337 * \param task: a task
1338 * \return the start time of this task
1340 double SD_task_get_finish_time(SD_task_t task)
1342 if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
1343 return surf_workstation_model->
1344 action_get_finish_time(task->surf_action);
1346 return task->finish_time;
1351 void SD_task_distribute_comp_amdhal(SD_task_t task, int ws_count)
1354 xbt_assert(task->kind == SD_TASK_COMP_PAR_AMDAHL,
1355 "Task %s is not a SD_TASK_COMP_PAR_AMDAHL typed task."
1356 "Cannot use this function.",
1357 SD_task_get_name(task));
1359 task->computation_amount = xbt_new0(double, ws_count);
1360 task->communication_amount = xbt_new0(double, ws_count * ws_count);
1361 task->workstation_nb = ws_count;
1362 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
1364 for(i=0;i<ws_count;i++){
1365 task->computation_amount[i] =
1366 (task->alpha + (1 - task->alpha)/ws_count) * task->amount;
1371 /** @brief Auto-schedules a task.
1373 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1374 * allows to specify the task costs at creation, and decouple them from the
1375 * scheduling process where you just specify which resource should deliver the
1378 * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e()
1379 * or SD_task_create_comp_seq(). Check their definitions for the exact semantic
1383 * We should create tasks kind for the following categories:
1384 * - Point to point communication (done)
1385 * - Sequential computation (done)
1386 * - group communication (redistribution, several kinds)
1387 * - parallel tasks with no internal communication (one kind per speedup
1388 * model such as Amdahl)
1389 * - idem+ internal communication. Task type not enough since we cannot store
1390 * comm cost alongside to comp one)
1392 void SD_task_schedulev(SD_task_t task, int count,
1393 const SD_workstation_t * list)
1396 SD_dependency_t dep;
1398 xbt_assert(task->kind != 0,
1399 "Task %s is not typed. Cannot automatically schedule it.",
1400 SD_task_get_name(task));
1401 switch (task->kind) {
1402 case SD_TASK_COMP_PAR_AMDAHL:
1403 SD_task_distribute_comp_amdhal(task, count);
1404 case SD_TASK_COMM_E2E:
1405 case SD_TASK_COMP_SEQ:
1406 xbt_assert(task->workstation_nb == count,
1407 "Got %d locations, but were expecting %d locations",
1408 count,task->workstation_nb);
1409 for (i = 0; i < count; i++)
1410 task->workstation_list[i] = list[i];
1411 if (SD_task_get_kind(task)== SD_TASK_COMP_SEQ && !task->computation_amount){
1412 /*This task has failed and is rescheduled. Reset the computation amount*/
1413 task->computation_amount = xbt_new0(double, 1);
1414 task->computation_amount[0] = task->remains;
1416 SD_task_do_schedule(task);
1419 xbt_die("Kind of task %s not supported by SD_task_schedulev()",
1420 SD_task_get_name(task));
1422 if (task->kind == SD_TASK_COMM_E2E) {
1423 XBT_VERB("Schedule comm task %s between %s -> %s. It costs %.f bytes",
1424 SD_task_get_name(task),
1425 SD_workstation_get_name(task->workstation_list[0]),
1426 SD_workstation_get_name(task->workstation_list[1]),
1427 task->communication_amount[2]);
1431 /* Iterate over all children and parents being COMM_E2E to say where I am
1432 * located (and start them if runnable) */
1433 if (task->kind == SD_TASK_COMP_SEQ) {
1434 XBT_VERB("Schedule computation task %s on %s. It costs %.f flops",
1435 SD_task_get_name(task),
1436 SD_workstation_get_name(task->workstation_list[0]),
1437 task->computation_amount[0]);
1439 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1440 SD_task_t before = dep->src;
1441 if (before->kind == SD_TASK_COMM_E2E) {
1442 before->workstation_list[1] = task->workstation_list[0];
1444 if (before->workstation_list[0] &&
1445 (__SD_task_is_schedulable(before)
1446 || __SD_task_is_not_scheduled(before))) {
1447 SD_task_do_schedule(before);
1449 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1450 SD_task_get_name(before),
1451 SD_workstation_get_name(before->workstation_list[0]),
1452 SD_workstation_get_name(before->workstation_list[1]),
1453 before->communication_amount[2]);
1457 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1458 SD_task_t after = dep->dst;
1459 if (after->kind == SD_TASK_COMM_E2E) {
1460 after->workstation_list[0] = task->workstation_list[0];
1461 if (after->workstation_list[1]
1462 && (__SD_task_is_not_scheduled(after)
1463 || __SD_task_is_schedulable(after))) {
1464 SD_task_do_schedule(after);
1466 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1467 SD_task_get_name(after),
1468 SD_workstation_get_name(after->workstation_list[0]),
1469 SD_workstation_get_name(after->workstation_list[1]),
1470 after->communication_amount[2]);
1476 /* Iterate over all children and parents being MXN_1D_BLOCK to say where I am
1477 * located (and start them if runnable) */
1478 if (task->kind == SD_TASK_COMP_PAR_AMDAHL) {
1479 XBT_VERB("Schedule computation task %s on %d workstations. %.f flops"
1480 " will be distributed following Amdahl'Law",
1481 SD_task_get_name(task), task->workstation_nb,
1482 task->computation_amount[0]);
1483 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1484 SD_task_t before = dep->src;
1485 if (before->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1486 if (!before->workstation_list){
1487 XBT_VERB("Sender side of Task %s is not scheduled yet",
1488 SD_task_get_name(before));
1489 before->workstation_list = xbt_new0(SD_workstation_t, count);
1490 before->workstation_nb = count;
1491 XBT_VERB("Fill the workstation list with list of Task '%s'",
1492 SD_task_get_name(task));
1493 for (i=0;i<count;i++)
1494 before->workstation_list[i] = task->workstation_list[i];
1496 XBT_VERB("Build communication matrix for task '%s'",
1497 SD_task_get_name(before));
1499 double src_start, src_end, dst_start, dst_end;
1500 src_nb = before->workstation_nb;
1502 before->workstation_list = (SD_workstation_t*) xbt_realloc(
1503 before->workstation_list,
1504 (before->workstation_nb+count)*sizeof(s_SD_workstation_t));
1505 for(i=0; i<count; i++)
1506 before->workstation_list[before->workstation_nb+i] =
1507 task->workstation_list[i];
1509 before->workstation_nb += count;
1511 before->computation_amount = xbt_new0(double,
1512 before->workstation_nb);
1513 before->communication_amount = xbt_new0(double,
1514 before->workstation_nb*
1515 before->workstation_nb);
1517 for(i=0;i<src_nb;i++){
1518 src_start = i*before->amount/src_nb;
1519 src_end = src_start + before->amount/src_nb;
1520 for(j=0; j<dst_nb; j++){
1521 dst_start = j*before->amount/dst_nb;
1522 dst_end = dst_start + before->amount/dst_nb;
1523 XBT_VERB("(%s->%s): (%.2f, %.2f)-> (%.2f, %.2f)",
1524 SD_workstation_get_name(before->workstation_list[i]),
1525 SD_workstation_get_name(before->workstation_list[src_nb+j]),
1526 src_start, src_end, dst_start, dst_end);
1527 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1528 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1530 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1531 MIN(src_end, dst_end) - MAX(src_start, dst_start);
1533 XBT_VERB("==> %.2f",
1534 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1538 if (__SD_task_is_schedulable(before) ||
1539 __SD_task_is_not_scheduled(before)) {
1540 SD_task_do_schedule(before);
1542 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1543 SD_task_get_name(before),before->amount, src_nb, dst_nb);
1548 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1549 SD_task_t after = dep->dst;
1550 if (after->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1551 if (!after->workstation_list){
1552 XBT_VERB("Receiver side of Task '%s' is not scheduled yet",
1553 SD_task_get_name(after));
1554 after->workstation_list = xbt_new0(SD_workstation_t, count);
1555 after->workstation_nb = count;
1556 XBT_VERB("Fill the workstation list with list of Task '%s'",
1557 SD_task_get_name(task));
1558 for (i=0;i<count;i++)
1559 after->workstation_list[i] = task->workstation_list[i];
1562 double src_start, src_end, dst_start, dst_end;
1564 dst_nb = after->workstation_nb;
1565 after->workstation_list = (SD_workstation_t*) xbt_realloc(
1566 after->workstation_list,
1567 (after->workstation_nb+count)*sizeof(s_SD_workstation_t));
1568 for(i=after->workstation_nb - 1; i>=0; i--)
1569 after->workstation_list[count+i] = after->workstation_list[i];
1570 for(i=0; i<count; i++)
1571 after->workstation_list[i] = task->workstation_list[i];
1573 after->workstation_nb += count;
1575 after->computation_amount = xbt_new0(double, after->workstation_nb);
1576 after->communication_amount = xbt_new0(double,
1577 after->workstation_nb*
1578 after->workstation_nb);
1580 for(i=0;i<src_nb;i++){
1581 src_start = i*after->amount/src_nb;
1582 src_end = src_start + after->amount/src_nb;
1583 for(j=0; j<dst_nb; j++){
1584 dst_start = j*after->amount/dst_nb;
1585 dst_end = dst_start + after->amount/dst_nb;
1586 XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)",
1587 i, j, src_start, src_end, dst_start, dst_end);
1588 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1589 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1591 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1592 MIN(src_end, dst_end)- MAX(src_start, dst_start);
1594 XBT_VERB("==> %.2f",
1595 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1599 if (__SD_task_is_schedulable(after) ||
1600 __SD_task_is_not_scheduled(after)) {
1601 SD_task_do_schedule(after);
1603 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1604 SD_task_get_name(after),after->amount, src_nb, dst_nb);
1612 /** @brief autoschedule a task on a list of workstations
1614 * This function is very similar to SD_task_schedulev(),
1615 * but takes the list of workstations to schedule onto as separate parameters.
1616 * It builds a proper vector of workstations and then call SD_task_schedulev()
1618 void SD_task_schedulel(SD_task_t task, int count, ...)
1621 SD_workstation_t *list = xbt_new(SD_workstation_t, count);
1623 va_start(ap, count);
1624 for (i = 0; i < count; i++) {
1625 list[i] = va_arg(ap, SD_workstation_t);
1628 SD_task_schedulev(task, count, list);
1633 * \brief Sets the tracing category of a task.
1635 * This function should be called after the creation of a
1636 * SimDAG task, to define the category of that task. The first
1637 * parameter must contain a task that was created with the
1638 * function #SD_task_create. The second parameter must contain
1639 * a category that was previously declared with the function
1642 * \param task The task to be considered
1643 * \param category the name of the category to be associated to the task
1645 * \see SD_task_get_category, TRACE_category, TRACE_category_with_color
1647 void SD_task_set_category (SD_task_t task, const char *category)
1650 if (!TRACE_is_enabled()) return;
1651 if (task == NULL) return;
1652 if (category == NULL){
1653 if (task->category) xbt_free (task->category);
1654 task->category = NULL;
1656 task->category = xbt_strdup (category);
1662 * \brief Gets the current tracing category of a task.
1664 * \param task The task to be considered
1666 * \see SD_task_set_category
1668 * \return Returns the name of the tracing category of the given task, NULL otherwise
1670 const char *SD_task_get_category (SD_task_t task)
1673 return task->category;