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");
508 XBT_INFO(" - (unknown kind %d)", task->kind);
511 XBT_INFO(" - amount: %.0f", SD_task_get_amount(task));
512 XBT_INFO(" - Dependencies to satisfy: %u", task->unsatisfied_dependencies);
513 if (!xbt_dynar_is_empty(task->tasks_before)) {
514 XBT_INFO(" - pre-dependencies:");
515 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
516 XBT_INFO(" %s", SD_task_get_name(dependency->src));
519 if (!xbt_dynar_is_empty(task->tasks_after)) {
520 XBT_INFO(" - post-dependencies:");
521 xbt_dynar_foreach(task->tasks_after, counter, dependency) {
522 XBT_INFO(" %s", SD_task_get_name(dependency->dst));
527 /** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */
528 void SD_task_dotty(SD_task_t task, void *out)
530 unsigned int counter;
531 SD_dependency_t dependency;
532 fprintf(out, " T%p [label=\"%.20s\"", task, task->name);
533 switch (task->kind) {
534 case SD_TASK_COMM_E2E:
535 fprintf(out, ", shape=box");
537 case SD_TASK_COMP_SEQ:
538 fprintf(out, ", shape=circle");
541 xbt_die("Unknown task type!");
543 fprintf(out, "];\n");
544 xbt_dynar_foreach(task->tasks_before, counter, dependency) {
545 fprintf(out, " T%p -> T%p;\n", dependency->src, dependency->dst);
549 /* Destroys a dependency between two tasks.
551 static void __SD_task_dependency_destroy(void *dependency)
553 xbt_free(((SD_dependency_t)dependency)->name);
554 xbt_free(dependency);
558 * \brief Adds a dependency between two tasks
560 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
561 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_RUNNABLE.
563 * \param name the name of the new dependency (can be \c NULL)
564 * \param data the user data you want to associate with this dependency (can be \c NULL)
565 * \param src the task which must be executed first
566 * \param dst the task you want to make depend on \a src
567 * \see SD_task_dependency_remove()
569 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
576 SD_dependency_t dependency;
578 dynar = src->tasks_after;
579 length = xbt_dynar_length(dynar);
583 "Cannot add a dependency between task '%s' and itself",
584 SD_task_get_name(src));
586 if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_schedulable(src)
587 && !__SD_task_is_scheduled_or_runnable(src) && !__SD_task_is_running(src))
589 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE"
591 SD_task_get_name(src));
593 if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_schedulable(dst)
594 && !__SD_task_is_scheduled_or_runnable(dst))
596 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED or SD_RUNNABLE",
597 SD_task_get_name(dst));
599 XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s",
600 SD_task_get_name(src), SD_task_get_name(dst));
601 for (i = 0; i < length && !found; i++) {
602 xbt_dynar_get_cpy(dynar, i, &dependency);
603 found = (dependency->dst == dst);
604 XBT_DEBUG("Dependency %d: dependency->dst = %s", i,
605 SD_task_get_name(dependency->dst));
610 "A dependency already exists between task '%s' and task '%s'",
611 SD_task_get_name(src), SD_task_get_name(dst));
613 dependency = xbt_new(s_SD_dependency_t, 1);
615 dependency->name = xbt_strdup(name); /* xbt_strdup is cleaver enough to deal with NULL args itself */
616 dependency->data = data;
617 dependency->src = src;
618 dependency->dst = dst;
620 /* src must be executed before dst */
621 xbt_dynar_push(src->tasks_after, &dependency);
622 xbt_dynar_push(dst->tasks_before, &dependency);
624 dst->unsatisfied_dependencies++;
627 /* if the task was runnable, then dst->tasks_before is not empty anymore,
628 so we must go back to state SD_SCHEDULED */
629 if (__SD_task_is_runnable(dst)) {
631 ("SD_task_dependency_add: %s was runnable and becomes scheduled!",
632 SD_task_get_name(dst));
633 __SD_task_set_state(dst, SD_SCHEDULED);
636 /* __SD_print_dependencies(src);
637 __SD_print_dependencies(dst); */
641 * \brief Indicates whether there is a dependency between two tasks.
644 * \param dst a task depending on \a src
646 * If src is NULL, checks whether dst has any pre-dependency.
647 * If dst is NULL, checks whether src has any post-dependency.
649 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
651 unsigned int counter;
652 SD_dependency_t dependency;
654 xbt_assert(src != NULL
656 "Invalid parameter: both src and dst are NULL");
660 xbt_dynar_foreach(src->tasks_after, counter, dependency) {
661 if (dependency->dst == dst)
665 return xbt_dynar_length(src->tasks_after);
668 return xbt_dynar_length(dst->tasks_before);
674 * \brief Remove a dependency between two tasks
677 * \param dst a task depending on \a src
678 * \see SD_task_dependency_add()
680 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
687 SD_dependency_t dependency;
689 /* remove the dependency from src->tasks_after */
690 dynar = src->tasks_after;
691 length = xbt_dynar_length(dynar);
693 for (i = 0; i < length && !found; i++) {
694 xbt_dynar_get_cpy(dynar, i, &dependency);
695 if (dependency->dst == dst) {
696 xbt_dynar_remove_at(dynar, i, NULL);
702 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
703 SD_task_get_name(src), SD_task_get_name(dst),
704 SD_task_get_name(dst), SD_task_get_name(src));
706 /* remove the dependency from dst->tasks_before */
707 dynar = dst->tasks_before;
708 length = xbt_dynar_length(dynar);
711 for (i = 0; i < length && !found; i++) {
712 xbt_dynar_get_cpy(dynar, i, &dependency);
713 if (dependency->src == src) {
714 xbt_dynar_remove_at(dynar, i, NULL);
715 __SD_task_dependency_destroy(dependency);
716 dst->unsatisfied_dependencies--;
721 /* should never happen... */
723 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
724 SD_task_get_name(dst), SD_task_get_name(src),
725 SD_task_get_name(src), SD_task_get_name(dst));
727 /* if the task was scheduled and dst->tasks_before is empty now, we can make it runnable */
729 if (dst->unsatisfied_dependencies == 0) {
730 if (__SD_task_is_scheduled(dst))
731 __SD_task_set_state(dst, SD_RUNNABLE);
733 __SD_task_set_state(dst, SD_SCHEDULABLE);
736 if (dst->is_not_ready == 0)
737 __SD_task_set_state(dst, SD_SCHEDULABLE);
739 /* __SD_print_dependencies(src);
740 __SD_print_dependencies(dst); */
744 * \brief Returns the user data associated with a dependency between two tasks
747 * \param dst a task depending on \a src
748 * \return the user data associated with this dependency (can be \c NULL)
749 * \see SD_task_dependency_add()
751 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
758 SD_dependency_t dependency;
760 dynar = src->tasks_after;
761 length = xbt_dynar_length(dynar);
763 for (i = 0; i < length && !found; i++) {
764 xbt_dynar_get_cpy(dynar, i, &dependency);
765 found = (dependency->dst == dst);
768 THROWF(arg_error, 0, "No dependency found between task '%s' and '%s'",
769 SD_task_get_name(src), SD_task_get_name(dst));
770 return dependency->data;
773 /* temporary function for debugging */
774 static void __SD_print_watch_points(SD_task_t task)
776 static const int state_masks[] =
777 { SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNING, SD_RUNNABLE, SD_DONE,
780 static const char *state_names[] =
781 { "schedulable", "scheduled", "running", "runnable", "done",
786 XBT_INFO("Task '%s' watch points (%x): ", SD_task_get_name(task),
790 for (i = 0; i < 5; i++) {
791 if (task->watch_points & state_masks[i])
792 XBT_INFO("%s ", state_names[i]);
797 * \brief Adds a watch point to a task
799 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
800 * task becomes the one given in argument. The
801 * watch point is then automatically removed.
804 * \param state the \ref e_SD_task_state_t "state" you want to watch
805 * (cannot be #SD_NOT_SCHEDULED)
806 * \see SD_task_unwatch()
808 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
810 if (state & SD_NOT_SCHEDULED)
812 "Cannot add a watch point for state SD_NOT_SCHEDULED");
814 task->watch_points = task->watch_points | state;
815 /* __SD_print_watch_points(task); */
819 * \brief Removes a watch point from a task
822 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
823 * \see SD_task_watch()
825 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
827 xbt_assert(state != SD_NOT_SCHEDULED,
828 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
830 task->watch_points = task->watch_points & ~state;
831 /* __SD_print_watch_points(task); */
835 * \brief Returns an approximative estimation of the execution time of a task.
837 * The estimation is very approximative because the value returned is the time
838 * the task would take if it was executed now and if it was the only task.
840 * \param task the task to evaluate
841 * \param workstation_nb number of workstations on which the task would be executed
842 * \param workstation_list the workstations on which the task would be executed
843 * \param computation_amount computation amount for each workstation
844 * \param communication_amount communication amount between each pair of workstations
847 double SD_task_get_execution_time(SD_task_t task,
849 const SD_workstation_t *
851 const double *computation_amount,
852 const double *communication_amount)
854 double time, max_time = 0.0;
856 xbt_assert(workstation_nb > 0, "Invalid parameter");
858 /* the task execution time is the maximum execution time of the parallel tasks */
860 for (i = 0; i < workstation_nb; i++) {
862 if (computation_amount != NULL)
864 SD_workstation_get_computation_time(workstation_list[i],
865 computation_amount[i]);
867 if (communication_amount != NULL)
868 for (j = 0; j < workstation_nb; j++) {
870 SD_route_get_communication_time(workstation_list[i],
872 communication_amount[i *
877 if (time > max_time) {
884 static XBT_INLINE void SD_task_do_schedule(SD_task_t task)
886 if (!__SD_task_is_not_scheduled(task) && !__SD_task_is_schedulable(task))
887 THROWF(arg_error, 0, "Task '%s' has already been scheduled",
888 SD_task_get_name(task));
890 /* update the task state */
891 if (task->unsatisfied_dependencies == 0)
892 __SD_task_set_state(task, SD_RUNNABLE);
894 __SD_task_set_state(task, SD_SCHEDULED);
898 * \brief Schedules a task
900 * The task state must be #SD_NOT_SCHEDULED.
901 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
902 * i.e. when its dependencies are satisfied.
904 * \param task the task you want to schedule
905 * \param workstation_count number of workstations on which the task will be executed
906 * \param workstation_list the workstations on which the task will be executed
907 * \param computation_amount computation amount for each workstation
908 * \param communication_amount communication amount between each pair of workstations
909 * \param rate task execution speed rate
910 * \see SD_task_unschedule()
912 void SD_task_schedule(SD_task_t task, int workstation_count,
913 const SD_workstation_t * workstation_list,
914 const double *computation_amount,
915 const double *communication_amount, double rate)
917 int communication_nb;
918 task->workstation_nb = 0;
920 xbt_assert(workstation_count > 0, "workstation_nb must be positive");
922 task->workstation_nb = workstation_count;
925 if (computation_amount) {
926 task->computation_amount = xbt_realloc(task->computation_amount,
927 sizeof(double) * workstation_count);
928 memcpy(task->computation_amount, computation_amount,
929 sizeof(double) * workstation_count);
931 xbt_free(task->computation_amount);
932 task->computation_amount = NULL;
935 communication_nb = workstation_count * workstation_count;
936 if (communication_amount) {
937 task->communication_amount = xbt_realloc(task->communication_amount,
938 sizeof(double) * communication_nb);
939 memcpy(task->communication_amount, communication_amount,
940 sizeof(double) * communication_nb);
942 xbt_free(task->communication_amount);
943 task->communication_amount = NULL;
946 task->workstation_list =
947 xbt_realloc(task->workstation_list,
948 sizeof(SD_workstation_t) * workstation_count);
949 memcpy(task->workstation_list, workstation_list,
950 sizeof(SD_workstation_t) * workstation_count);
952 SD_task_do_schedule(task);
956 * \brief Unschedules a task
958 * The task state must be #SD_SCHEDULED, #SD_RUNNABLE, #SD_RUNNING or #SD_FAILED.
959 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
960 * Call SD_task_schedule() to schedule it again.
962 * \param task the task you want to unschedule
963 * \see SD_task_schedule()
965 void SD_task_unschedule(SD_task_t task)
967 if (task->state_set != sd_global->scheduled_task_set &&
968 task->state_set != sd_global->runnable_task_set &&
969 task->state_set != sd_global->running_task_set &&
970 task->state_set != sd_global->failed_task_set)
972 "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED",
973 SD_task_get_name(task));
975 if (__SD_task_is_scheduled_or_runnable(task) /* if the task is scheduled or runnable */
976 && ((task->kind == SD_TASK_COMP_PAR_AMDAHL) ||
977 (task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK))) { /* Don't free scheduling data for typed tasks */
978 __SD_task_destroy_scheduling_data(task);
979 task->workstation_list=NULL;
980 task->workstation_nb = 0;
983 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
984 surf_workstation_model->action_cancel(task->surf_action);
986 if (task->unsatisfied_dependencies == 0)
987 __SD_task_set_state(task, SD_SCHEDULABLE);
989 __SD_task_set_state(task, SD_NOT_SCHEDULED);
991 task->remains = task->amount;
992 task->start_time = -1.0;
995 /* Destroys the data memorized by SD_task_schedule. Task state must be SD_SCHEDULED or SD_RUNNABLE.
997 static void __SD_task_destroy_scheduling_data(SD_task_t task)
999 if (!__SD_task_is_scheduled_or_runnable(task)
1000 && !__SD_task_is_in_fifo(task))
1001 THROWF(arg_error, 0,
1002 "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
1003 SD_task_get_name(task));
1005 xbt_free(task->computation_amount);
1006 xbt_free(task->communication_amount);
1007 task->computation_amount = task->communication_amount = NULL;
1010 /* Runs a task. This function is directly called by __SD_task_try_to_run if the task
1011 * doesn't have to wait in fifos. Otherwise, it is called by __SD_task_just_done when
1012 * the task gets out of its fifos.
1014 void __SD_task_really_run(SD_task_t task)
1018 void **surf_workstations;
1020 xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
1021 "Task '%s' is not runnable or in a fifo! Task state: %d",
1022 SD_task_get_name(task), (int)SD_task_get_state(task));
1023 xbt_assert(task->workstation_list != NULL,
1024 "Task '%s': workstation_list is NULL!",
1025 SD_task_get_name(task));
1029 XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
1031 /* set this task as current task for the workstations in sequential mode */
1032 for (i = 0; i < task->workstation_nb; i++) {
1033 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
1034 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1035 task->workstation_list[i]->current_task = task;
1036 xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
1037 "The workstation should be busy now");
1041 XBT_DEBUG("Task '%s' set as current task for its workstations",
1042 SD_task_get_name(task));
1044 /* start the task */
1046 /* we have to create a Surf workstation array instead of the SimDag
1047 * workstation array */
1048 surf_workstations = xbt_new(void *, task->workstation_nb);
1050 for (i = 0; i < task->workstation_nb; i++)
1051 surf_workstations[i] = task->workstation_list[i]->surf_workstation;
1053 /* It's allowed to pass a NULL vector as cost to mean vector of 0.0 (easing
1054 * user's life). Let's deal with it */
1055 #define cost_or_zero(array,pos) ((array)?(array)[pos]:0.0)
1057 task->surf_action = NULL;
1058 if ((task->workstation_nb == 1)
1059 && (cost_or_zero(task->communication_amount, 0) == 0.0)) {
1061 surf_workstation_model->extension.
1062 workstation.execute(surf_workstations[0],
1063 cost_or_zero(task->computation_amount, 0));
1064 } else if ((task->workstation_nb == 1)
1065 && (cost_or_zero(task->computation_amount, 0) == 0.0)) {
1068 surf_workstation_model->extension.
1069 workstation.communicate(surf_workstations[0], surf_workstations[0],
1070 cost_or_zero(task->communication_amount,
1072 } else if ((task->workstation_nb == 2)
1073 && (cost_or_zero(task->computation_amount, 0) == 0.0)
1074 && (cost_or_zero(task->computation_amount, 1) == 0.0)) {
1078 for (i = 0; i < task->workstation_nb * task->workstation_nb; i++) {
1079 if (cost_or_zero(task->communication_amount, i) > 0.0) {
1081 value = cost_or_zero(task->communication_amount, i);
1086 surf_workstation_model->extension.
1087 workstation.communicate(surf_workstations[0],
1088 surf_workstations[1], value, task->rate);
1093 if (!task->surf_action) {
1094 double *computation_amount = xbt_new(double, task->workstation_nb);
1095 double *communication_amount = xbt_new(double, task->workstation_nb *
1096 task->workstation_nb);
1098 memcpy(computation_amount, task->computation_amount, sizeof(double) *
1099 task->workstation_nb);
1100 memcpy(communication_amount, task->communication_amount,
1101 sizeof(double) * task->workstation_nb * task->workstation_nb);
1104 surf_workstation_model->extension.
1105 workstation.execute_parallel_task(task->workstation_nb,
1108 communication_amount,
1111 xbt_free(surf_workstations);
1114 surf_workstation_model->action_data_set(task->surf_action, task);
1116 XBT_DEBUG("surf_action = %p", task->surf_action);
1120 TRACE_surf_action(task->surf_action, task->category);
1123 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
1124 __SD_task_set_state(task, SD_RUNNING);
1125 xbt_assert(__SD_task_is_running(task), "Bad state of task '%s': %d",
1126 SD_task_get_name(task), (int)SD_task_get_state(task));
1130 /* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_RUNNABLE
1131 * (ie when its dependencies are satisfied).
1132 * If one of the workstations where the task is scheduled on is busy (in sequential mode),
1133 * the task doesn't start.
1134 * Returns whether the task has started.
1136 int __SD_task_try_to_run(SD_task_t task)
1141 SD_workstation_t workstation;
1143 xbt_assert(__SD_task_is_runnable(task),
1144 "Task '%s' is not runnable! Task state: %d",
1145 SD_task_get_name(task), (int)SD_task_get_state(task));
1148 for (i = 0; i < task->workstation_nb; i++) {
1149 can_start = can_start &&
1150 !__SD_workstation_is_busy(task->workstation_list[i]);
1153 XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
1155 if (!can_start) { /* if the task cannot start and is not in the fifos yet */
1156 for (i = 0; i < task->workstation_nb; i++) {
1157 workstation = task->workstation_list[i];
1158 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1159 XBT_DEBUG("Pushing task '%s' in the fifo of workstation '%s'",
1160 SD_task_get_name(task),
1161 SD_workstation_get_name(workstation));
1162 xbt_fifo_push(workstation->task_fifo, task);
1165 __SD_task_set_state(task, SD_IN_FIFO);
1166 xbt_assert(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
1167 SD_task_get_name(task), (int)SD_task_get_state(task));
1168 XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
1170 __SD_task_really_run(task);
1176 /* This function is called by SD_simulate when a task is done.
1177 * It updates task->state and task->action and executes if necessary the tasks
1178 * which were waiting in fifos for the end of `task'
1180 void __SD_task_just_done(SD_task_t task)
1183 SD_workstation_t workstation;
1185 SD_task_t candidate;
1186 int candidate_nb = 0;
1187 int candidate_capacity = 8;
1188 SD_task_t *candidates;
1191 xbt_assert(__SD_task_is_running(task),
1192 "The task must be running! Task state: %d",
1193 (int)SD_task_get_state(task));
1194 xbt_assert(task->workstation_list != NULL,
1195 "Task '%s': workstation_list is NULL!",
1196 SD_task_get_name(task));
1199 candidates = xbt_new(SD_task_t, 8);
1201 __SD_task_set_state(task, SD_DONE);
1202 surf_workstation_model->action_unref(task->surf_action);
1203 task->surf_action = NULL;
1205 XBT_DEBUG("Looking for candidates");
1207 /* if the task was executed on sequential workstations,
1208 maybe we can execute the next task of the fifo for each workstation */
1209 for (i = 0; i < task->workstation_nb; i++) {
1210 workstation = task->workstation_list[i];
1211 XBT_DEBUG("Workstation '%s': access_mode = %d",
1212 SD_workstation_get_name(workstation), (int)workstation->access_mode);
1213 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1214 xbt_assert(workstation->task_fifo != NULL,
1215 "Workstation '%s' has sequential access but no fifo!",
1216 SD_workstation_get_name(workstation));
1217 xbt_assert(workstation->current_task =
1218 task, "Workstation '%s': current task should be '%s'",
1219 SD_workstation_get_name(workstation),
1220 SD_task_get_name(task));
1222 /* the task is over so we can release the workstation */
1223 workstation->current_task = NULL;
1225 XBT_DEBUG("Getting candidate in fifo");
1227 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1228 (workstation->task_fifo));
1230 if (candidate != NULL) {
1231 XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
1232 xbt_assert(__SD_task_is_in_fifo(candidate),
1233 "Bad state of candidate '%s': %d",
1234 SD_task_get_name(candidate),
1235 (int)SD_task_get_state(candidate));
1238 XBT_DEBUG("Candidate in fifo: %p", candidate);
1240 /* if there was a task waiting for my place */
1241 if (candidate != NULL) {
1242 /* Unfortunately, we are not sure yet that we can execute the task now,
1243 because the task can be waiting more deeply in some other workstation's fifos...
1244 So we memorize all candidate tasks, and then we will check for each candidate
1245 whether or not all its workstations are available. */
1247 /* realloc if necessary */
1248 if (candidate_nb == candidate_capacity) {
1249 candidate_capacity *= 2;
1251 xbt_realloc(candidates,
1252 sizeof(SD_task_t) * candidate_capacity);
1255 /* register the candidate */
1256 candidates[candidate_nb++] = candidate;
1257 candidate->fifo_checked = 0;
1262 XBT_DEBUG("Candidates found: %d", candidate_nb);
1264 /* now we check every candidate task */
1265 for (i = 0; i < candidate_nb; i++) {
1266 candidate = candidates[i];
1268 if (candidate->fifo_checked) {
1269 continue; /* we have already evaluated that task */
1272 xbt_assert(__SD_task_is_in_fifo(candidate),
1273 "Bad state of candidate '%s': %d",
1274 SD_task_get_name(candidate), (int)SD_task_get_state(candidate));
1276 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1277 workstation = candidate->workstation_list[j];
1279 /* I can start on this workstation if the workstation is shared
1280 or if I am the first task in the fifo */
1281 can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS
1283 xbt_fifo_get_item_content(xbt_fifo_get_first_item
1284 (workstation->task_fifo));
1287 XBT_DEBUG("Candidate '%s' can start: %d", SD_task_get_name(candidate),
1290 /* now we are sure that I can start! */
1292 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
1293 workstation = candidate->workstation_list[j];
1295 /* update the fifo */
1296 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
1297 candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */
1298 XBT_DEBUG("Head of the fifo: '%s'",
1300 NULL) ? SD_task_get_name(candidate) : "NULL");
1301 xbt_assert(candidate == candidates[i],
1302 "Error in __SD_task_just_done: bad first task in the fifo");
1304 } /* for each workstation */
1306 /* finally execute the task */
1307 XBT_DEBUG("Task '%s' state: %d", SD_task_get_name(candidate),
1308 (int)SD_task_get_state(candidate));
1309 __SD_task_really_run(candidate);
1312 ("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
1313 SD_task_get_name(candidate), candidate->state_set,
1314 sd_global->running_task_set, __SD_task_is_running(candidate));
1315 xbt_assert(__SD_task_is_running(candidate),
1316 "Bad state of task '%s': %d",
1317 SD_task_get_name(candidate),
1318 (int)SD_task_get_state(candidate));
1319 XBT_DEBUG("Okay, the task is running.");
1322 candidate->fifo_checked = 1;
1323 } /* for each candidate */
1325 xbt_free(candidates);
1329 * Remove all dependencies associated with a task. This function is called
1330 * when the task is destroyed.
1332 static void __SD_task_remove_dependencies(SD_task_t task)
1334 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
1335 because each one is stored twice */
1336 SD_dependency_t dependency;
1337 while (!xbt_dynar_is_empty(task->tasks_before)) {
1338 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
1339 SD_task_dependency_remove(dependency->src, dependency->dst);
1342 while (!xbt_dynar_is_empty(task->tasks_after)) {
1343 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
1344 SD_task_dependency_remove(dependency->src, dependency->dst);
1349 * \brief Returns the start time of a task
1351 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1353 * \param task: a task
1354 * \return the start time of this task
1356 double SD_task_get_start_time(SD_task_t task)
1358 if (task->surf_action)
1359 return surf_workstation_model->
1360 action_get_start_time(task->surf_action);
1362 return task->start_time;
1366 * \brief Returns the finish time of a task
1368 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1369 * If the state is not completed yet, the returned value is an
1370 * estimation of the task finish time. This value can fluctuate
1371 * until the task is completed.
1373 * \param task: a task
1374 * \return the start time of this task
1376 double SD_task_get_finish_time(SD_task_t task)
1378 if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
1379 return surf_workstation_model->
1380 action_get_finish_time(task->surf_action);
1382 return task->finish_time;
1387 void SD_task_distribute_comp_amdhal(SD_task_t task, int ws_count)
1390 xbt_assert(task->kind == SD_TASK_COMP_PAR_AMDAHL,
1391 "Task %s is not a SD_TASK_COMP_PAR_AMDAHL typed task."
1392 "Cannot use this function.",
1393 SD_task_get_name(task));
1395 task->computation_amount = xbt_new0(double, ws_count);
1396 task->communication_amount = xbt_new0(double, ws_count * ws_count);
1397 task->workstation_nb = ws_count;
1398 task->workstation_list = xbt_new0(SD_workstation_t, ws_count);
1400 for(i=0;i<ws_count;i++){
1401 task->computation_amount[i] =
1402 (task->alpha + (1 - task->alpha)/ws_count) * task->amount;
1407 /** @brief Auto-schedules a task.
1409 * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
1410 * allows to specify the task costs at creation, and decorelate them from the
1411 * scheduling process where you just specify which resource should deliver the
1414 * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e() or
1415 * SD_task_create_comp_seq(). Check their definitions for the exact semantic of each
1419 * We should create tasks kind for the following categories:
1420 * - Point to point communication (done)
1421 * - Sequential computation (done)
1422 * - group communication (redistribution, several kinds)
1423 * - parallel tasks with no internal communication (one kind per speedup model such as amdal)
1424 * - idem+ internal communication. Task type not enough since we cannot store comm cost alongside to comp one)
1426 void SD_task_schedulev(SD_task_t task, int count,
1427 const SD_workstation_t * list)
1430 SD_dependency_t dep;
1432 xbt_assert(task->kind != 0,
1433 "Task %s is not typed. Cannot automatically schedule it.",
1434 SD_task_get_name(task));
1435 switch (task->kind) {
1436 case SD_TASK_COMP_PAR_AMDAHL:
1437 SD_task_distribute_comp_amdhal(task, count);
1438 case SD_TASK_COMM_E2E:
1439 case SD_TASK_COMP_SEQ:
1440 xbt_assert(task->workstation_nb == count,"Got %d locations, but were expecting %d locations",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 childs and parent being COMM_E2E to say where I am located (and start them if runnable) */
1464 if (task->kind == SD_TASK_COMP_SEQ) {
1465 XBT_VERB("Schedule computation task %s on %s. It costs %.f flops",
1466 SD_task_get_name(task),
1467 SD_workstation_get_name(task->workstation_list[0]),
1468 task->computation_amount[0]);
1470 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1471 SD_task_t before = dep->src;
1472 if (before->kind == SD_TASK_COMM_E2E) {
1473 before->workstation_list[1] = task->workstation_list[0];
1475 if (before->workstation_list[0] &&
1476 (__SD_task_is_schedulable(before)
1477 || __SD_task_is_not_scheduled(before))) {
1478 SD_task_do_schedule(before);
1480 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1481 SD_task_get_name(before),
1482 SD_workstation_get_name(before->workstation_list[0]),
1483 SD_workstation_get_name(before->workstation_list[1]),
1484 before->communication_amount[2]);
1488 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1489 SD_task_t after = dep->dst;
1490 if (after->kind == SD_TASK_COMM_E2E) {
1491 after->workstation_list[0] = task->workstation_list[0];
1492 if (after->workstation_list[1]
1493 && (__SD_task_is_not_scheduled(after)
1494 || __SD_task_is_schedulable(after))) {
1495 SD_task_do_schedule(after);
1497 ("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
1498 SD_task_get_name(after),
1499 SD_workstation_get_name(after->workstation_list[0]),
1500 SD_workstation_get_name(after->workstation_list[1]),
1501 after->communication_amount[2]);
1507 /* Iterate over all childs and parent being MXN_1D_BLOC to say where I am located (and start them if runnable) */
1508 if (task->kind == SD_TASK_COMP_PAR_AMDAHL) {
1509 XBT_VERB("Schedule computation task %s on %d workstations. %.f flops"
1510 " will be distributed following Amdahl'Law",
1511 SD_task_get_name(task), task->workstation_nb,
1512 task->computation_amount[0]);
1513 xbt_dynar_foreach(task->tasks_before, cpt, dep) {
1514 SD_task_t before = dep->src;
1515 if (before->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1516 if (!before->workstation_list){
1517 XBT_VERB("Sender side of Task %s is not scheduled yet. Fill the workstation list with receiver side",
1518 SD_task_get_name(before));
1519 before->workstation_list = xbt_new0(SD_workstation_t, count);
1520 before->workstation_nb = count;
1521 for (i=0;i<count;i++)
1522 before->workstation_list[i] = task->workstation_list[i];
1525 double src_start, src_end, dst_start, dst_end;
1526 src_nb = before->workstation_nb;
1528 before->workstation_list = (SD_workstation_t*) xbt_realloc(
1529 before->workstation_list,
1530 (before->workstation_nb+count)*sizeof(s_SD_workstation_t));
1531 for(i=0; i<count; i++)
1532 before->workstation_list[before->workstation_nb+i] =
1533 task->workstation_list[i];
1535 before->workstation_nb += count;
1537 before->computation_amount = xbt_new0(double,
1538 before->workstation_nb);
1539 before->communication_amount = xbt_new0(double,
1540 before->workstation_nb*
1541 before->workstation_nb);
1543 for(i=0;i<src_nb;i++){
1544 src_start = i*before->amount/src_nb;
1545 src_end = src_start + before->amount/src_nb;
1546 for(j=0; j<dst_nb; j++){
1547 dst_start = j*before->amount/dst_nb;
1548 dst_end = dst_start + before->amount/dst_nb;
1549 XBT_VERB("(%s->%s): (%.2f, %.2f)-> (%.2f, %.2f)",
1550 SD_workstation_get_name(before->workstation_list[i]),
1551 SD_workstation_get_name(before->workstation_list[src_nb+j]),
1552 src_start, src_end, dst_start, dst_end);
1553 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1554 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1556 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1557 MIN(src_end, dst_end) - MAX(src_start, dst_start);
1559 XBT_VERB("==> %.2f",
1560 before->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1564 if (__SD_task_is_schedulable(before) ||
1565 __SD_task_is_not_scheduled(before)) {
1566 SD_task_do_schedule(before);
1568 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1569 SD_task_get_name(before),before->amount, src_nb, dst_nb);
1574 xbt_dynar_foreach(task->tasks_after, cpt, dep) {
1575 SD_task_t after = dep->dst;
1576 if (after->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK){
1577 if (!after->workstation_list){
1578 XBT_VERB("Receiver side of Task %s is not scheduled yet. Fill the workstation list with sender side",
1579 SD_task_get_name(after));
1580 after->workstation_list = xbt_new0(SD_workstation_t, count);
1581 after->workstation_nb = count;
1582 for (i=0;i<count;i++)
1583 after->workstation_list[i] = task->workstation_list[i];
1586 double src_start, src_end, dst_start, dst_end;
1588 dst_nb = after->workstation_nb;
1589 after->workstation_list = (SD_workstation_t*) xbt_realloc(
1590 after->workstation_list,
1591 (after->workstation_nb+count)*sizeof(s_SD_workstation_t));
1592 for(i=after->workstation_nb - 1; i>=0; i--)
1593 after->workstation_list[count+i] = after->workstation_list[i];
1594 for(i=0; i<count; i++)
1595 after->workstation_list[i] = task->workstation_list[i];
1597 after->workstation_nb += count;
1599 after->computation_amount = xbt_new0(double, after->workstation_nb);
1600 after->communication_amount = xbt_new0(double,
1601 after->workstation_nb*
1602 after->workstation_nb);
1604 for(i=0;i<src_nb;i++){
1605 src_start = i*after->amount/src_nb;
1606 src_end = src_start + after->amount/src_nb;
1607 for(j=0; j<dst_nb; j++){
1608 dst_start = j*after->amount/dst_nb;
1609 dst_end = dst_start + after->amount/dst_nb;
1610 XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)",
1611 i, j, src_start, src_end, dst_start, dst_end);
1612 if ((src_end <= dst_start) || (dst_end <= src_start)) {
1613 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]=0.0;
1615 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j] =
1616 MIN(src_end, dst_end)- MAX(src_start, dst_start);
1618 XBT_VERB("==> %.2f",
1619 after->communication_amount[i*(src_nb+dst_nb)+src_nb+j]);
1623 if (__SD_task_is_schedulable(after) ||
1624 __SD_task_is_not_scheduled(after)) {
1625 SD_task_do_schedule(after);
1627 ("Auto-Schedule redistribution task %s. Send %.f bytes from %d hosts to %d hosts.",
1628 SD_task_get_name(after),after->amount, src_nb, dst_nb);
1636 /** @brief autoschedule a task on a list of workstations
1638 * This function is very similar to SD_task_schedulev(),
1639 * but takes the list of workstations to schedule onto as separate parameters.
1640 * It builds a proper vector of workstations and then call SD_task_schedulev()
1642 void SD_task_schedulel(SD_task_t task, int count, ...)
1645 SD_workstation_t *list = xbt_new(SD_workstation_t, count);
1647 va_start(ap, count);
1648 for (i = 0; i < count; i++) {
1649 list[i] = va_arg(ap, SD_workstation_t);
1652 SD_task_schedulev(task, count, list);
1657 * \brief Sets the tracing category of a task.
1659 * This function should be called after the creation of a
1660 * SimDAG task, to define the category of that task. The first
1661 * parameter must contain a task that was created with the
1662 * function #SD_task_create. The second parameter must contain
1663 * a category that was previously declared with the function
1666 * \param task The task to be considered
1667 * \param category the name of the category to be associated to the task
1669 * \see SD_task_get_category, TRACE_category, TRACE_category_with_color
1671 void SD_task_set_category (SD_task_t task, const char *category)
1674 if (!TRACE_is_enabled()) return;
1675 if (task == NULL) return;
1676 if (category == NULL){
1677 if (task->category) xbt_free (task->category);
1678 task->category = NULL;
1680 task->category = xbt_strdup (category);
1686 * \brief Gets the current tracing category of a task.
1688 * \param task The task to be considered
1690 * \see SD_task_set_category
1692 * \return Returns the name of the tracing category of the given task, NULL otherwise
1694 const char *SD_task_get_category (SD_task_t task)
1697 return task->category;