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 alpha parameter of a SD_TASK_COMP_PAR_AMDAH task
457 * \param task a parallel task assuming Amdahl's law as speedup model
458 * \return the alpha parameter (serial part of a task in percent) for this task
460 double SD_task_get_alpha(SD_task_t task)
462 xbt_assert(SD_task_get_kind(task) == SD_TASK_COMP_PAR_AMDAHL,
463 "Alpha parameter is not defined for this kink of task");
469 * \brief Returns the remaining amount work to do till the completion of a task
472 * \return the remaining amount of work (computation or data transfer) of this task
473 * \see SD_task_get_amount()
475 double SD_task_get_remaining_amount(SD_task_t task)
477 if (task->surf_action)
478 return surf_workstation_model->get_remains(task->surf_action);
480 return task->remains;
483 int SD_task_get_kind(SD_task_t task)
488 /** @brief Displays debugging informations about a task */
489 void SD_task_dump(SD_task_t task)
491 unsigned int counter;
492 SD_dependency_t dependency;
495 XBT_INFO("Displaying task %s", SD_task_get_name(task));
496 statename = bprintf("%s %s %s %s %s %s %s %s",
497 (task->state == SD_NOT_SCHEDULED ? "not scheduled" :
499 (task->state == SD_SCHEDULABLE ? "schedulable" : ""),
500 (task->state == SD_SCHEDULED ? "scheduled" : ""),
501 (task->state == SD_RUNNABLE ? "runnable" :
503 (task->state == SD_IN_FIFO ? "in fifo" : ""),
504 (task->state == SD_RUNNING ? "running" : ""),
505 (task->state == SD_DONE ? "done" : ""),
506 (task->state == SD_FAILED ? "failed" : ""));
507 XBT_INFO(" - state: %s", statename);
510 if (task->kind != 0) {
511 switch (task->kind) {
512 case SD_TASK_COMM_E2E:
513 XBT_INFO(" - kind: end-to-end communication");
515 case SD_TASK_COMP_SEQ:
516 XBT_INFO(" - kind: sequential computation");
518 case SD_TASK_COMP_PAR_AMDAHL:
519 XBT_INFO(" - kind: parallel computation following Amdahl's law");
521 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
522 XBT_INFO(" - kind: MxN data redistribution assuming 1D block distribution");
525 XBT_INFO(" - (unknown kind %d)", task->kind);
528 XBT_INFO(" - amount: %.0f", SD_task_get_amount(task));
529 if (task->kind == SD_TASK_COMP_PAR_AMDAHL)
530 XBT_INFO(" - alpha: %.2f", task->alpha);
531 XBT_INFO(" - Dependencies to satisfy: %d", task->unsatisfied_dependencies);
532 if (!xbt_dynar_is_empty(task->tasks_before)) {
533 XBT_INFO(" - pre-dependencies:");
534 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
535 XBT_INFO(" %s", SD_task_get_name(dependency->src));
538 if (!xbt_dynar_is_empty(task->tasks_after)) {
539 XBT_INFO(" - post-dependencies:");
540 xbt_dynar_foreach(task->tasks_after, counter, dependency) {
541 XBT_INFO(" %s", SD_task_get_name(dependency->dst));
546 /** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */
547 void SD_task_dotty(SD_task_t task, void *out)
549 unsigned int counter;
550 SD_dependency_t dependency;
551 fprintf(out, " T%p [label=\"%.20s\"", task, task->name);
552 switch (task->kind) {
553 case SD_TASK_COMM_E2E:
554 case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
555 fprintf(out, ", shape=box");
557 case SD_TASK_COMP_SEQ:
558 case SD_TASK_COMP_PAR_AMDAHL:
559 fprintf(out, ", shape=circle");
562 xbt_die("Unknown task type!");
564 fprintf(out, "];\n");
565 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
566 fprintf(out, " T%p -> T%p;\n", dependency->src, dependency->dst);
570 /* Destroys a dependency between two tasks.
572 static void __SD_task_dependency_destroy(void *dependency)
574 xbt_free(((SD_dependency_t)dependency)->name);
575 xbt_free(dependency);
579 * \brief Adds a dependency between two tasks
581 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
582 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_RUNNABLE.
584 * \param name the name of the new dependency (can be \c NULL)
585 * \param data the user data you want to associate with this dependency (can be \c NULL)
586 * \param src the task which must be executed first
587 * \param dst the task you want to make depend on \a src
588 * \see SD_task_dependency_remove()
590 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
597 SD_dependency_t dependency;
599 dynar = src->tasks_after;
600 length = xbt_dynar_length(dynar);
604 "Cannot add a dependency between task '%s' and itself",
605 SD_task_get_name(src));
607 if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_schedulable(src)
608 && !__SD_task_is_scheduled_or_runnable(src) && !__SD_task_is_running(src))
610 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE"
612 SD_task_get_name(src));
614 if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_schedulable(dst)
615 && !__SD_task_is_scheduled_or_runnable(dst))
617 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE",
618 SD_task_get_name(dst));
620 XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s",
621 SD_task_get_name(src), SD_task_get_name(dst));
622 for (i = 0; i < length && !found; i++) {
623 xbt_dynar_get_cpy(dynar, i, &dependency);
624 found = (dependency->dst == dst);
625 XBT_DEBUG("Dependency %d: dependency->dst = %s", i,
626 SD_task_get_name(dependency->dst));
631 "A dependency already exists between task '%s' and task '%s'",
632 SD_task_get_name(src), SD_task_get_name(dst));
634 dependency = xbt_new(s_SD_dependency_t, 1);
636 dependency->name = xbt_strdup(name); /* xbt_strdup is cleaver enough to deal with NULL args itself */
637 dependency->data = data;
638 dependency->src = src;
639 dependency->dst = dst;
641 /* src must be executed before dst */
642 xbt_dynar_push(src->tasks_after, &dependency);
643 xbt_dynar_push(dst->tasks_before, &dependency);
645 dst->unsatisfied_dependencies++;
648 /* if the task was runnable, then dst->tasks_before is not empty anymore,
649 so we must go back to state SD_SCHEDULED */
650 if (__SD_task_is_runnable(dst)) {
652 ("SD_task_dependency_add: %s was runnable and becomes scheduled!",
653 SD_task_get_name(dst));
654 __SD_task_set_state(dst, SD_SCHEDULED);
658 * \brief Returns the name given as input when dependency has been created..
661 * \param dst a task depending on \a src
664 const char *SD_task_dependency_get_name(SD_task_t src, SD_task_t dst){
666 SD_dependency_t dependency;
668 xbt_dynar_foreach(src->tasks_after, i, dependency){
669 if (dependency->dst == dst)
670 return dependency->name;
676 * \brief Indicates whether there is a dependency between two tasks.
679 * \param dst a task depending on \a src
681 * If src is NULL, checks whether dst has any pre-dependency.
682 * If dst is NULL, checks whether src has any post-dependency.
684 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
686 unsigned int counter;
687 SD_dependency_t dependency;
689 xbt_assert(src != NULL
691 "Invalid parameter: both src and dst are NULL");
695 xbt_dynar_foreach(src->tasks_after, counter, dependency) {
696 if (dependency->dst == dst)
700 return xbt_dynar_length(src->tasks_after);
703 return xbt_dynar_length(dst->tasks_before);
709 * \brief Remove a dependency between two tasks
712 * \param dst a task depending on \a src
713 * \see SD_task_dependency_add()
715 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
722 SD_dependency_t dependency;
724 /* remove the dependency from src->tasks_after */
725 dynar = src->tasks_after;
726 length = xbt_dynar_length(dynar);
728 for (i = 0; i < length && !found; i++) {
729 xbt_dynar_get_cpy(dynar, i, &dependency);
730 if (dependency->dst == dst) {
731 xbt_dynar_remove_at(dynar, i, NULL);
737 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
738 SD_task_get_name(src), SD_task_get_name(dst),
739 SD_task_get_name(dst), SD_task_get_name(src));
741 /* remove the dependency from dst->tasks_before */
742 dynar = dst->tasks_before;
743 length = xbt_dynar_length(dynar);
746 for (i = 0; i < length && !found; i++) {
747 xbt_dynar_get_cpy(dynar, i, &dependency);
748 if (dependency->src == src) {
749 xbt_dynar_remove_at(dynar, i, NULL);
750 __SD_task_dependency_destroy(dependency);
751 dst->unsatisfied_dependencies--;
756 /* should never happen... */
758 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
759 SD_task_get_name(dst), SD_task_get_name(src),
760 SD_task_get_name(src), SD_task_get_name(dst));
762 /* if the task was scheduled and dst->tasks_before is empty now, we can make it runnable */
764 if (dst->unsatisfied_dependencies == 0) {
765 if (__SD_task_is_scheduled(dst))
766 __SD_task_set_state(dst, SD_RUNNABLE);
768 __SD_task_set_state(dst, SD_SCHEDULABLE);
771 if (dst->is_not_ready == 0)
772 __SD_task_set_state(dst, SD_SCHEDULABLE);
774 /* __SD_print_dependencies(src);
775 __SD_print_dependencies(dst); */
779 * \brief Returns the user data associated with a dependency between two tasks
782 * \param dst a task depending on \a src
783 * \return the user data associated with this dependency (can be \c NULL)
784 * \see SD_task_dependency_add()
786 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
793 SD_dependency_t dependency;
795 dynar = src->tasks_after;
796 length = xbt_dynar_length(dynar);
798 for (i = 0; i < length && !found; i++) {
799 xbt_dynar_get_cpy(dynar, i, &dependency);
800 found = (dependency->dst == dst);
803 THROWF(arg_error, 0, "No dependency found between task '%s' and '%s'",
804 SD_task_get_name(src), SD_task_get_name(dst));
805 return dependency->data;
808 /* temporary function for debugging */
809 static void __SD_print_watch_points(SD_task_t task)
811 static const int state_masks[] =
812 { SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNING, SD_RUNNABLE, SD_DONE,
815 static const char *state_names[] =
816 { "schedulable", "scheduled", "running", "runnable", "done",
821 XBT_INFO("Task '%s' watch points (%x): ", SD_task_get_name(task),
825 for (i = 0; i < 5; i++) {
826 if (task->watch_points & state_masks[i])
827 XBT_INFO("%s ", state_names[i]);
832 * \brief Adds a watch point to a task
834 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
835 * task becomes the one given in argument. The
836 * watch point is then automatically removed.
839 * \param state the \ref e_SD_task_state_t "state" you want to watch
840 * (cannot be #SD_NOT_SCHEDULED)
841 * \see SD_task_unwatch()
843 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
845 if (state & SD_NOT_SCHEDULED)
847 "Cannot add a watch point for state SD_NOT_SCHEDULED");
849 task->watch_points = task->watch_points | state;
850 /* __SD_print_watch_points(task); */
854 * \brief Removes a watch point from a task
857 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
858 * \see SD_task_watch()
860 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
862 xbt_assert(state != SD_NOT_SCHEDULED,
863 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
865 task->watch_points = task->watch_points & ~state;
866 /* __SD_print_watch_points(task); */
870 * \brief Returns an approximative estimation of the execution time of a task.
872 * The estimation is very approximative because the value returned is the time
873 * the task would take if it was executed now and if it was the only task.
875 * \param task the task to evaluate
876 * \param workstation_nb number of workstations on which the task would be executed
877 * \param workstation_list the workstations on which the task would be executed
878 * \param computation_amount computation amount for each workstation
879 * \param communication_amount communication amount between each pair of workstations
882 double SD_task_get_execution_time(SD_task_t task,
884 const SD_workstation_t *
886 const double *computation_amount,
887 const double *communication_amount)
889 double time, max_time = 0.0;
891 xbt_assert(workstation_nb > 0, "Invalid parameter");
893 /* the task execution time is the maximum execution time of the parallel tasks */
895 for (i = 0; i < workstation_nb; i++) {
897 if (computation_amount != NULL)
899 SD_workstation_get_computation_time(workstation_list[i],
900 computation_amount[i]);
902 if (communication_amount != NULL)
903 for (j = 0; j < workstation_nb; j++) {
905 SD_route_get_communication_time(workstation_list[i],
907 communication_amount[i *
912 if (time > max_time) {
919 static XBT_INLINE void SD_task_do_schedule(SD_task_t task)
921 if (!__SD_task_is_not_scheduled(task) && !__SD_task_is_schedulable(task))
922 THROWF(arg_error, 0, "Task '%s' has already been scheduled",
923 SD_task_get_name(task));
925 /* update the task state */
926 if (task->unsatisfied_dependencies == 0)
927 __SD_task_set_state(task, SD_RUNNABLE);
929 __SD_task_set_state(task, SD_SCHEDULED);
933 * \brief Schedules a task
935 * The task state must be #SD_NOT_SCHEDULED.
936 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
937 * i.e. when its dependencies are satisfied.
939 * \param task the task you want to schedule
940 * \param workstation_count number of workstations on which the task will be executed
941 * \param workstation_list the workstations on which the task will be executed
942 * \param computation_amount computation amount for each workstation
943 * \param communication_amount communication amount between each pair of workstations
944 * \param rate task execution speed rate
945 * \see SD_task_unschedule()
947 void SD_task_schedule(SD_task_t task, int workstation_count,
948 const SD_workstation_t * workstation_list,
949 const double *computation_amount,
950 const double *communication_amount, double rate)
952 int communication_nb;
953 task->workstation_nb = 0;
955 xbt_assert(workstation_count > 0, "workstation_nb must be positive");
957 task->workstation_nb = workstation_count;
960 if (computation_amount) {
961 task->computation_amount = xbt_realloc(task->computation_amount,
962 sizeof(double) * workstation_count);
963 memcpy(task->computation_amount, computation_amount,
964 sizeof(double) * workstation_count);
966 xbt_free(task->computation_amount);
967 task->computation_amount = NULL;
970 communication_nb = workstation_count * workstation_count;
971 if (communication_amount) {
972 task->communication_amount = xbt_realloc(task->communication_amount,
973 sizeof(double) * communication_nb);
974 memcpy(task->communication_amount, communication_amount,
975 sizeof(double) * communication_nb);
977 xbt_free(task->communication_amount);
978 task->communication_amount = NULL;
981 task->workstation_list =
982 xbt_realloc(task->workstation_list,
983 sizeof(SD_workstation_t) * workstation_count);
984 memcpy(task->workstation_list, workstation_list,
985 sizeof(SD_workstation_t) * workstation_count);
987 SD_task_do_schedule(task);
991 * \brief Unschedules a task
993 * The task state must be #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING or #SD_FAILED.
994 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
995 * Call SD_task_schedule() to schedule it again.
997 * \param task the task you want to unschedule
998 * \see SD_task_schedule()
1000 void SD_task_unschedule(SD_task_t task)
1002 if (task->state_set != sd_global->scheduled_task_set &&
1003 task->state_set != sd_global->runnable_task_set &&
1004 task->state_set != sd_global->running_task_set &&
1005 task->state_set != sd_global->failed_task_set)
1006 THROWF(arg_error, 0,
1007 "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED",
1008 SD_task_get_name(task));
1010 if (__SD_task_is_scheduled_or_runnable(task) /* if the task is scheduled or runnable */
1011 && ((task->kind == SD_TASK_COMP_PAR_AMDAHL) ||
1012 (task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK))) { /* Don't free scheduling data for typed tasks */
1013 __SD_task_destroy_scheduling_data(task);
1014 task->workstation_list=NULL;
1015 task->workstation_nb = 0;
1018 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
1019 surf_workstation_model->action_cancel(task->surf_action);
1021 if (task->unsatisfied_dependencies == 0)
1022 __SD_task_set_state(task, SD_SCHEDULABLE);
1024 __SD_task_set_state(task, SD_NOT_SCHEDULED);
1026 task->remains = task->amount;
1027 task->start_time = -1.0;
1030 /* Destroys the data memorized by SD_task_schedule.
1031 * Task state must be SD_SCHEDULED or SD_RUNNABLE.
1033 static void __SD_task_destroy_scheduling_data(SD_task_t task)
1035 if (!__SD_task_is_scheduled_or_runnable(task)
1036 && !__SD_task_is_in_fifo(task))
1037 THROWF(arg_error, 0,
1038 "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
1039 SD_task_get_name(task));
1041 xbt_free(task->computation_amount);
1042 xbt_free(task->communication_amount);
1043 task->computation_amount = task->communication_amount = NULL;
1046 /* Runs a task. This function is directly called by __SD_task_try_to_run if
1047 * the task doesn't have to wait in FIFOs. Otherwise, it is called by
1048 * __SD_task_just_done when the task gets out of its FIFOs.
1050 void __SD_task_really_run(SD_task_t task)
1054 void **surf_workstations;
1056 xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
1057 "Task '%s' is not runnable or in a fifo! Task state: %d",
1058 SD_task_get_name(task), (int)SD_task_get_state(task));
1059 xbt_assert(task->workstation_list != NULL,
1060 "Task '%s': workstation_list is NULL!",
1061 SD_task_get_name(task));
1063 XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
1064 int workstation_nb = task->workstation_nb;
1066 /* set this task as current task for the workstations in sequential mode */
1067 for (i = 0; i < workstation_nb; i++) {
1068 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
1069 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1070 SD_workstation_priv(task->workstation_list[i])->current_task = task;
1071 xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
1072 "The workstation should be busy now");
1076 XBT_DEBUG("Task '%s' set as current task for its workstations",
1077 SD_task_get_name(task));
1079 /* start the task */
1081 /* we have to create a Surf workstation array instead of the SimDag
1082 * workstation array */
1083 surf_workstations = xbt_new(void *, workstation_nb);
1085 for (i = 0; i < workstation_nb; i++)
1086 surf_workstations[i] = task->workstation_list[i];
1088 double *computation_amount = xbt_new0(double, workstation_nb);
1089 double *communication_amount = xbt_new0(double, workstation_nb * workstation_nb);
1092 if(task->computation_amount)
1093 memcpy(computation_amount, task->computation_amount, sizeof(double) *
1095 if(task->communication_amount)
1096 memcpy(communication_amount, task->communication_amount,
1097 sizeof(double) * workstation_nb * workstation_nb);
1100 surf_workstation_model->extension.
1101 workstation.execute_parallel_task(workstation_nb,
1104 communication_amount,
1107 surf_workstation_model->action_data_set(task->surf_action, task);
1109 XBT_DEBUG("surf_action = %p", task->surf_action);
1113 TRACE_surf_action(task->surf_action, task->category);
1116 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
1117 __SD_task_set_state(task, SD_RUNNING);
1118 xbt_assert(__SD_task_is_running(task), "Bad state of task '%s': %d",
1119 SD_task_get_name(task), (int)SD_task_get_state(task));
1123 /* Tries to run a task. This function is called by SD_simulate() when a
1124 * scheduled task becomes SD_RUNNABLE (i.e., when its dependencies are
1126 * If one of the workstations where the task is scheduled on is busy (in
1127 * sequential mode), the task doesn't start.
1128 * Returns whether the task has started.
1130 int __SD_task_try_to_run(SD_task_t task)
1135 SD_workstation_t workstation;
1137 xbt_assert(__SD_task_is_runnable(task),
1138 "Task '%s' is not runnable! Task state: %d",
1139 SD_task_get_name(task), (int)SD_task_get_state(task));
1142 for (i = 0; i < task->workstation_nb; i++) {
1143 can_start = can_start &&
1144 !__SD_workstation_is_busy(task->workstation_list[i]);
1147 XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
1149 if (!can_start) { /* if the task cannot start and is not in the FIFOs yet */
1150 for (i = 0; i < task->workstation_nb; i++) {
1151 workstation = task->workstation_list[i];
1152 if (SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1153 XBT_DEBUG("Pushing task '%s' in the FIFO of workstation '%s'",
1154 SD_task_get_name(task),
1155 SD_workstation_get_name(workstation));
1156 xbt_fifo_push(SD_workstation_priv(workstation)->task_fifo, task);
1159 __SD_task_set_state(task, SD_IN_FIFO);
1160 xbt_assert(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
1161 SD_task_get_name(task), (int)SD_task_get_state(task));
1162 XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
1164 __SD_task_really_run(task);
1170 /* This function is called by SD_simulate when a task is done.
1171 * It updates task->state and task->action and executes if necessary the tasks
1172 * which were waiting in FIFOs for the end of `task'
1174 void __SD_task_just_done(SD_task_t task)
1177 SD_workstation_t workstation;
1179 SD_task_t candidate;
1180 int candidate_nb = 0;
1181 int candidate_capacity = 8;
1182 SD_task_t *candidates;
1185 xbt_assert(__SD_task_is_running(task),
1186 "The task must be running! Task state: %d",
1187 (int)SD_task_get_state(task));
1188 xbt_assert(task->workstation_list != NULL,
1189 "Task '%s': workstation_list is NULL!",
1190 SD_task_get_name(task));
1193 candidates = xbt_new(SD_task_t, 8);
1195 __SD_task_set_state(task, SD_DONE);
1196 surf_workstation_model->action_unref(task->surf_action);
1197 task->surf_action = NULL;
1199 XBT_DEBUG("Looking for candidates");
1201 /* if the task was executed on sequential workstations,
1202 maybe we can execute the next task of the FIFO for each workstation */
1203 for (i = 0; i < task->workstation_nb; i++) {
1204 workstation = task->workstation_list[i];
1205 XBT_DEBUG("Workstation '%s': access_mode = %d",
1206 SD_workstation_get_name(workstation), (int)SD_workstation_priv(workstation)->access_mode);
1207 if (SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1208 xbt_assert(SD_workstation_priv(workstation)->task_fifo != NULL,
1209 "Workstation '%s' has sequential access but no FIFO!",
1210 SD_workstation_get_name(workstation));
1211 xbt_assert(SD_workstation_priv(workstation)->current_task =
1212 task, "Workstation '%s': current task should be '%s'",
1213 SD_workstation_get_name(workstation),
1214 SD_task_get_name(task));
1216 /* the task is over so we can release the workstation */
1217 SD_workstation_priv(workstation)->current_task = NULL;
1219 XBT_DEBUG("Getting candidate in FIFO");
1221 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1222 (SD_workstation_priv(workstation)->task_fifo));
1224 if (candidate != NULL) {
1225 XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
1226 xbt_assert(__SD_task_is_in_fifo(candidate),
1227 "Bad state of candidate '%s': %d",
1228 SD_task_get_name(candidate),
1229 (int)SD_task_get_state(candidate));
1232 XBT_DEBUG("Candidate in fifo: %p", candidate);
1234 /* if there was a task waiting for my place */
1235 if (candidate != NULL) {
1236 /* Unfortunately, we are not sure yet that we can execute the task now,
1237 because the task can be waiting more deeply in some other
1238 workstation's FIFOs ...
1239 So we memorize all candidate tasks, and then we will check for each
1240 candidate whether or not all its workstations are available. */
1242 /* realloc if necessary */
1243 if (candidate_nb == candidate_capacity) {
1244 candidate_capacity *= 2;
1246 xbt_realloc(candidates,
1247 sizeof(SD_task_t) * candidate_capacity);
1250 /* register the candidate */
1251 candidates[candidate_nb++] = candidate;
1252 candidate->fifo_checked = 0;
1257 XBT_DEBUG("Candidates found: %d", candidate_nb);
1259 /* now we check every candidate task */
1260 for (i = 0; i < candidate_nb; i++) {
1261 candidate = candidates[i];
1263 if (candidate->fifo_checked) {
1264 continue; /* we have already evaluated that task */
1267 xbt_assert(__SD_task_is_in_fifo(candidate),
1268 "Bad state of candidate '%s': %d",
1269 SD_task_get_name(candidate), (int)SD_task_get_state(candidate));
1271 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1272 workstation = candidate->workstation_list[j];
1274 /* I can start on this workstation if the workstation is shared
1275 or if I am the first task in the FIFO */
1276 can_start = SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SHARED_ACCESS
1278 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1279 (SD_workstation_priv(workstation)->task_fifo));
1282 XBT_DEBUG("Candidate '%s' can start: %d", SD_task_get_name(candidate),
1285 /* now we are sure that I can start! */
1287 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1288 workstation = candidate->workstation_list[j];
1290 /* update the FIFO */
1291 if (SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1292 candidate = xbt_fifo_shift(SD_workstation_priv(workstation)->task_fifo); /* the return value is stored just for debugging */
1293 XBT_DEBUG("Head of the FIFO: '%s'",
1295 NULL) ? SD_task_get_name(candidate) : "NULL");
1296 xbt_assert(candidate == candidates[i],
1297 "Error in __SD_task_just_done: bad first task in the FIFO");
1299 } /* for each workstation */
1301 /* finally execute the task */
1302 XBT_DEBUG("Task '%s' state: %d", SD_task_get_name(candidate),
1303 (int)SD_task_get_state(candidate));
1304 __SD_task_really_run(candidate);
1307 ("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
1308 SD_task_get_name(candidate), candidate->state_set,
1309 sd_global->running_task_set, __SD_task_is_running(candidate));
1310 xbt_assert(__SD_task_is_running(candidate),
1311 "Bad state of task '%s': %d",
1312 SD_task_get_name(candidate),
1313 (int)SD_task_get_state(candidate));
1314 XBT_DEBUG("Okay, the task is running.");
1317 candidate->fifo_checked = 1;
1318 } /* for each candidate */
1320 xbt_free(candidates);
1324 * Remove all dependencies associated with a task. This function is called
1325 * when the task is destroyed.
1327 static void __SD_task_remove_dependencies(SD_task_t task)
1329 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
1330 because each one is stored twice */
1331 SD_dependency_t dependency;
1332 while (!xbt_dynar_is_empty(task->tasks_before)) {
1333 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
1334 SD_task_dependency_remove(dependency->src, dependency->dst);
1337 while (!xbt_dynar_is_empty(task->tasks_after)) {
1338 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
1339 SD_task_dependency_remove(dependency->src, dependency->dst);
1344 * \brief Returns the start time of a task
1346 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1348 * \param task: a task
1349 * \return the start time of this task
1351 double SD_task_get_start_time(SD_task_t task)
1353 if (task->surf_action)
1354 return surf_workstation_model->
1355 action_get_start_time(task->surf_action);
1357 return task->start_time;
1361 * \brief Returns the finish time of a task
1363 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1364 * If the state is not completed yet, the returned value is an
1365 * estimation of the task finish time. This value can fluctuate
1366 * until the task is completed.
1368 * \param task: a task
1369 * \return the start time of this task
1371 double SD_task_get_finish_time(SD_task_t task)
1373 if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
1374 return surf_workstation_model->
1375 action_get_finish_time(task->surf_action);
1377 return task->finish_time;
1382 void SD_task_distribute_comp_amdhal(SD_task_t task, int ws_count)
1385 xbt_assert(task->kind == SD_TASK_COMP_PAR_AMDAHL,
1386 "Task %s is not a SD_TASK_COMP_PAR_AMDAHL typed task."
1387 "Cannot use this function.",
1388 SD_task_get_name(task));
1389 task->computation_amount = xbt_new0(double, ws_count);
1390 task->communication_amount = xbt_new0(double, ws_count * ws_count);
1391 if (task->workstation_list)
1392 xbt_free(task->workstation_list);
1393 task->workstation_nb = ws_count;
1394 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
1396 for(i=0;i<ws_count;i++){
1397 task->computation_amount[i] =
1398 (task->alpha + (1 - task->alpha)/ws_count) * task->amount;
1403 /** @brief Auto-schedules a task.
1405 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1406 * allows to specify the task costs at creation, and decouple them from the
1407 * scheduling process where you just specify which resource should deliver the
1410 * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e()
1411 * or SD_task_create_comp_seq(). Check their definitions for the exact semantic
1415 * We should create tasks kind for the following categories:
1416 * - Point to point communication (done)
1417 * - Sequential computation (done)
1418 * - group communication (redistribution, several kinds)
1419 * - parallel tasks with no internal communication (one kind per speedup
1420 * model such as Amdahl)
1421 * - idem+ internal communication. Task type not enough since we cannot store
1422 * comm cost alongside to comp one)
1424 void SD_task_schedulev(SD_task_t task, int count,
1425 const SD_workstation_t * list)
1428 SD_dependency_t dep;
1430 xbt_assert(task->kind != 0,
1431 "Task %s is not typed. Cannot automatically schedule it.",
1432 SD_task_get_name(task));
1433 switch (task->kind) {
1434 case SD_TASK_COMP_PAR_AMDAHL:
1435 SD_task_distribute_comp_amdhal(task, count);
1436 case SD_TASK_COMM_E2E:
1437 case SD_TASK_COMP_SEQ:
1438 xbt_assert(task->workstation_nb == count,
1439 "Got %d locations, but were expecting %d locations",
1440 count,task->workstation_nb);
1441 for (i = 0; i < count; i++)
1442 task->workstation_list[i] = list[i];
1443 if (SD_task_get_kind(task)== SD_TASK_COMP_SEQ && !task->computation_amount){
1444 /*This task has failed and is rescheduled. Reset the computation amount*/
1445 task->computation_amount = xbt_new0(double, 1);
1446 task->computation_amount[0] = task->remains;
1448 SD_task_do_schedule(task);
1451 xbt_die("Kind of task %s not supported by SD_task_schedulev()",
1452 SD_task_get_name(task));
1454 if (task->kind == SD_TASK_COMM_E2E) {
1455 XBT_VERB("Schedule comm task %s between %s -> %s. It costs %.f bytes",
1456 SD_task_get_name(task),
1457 SD_workstation_get_name(task->workstation_list[0]),
1458 SD_workstation_get_name(task->workstation_list[1]),
1459 task->communication_amount[2]);
1463 /* Iterate over all children and parents being COMM_E2E to say where I am
1464 * located (and start them if runnable) */
1465 if (task->kind == SD_TASK_COMP_SEQ) {
1466 XBT_VERB("Schedule computation task %s on %s. It costs %.f flops",
1467 SD_task_get_name(task),
1468 SD_workstation_get_name(task->workstation_list[0]),
1469 task->computation_amount[0]);
1471 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1472 SD_task_t before = dep->src;
1473 if (before->kind == SD_TASK_COMM_E2E) {
1474 before->workstation_list[1] = task->workstation_list[0];
1476 if (before->workstation_list[0] &&
1477 (__SD_task_is_schedulable(before)
1478 || __SD_task_is_not_scheduled(before))) {
1479 SD_task_do_schedule(before);
1481 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1482 SD_task_get_name(before),
1483 SD_workstation_get_name(before->workstation_list[0]),
1484 SD_workstation_get_name(before->workstation_list[1]),
1485 before->communication_amount[2]);
1489 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1490 SD_task_t after = dep->dst;
1491 if (after->kind == SD_TASK_COMM_E2E) {
1492 after->workstation_list[0] = task->workstation_list[0];
1493 if (after->workstation_list[1]
1494 && (__SD_task_is_not_scheduled(after)
1495 || __SD_task_is_schedulable(after))) {
1496 SD_task_do_schedule(after);
1498 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1499 SD_task_get_name(after),
1500 SD_workstation_get_name(after->workstation_list[0]),
1501 SD_workstation_get_name(after->workstation_list[1]),
1502 after->communication_amount[2]);
1508 /* Iterate over all children and parents being MXN_1D_BLOCK to say where I am
1509 * located (and start them if runnable) */
1510 if (task->kind == SD_TASK_COMP_PAR_AMDAHL) {
1511 XBT_VERB("Schedule computation task %s on %d workstations. %.f flops"
1512 " will be distributed following Amdahl'Law",
1513 SD_task_get_name(task), task->workstation_nb,
1514 task->computation_amount[0]);
1515 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1516 SD_task_t before = dep->src;
1517 if (before->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1518 if (!before->workstation_list){
1519 XBT_VERB("Sender side of Task %s is not scheduled yet",
1520 SD_task_get_name(before));
1521 before->workstation_list = xbt_new0(SD_workstation_t, count);
1522 before->workstation_nb = count;
1523 XBT_VERB("Fill the workstation list with list of Task '%s'",
1524 SD_task_get_name(task));
1525 for (i=0;i<count;i++)
1526 before->workstation_list[i] = task->workstation_list[i];
1528 XBT_VERB("Build communication matrix for task '%s'",
1529 SD_task_get_name(before));
1531 double src_start, src_end, dst_start, dst_end;
1532 src_nb = before->workstation_nb;
1534 before->workstation_list = (SD_workstation_t*) xbt_realloc(
1535 before->workstation_list,
1536 (before->workstation_nb+count)*sizeof(s_SD_workstation_t));
1537 for(i=0; i<count; i++)
1538 before->workstation_list[before->workstation_nb+i] =
1539 task->workstation_list[i];
1541 before->workstation_nb += count;
1542 if (before->computation_amount)
1543 xbt_free(before->computation_amount);
1544 if (before->communication_amount)
1545 xbt_free(before->communication_amount);
1547 before->computation_amount = xbt_new0(double,
1548 before->workstation_nb);
1549 before->communication_amount = xbt_new0(double,
1550 before->workstation_nb*
1551 before->workstation_nb);
1553 for(i=0;i<src_nb;i++){
1554 src_start = i*before->amount/src_nb;
1555 src_end = src_start + before->amount/src_nb;
1556 for(j=0; j<dst_nb; j++){
1557 dst_start = j*before->amount/dst_nb;
1558 dst_end = dst_start + before->amount/dst_nb;
1559 XBT_VERB("(%s->%s): (%.2f, %.2f)-> (%.2f, %.2f)",
1560 SD_workstation_get_name(before->workstation_list[i]),
1561 SD_workstation_get_name(before->workstation_list[src_nb+j]),
1562 src_start, src_end, dst_start, dst_end);
1563 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1564 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1566 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1567 MIN(src_end, dst_end) - MAX(src_start, dst_start);
1569 XBT_VERB("==> %.2f",
1570 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1574 if (__SD_task_is_schedulable(before) ||
1575 __SD_task_is_not_scheduled(before)) {
1576 SD_task_do_schedule(before);
1578 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1579 SD_task_get_name(before),before->amount, src_nb, dst_nb);
1584 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1585 SD_task_t after = dep->dst;
1586 if (after->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1587 if (!after->workstation_list){
1588 XBT_VERB("Receiver side of Task '%s' is not scheduled yet",
1589 SD_task_get_name(after));
1590 after->workstation_list = xbt_new0(SD_workstation_t, count);
1591 after->workstation_nb = count;
1592 XBT_VERB("Fill the workstation list with list of Task '%s'",
1593 SD_task_get_name(task));
1594 for (i=0;i<count;i++)
1595 after->workstation_list[i] = task->workstation_list[i];
1598 double src_start, src_end, dst_start, dst_end;
1600 dst_nb = after->workstation_nb;
1601 after->workstation_list = (SD_workstation_t*) xbt_realloc(
1602 after->workstation_list,
1603 (after->workstation_nb+count)*sizeof(s_SD_workstation_t));
1604 for(i=after->workstation_nb - 1; i>=0; i--)
1605 after->workstation_list[count+i] = after->workstation_list[i];
1606 for(i=0; i<count; i++)
1607 after->workstation_list[i] = task->workstation_list[i];
1609 after->workstation_nb += count;
1611 if (after->computation_amount)
1612 xbt_free(after->computation_amount);
1613 if (after->communication_amount)
1614 xbt_free(after->communication_amount);
1616 after->computation_amount = xbt_new0(double, after->workstation_nb);
1617 after->communication_amount = xbt_new0(double,
1618 after->workstation_nb*
1619 after->workstation_nb);
1621 for(i=0;i<src_nb;i++){
1622 src_start = i*after->amount/src_nb;
1623 src_end = src_start + after->amount/src_nb;
1624 for(j=0; j<dst_nb; j++){
1625 dst_start = j*after->amount/dst_nb;
1626 dst_end = dst_start + after->amount/dst_nb;
1627 XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)",
1628 i, j, src_start, src_end, dst_start, dst_end);
1629 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1630 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1632 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1633 MIN(src_end, dst_end)- MAX(src_start, dst_start);
1635 XBT_VERB("==> %.2f",
1636 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1640 if (__SD_task_is_schedulable(after) ||
1641 __SD_task_is_not_scheduled(after)) {
1642 SD_task_do_schedule(after);
1644 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1645 SD_task_get_name(after),after->amount, src_nb, dst_nb);
1653 /** @brief autoschedule a task on a list of workstations
1655 * This function is very similar to SD_task_schedulev(),
1656 * but takes the list of workstations to schedule onto as separate parameters.
1657 * It builds a proper vector of workstations and then call SD_task_schedulev()
1659 void SD_task_schedulel(SD_task_t task, int count, ...)
1662 SD_workstation_t *list = xbt_new(SD_workstation_t, count);
1664 va_start(ap, count);
1665 for (i = 0; i < count; i++) {
1666 list[i] = va_arg(ap, SD_workstation_t);
1669 SD_task_schedulev(task, count, list);
1674 * \brief Sets the tracing category of a task.
1676 * This function should be called after the creation of a
1677 * SimDAG task, to define the category of that task. The first
1678 * parameter must contain a task that was created with the
1679 * function #SD_task_create. The second parameter must contain
1680 * a category that was previously declared with the function
1683 * \param task The task to be considered
1684 * \param category the name of the category to be associated to the task
1686 * \see SD_task_get_category, TRACE_category, TRACE_category_with_color
1688 void SD_task_set_category (SD_task_t task, const char *category)
1691 if (!TRACE_is_enabled()) return;
1692 if (task == NULL) return;
1693 if (category == NULL){
1694 if (task->category) xbt_free (task->category);
1695 task->category = NULL;
1697 task->category = xbt_strdup (category);
1703 * \brief Gets the current tracing category of a task.
1705 * \param task The task to be considered
1707 * \see SD_task_set_category
1709 * \return Returns the name of the tracing category of the given task, NULL otherwise
1711 const char *SD_task_get_category (SD_task_t task)
1714 return task->category;