2 #include "simdag/simdag.h"
3 #include "xbt/sysdep.h"
6 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_task, sd,
7 "Logging specific to SimDag (task)");
9 static void __SD_task_remove_dependencies(SD_task_t task);
10 static void __SD_task_destroy_scheduling_data(SD_task_t task);
13 * \brief Creates a new task.
15 * \param name the name of the task (can be \c NULL)
16 * \param data the user data you want to associate with the task (can be \c NULL)
17 * \param amount amount of the task
18 * \return the new task
19 * \see SD_task_destroy()
21 SD_task_t SD_task_create(const char *name, void *data, double amount)
27 task = xbt_new(s_SD_task_t, 1);
29 /* general information */
30 task->data = data; /* user data */
32 task->name = xbt_strdup(name);
36 task->state_hookup.prev = NULL;
37 task->state_hookup.next = NULL;
38 task->state_set = sd_global->not_scheduled_task_set;
39 task->state = SD_NOT_SCHEDULED;
40 xbt_swag_insert(task, task->state_set);
42 task->amount = amount;
43 task->remains = amount;
44 task->start_time = -1.0;
45 task->finish_time = -1.0;
46 task->surf_action = NULL;
47 task->watch_points = 0;
50 task->tasks_before = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
51 task->tasks_after = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
53 /* scheduling parameters */
54 task->workstation_nb = 0;
55 task->workstation_list = NULL;
56 task->computation_amount = NULL;
57 task->communication_amount = NULL;
60 sd_global->task_number++;
66 * \brief Returns the user data of a task
69 * \return the user data associated with this task (can be \c NULL)
70 * \see SD_task_set_data()
72 void *SD_task_get_data(SD_task_t task)
75 xbt_assert0(task != NULL, "Invalid parameter");
80 * \brief Sets the user data of a task
82 * The new data can be \c NULL. The old data should have been freed first
83 * if it was not \c NULL.
86 * \param data the new data you want to associate with this task
87 * \see SD_task_get_data()
89 void SD_task_set_data(SD_task_t task, void *data)
92 xbt_assert0(task != NULL, "Invalid parameter");
97 * \brief Returns the state of a task
100 * \return the current \ref e_SD_task_state_t "state" of this task:
101 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_READY, #SD_RUNNING, #SD_DONE or #SD_FAILED
102 * \see e_SD_task_state_t
104 e_SD_task_state_t SD_task_get_state(SD_task_t task)
106 SD_CHECK_INIT_DONE();
107 xbt_assert0(task != NULL, "Invalid parameter");
111 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
113 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
115 xbt_swag_remove(task, task->state_set);
117 case SD_NOT_SCHEDULED:
118 task->state_set = sd_global->not_scheduled_task_set;
121 task->state_set = sd_global->scheduled_task_set;
124 task->state_set = sd_global->ready_task_set;
127 task->state_set = sd_global->in_fifo_task_set;
130 task->state_set = sd_global->running_task_set;
132 surf_workstation_model->common_public->action_get_start_time(task->
136 task->state_set = sd_global->done_task_set;
138 surf_workstation_model->common_public->action_get_finish_time(task->
143 task->state_set = sd_global->failed_task_set;
146 xbt_assert0(0, "Invalid state");
148 xbt_swag_insert(task, task->state_set);
149 task->state = new_state;
151 if (task->watch_points & new_state) {
152 INFO1("Watch point reached with task '%s'!", SD_task_get_name(task));
153 sd_global->watch_point_reached = 1;
154 SD_task_unwatch(task, new_state); /* remove the watch point */
159 * \brief Returns the name of a task
162 * \return the name of this task (can be \c NULL)
164 const char *SD_task_get_name(SD_task_t task)
166 SD_CHECK_INIT_DONE();
167 xbt_assert0(task != NULL, "Invalid parameter");
172 * \brief Returns the total amount of a task
175 * \return the total amount of this task
176 * \see SD_task_get_remaining_amount()
178 double SD_task_get_amount(SD_task_t task)
180 SD_CHECK_INIT_DONE();
181 xbt_assert0(task != NULL, "Invalid parameter");
186 * \brief Returns the remaining amount of a task
189 * \return the remaining amount of this task
190 * \see SD_task_get_amount()
192 double SD_task_get_remaining_amount(SD_task_t task)
194 SD_CHECK_INIT_DONE();
195 xbt_assert0(task != NULL, "Invalid parameter");
197 if (task->surf_action)
198 return task->surf_action->remains;
200 return task->remains;
203 /* temporary function for debbuging */
204 static void __SD_print_dependencies(SD_task_t task)
209 SD_dependency_t dependency;
211 INFO1("The following tasks must be executed before %s:",
212 SD_task_get_name(task));
213 dynar = task->tasks_before;
214 length = xbt_dynar_length(dynar);
217 for (i = 0; i < length; i++) {
218 xbt_dynar_get_cpy(dynar, i, &dependency);
219 INFO1(" %s", SD_task_get_name(dependency->src));
222 INFO1("The following tasks must be executed after %s:",
223 SD_task_get_name(task));
225 dynar = task->tasks_after;
226 length = xbt_dynar_length(dynar);
227 for (i = 0; i < length; i++) {
228 xbt_dynar_get_cpy(dynar, i, &dependency);
229 INFO1(" %s", SD_task_get_name(dependency->dst));
231 INFO0("----------------------------");
234 /* Destroys a dependency between two tasks.
236 static void __SD_task_dependency_destroy(void *dependency)
238 if (((SD_dependency_t) dependency)->name != NULL)
239 xbt_free(((SD_dependency_t) dependency)->name);
240 xbt_free(dependency);
244 * \brief Adds a dependency between two tasks
246 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
247 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_READY.
249 * \param name the name of the new dependency (can be \c NULL)
250 * \param data the user data you want to associate with this dependency (can be \c NULL)
251 * \param src the task which must be executed first
252 * \param dst the task you want to make depend on \a src
253 * \see SD_task_dependency_remove()
255 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
262 SD_dependency_t dependency;
264 SD_CHECK_INIT_DONE();
265 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
267 dynar = src->tasks_after;
268 length = xbt_dynar_length(dynar);
274 "Cannot add a dependency between task '%s' and itself",
275 SD_task_get_name(src));
277 if (!__SD_task_is_not_scheduled(src)
278 && !__SD_task_is_scheduled_or_ready(src))
280 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY",
281 SD_task_get_name(src));
283 if (!__SD_task_is_not_scheduled(dst)
284 && !__SD_task_is_scheduled_or_ready(dst))
286 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY",
287 SD_task_get_name(dst));
289 DEBUG2("SD_task_dependency_add: src = %s, dst = %s", SD_task_get_name(src),
290 SD_task_get_name(dst));
291 for (i = 0; i < length && !found; i++) {
292 xbt_dynar_get_cpy(dynar, i, &dependency);
293 found = (dependency->dst == dst);
294 DEBUG2("Dependency %d: dependency->dst = %s", i,
295 SD_task_get_name(dependency->dst));
300 "A dependency already exists between task '%s' and task '%s'",
301 SD_task_get_name(src), SD_task_get_name(dst));
303 dependency = xbt_new(s_SD_dependency_t, 1);
306 dependency->name = xbt_strdup(name);
308 dependency->name = NULL;
310 dependency->data = data;
311 dependency->src = src;
312 dependency->dst = dst;
314 /* src must be executed before dst */
315 xbt_dynar_push(src->tasks_after, &dependency);
316 xbt_dynar_push(dst->tasks_before, &dependency);
318 /* if the task was ready, then dst->tasks_before is not empty anymore,
319 so we must go back to state SD_SCHEDULED */
320 if (__SD_task_is_ready(dst)) {
321 DEBUG1("SD_task_dependency_add: %s was ready and becomes scheduled!",
322 SD_task_get_name(dst));
323 __SD_task_set_state(dst, SD_SCHEDULED);
326 /* __SD_print_dependencies(src);
327 __SD_print_dependencies(dst); */
331 * \brief Indacates whether there is a dependency between two tasks.
334 * \param dst a task depending on \a src
336 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
341 SD_dependency_t dependency;
343 SD_CHECK_INIT_DONE();
344 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
346 dynar = src->tasks_after;
347 length = xbt_dynar_length(dynar);
349 for (i = 0; i < length; i++) {
350 xbt_dynar_get_cpy(dynar, i, &dependency);
351 if (dependency->dst == dst)
358 * \brief Remove a dependency between two tasks
361 * \param dst a task depending on \a src
362 * \see SD_task_dependency_add()
364 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
371 SD_dependency_t dependency;
373 SD_CHECK_INIT_DONE();
374 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
376 /* remove the dependency from src->tasks_after */
377 dynar = src->tasks_after;
378 length = xbt_dynar_length(dynar);
380 for (i = 0; i < length && !found; i++) {
381 xbt_dynar_get_cpy(dynar, i, &dependency);
382 if (dependency->dst == dst) {
383 xbt_dynar_remove_at(dynar, i, NULL);
389 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
390 SD_task_get_name(src), SD_task_get_name(dst),
391 SD_task_get_name(dst), SD_task_get_name(src));
393 /* remove the dependency from dst->tasks_before */
394 dynar = dst->tasks_before;
395 length = xbt_dynar_length(dynar);
398 for (i = 0; i < length && !found; i++) {
399 xbt_dynar_get_cpy(dynar, i, &dependency);
400 if (dependency->src == src) {
401 xbt_dynar_remove_at(dynar, i, NULL);
402 __SD_task_dependency_destroy(dependency);
406 /* should never happen... */
408 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
409 SD_task_get_name(dst), SD_task_get_name(src),
410 SD_task_get_name(src), SD_task_get_name(dst));
412 /* if the task was scheduled and dst->tasks_before is empty now, we can make it ready */
413 if (xbt_dynar_length(dst->tasks_before) == 0 && __SD_task_is_scheduled(dst))
414 __SD_task_set_state(dst, SD_READY);
416 /* __SD_print_dependencies(src);
417 __SD_print_dependencies(dst); */
421 * \brief Returns the user data associated with a dependency between two tasks
424 * \param dst a task depending on \a src
425 * \return the user data associated with this dependency (can be \c NULL)
426 * \see SD_task_dependency_add()
428 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
435 SD_dependency_t dependency;
438 SD_CHECK_INIT_DONE();
439 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
441 dynar = src->tasks_after;
442 length = xbt_dynar_length(dynar);
444 for (i = 0; i < length && !found; i++) {
445 xbt_dynar_get_cpy(dynar, i, &dependency);
446 found = (dependency->dst == dst);
449 THROW2(arg_error, 0, "No dependency found between task '%s' and '%s'",
450 SD_task_get_name(src), SD_task_get_name(dst));
451 return dependency->data;
454 /* temporary function for debugging */
455 static void __SD_print_watch_points(SD_task_t task)
457 static const int state_masks[] =
458 { SD_SCHEDULED, SD_RUNNING, SD_READY, SD_DONE, SD_FAILED };
459 static const char *state_names[] =
460 { "scheduled", "running", "ready", "done", "failed" };
463 INFO2("Task '%s' watch points (%x): ", SD_task_get_name(task),
467 for (i = 0; i < 5; i++) {
468 if (task->watch_points & state_masks[i])
469 INFO1("%s ", state_names[i]);
474 * \brief Adds a watch point to a task
476 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
477 * task becomes the one given in argument. The
478 * watch point is then automatically removed.
481 * \param state the \ref e_SD_task_state_t "state" you want to watch
482 * (cannot be #SD_NOT_SCHEDULED)
483 * \see SD_task_unwatch()
485 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
487 SD_CHECK_INIT_DONE();
488 xbt_assert0(task != NULL, "Invalid parameter");
490 if (state & SD_NOT_SCHEDULED)
492 "Cannot add a watch point for state SD_NOT_SCHEDULED");
494 task->watch_points = task->watch_points | state;
495 /* __SD_print_watch_points(task); */
499 * \brief Removes a watch point from a task
502 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
503 * \see SD_task_watch()
505 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
507 SD_CHECK_INIT_DONE();
508 xbt_assert0(task != NULL, "Invalid parameter");
509 xbt_assert0(state != SD_NOT_SCHEDULED,
510 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
512 task->watch_points = task->watch_points & ~state;
513 /* __SD_print_watch_points(task); */
517 * \brief Returns an approximative estimation of the execution time of a task.
519 * The estimation is very approximative because the value returned is the time
520 * the task would take if it was executed now and if it was the only task.
522 * \param task the task to evaluate
523 * \param workstation_nb number of workstations on which the task would be executed
524 * \param workstation_list the workstations on which the task would be executed
525 * \param computation_amount computation amount for each workstation
526 * \param communication_amount communication amount between each pair of workstations
527 * \param rate task execution speed rate
530 double SD_task_get_execution_time(SD_task_t task,
532 const SD_workstation_t * workstation_list,
533 const double *computation_amount,
534 const double *communication_amount,
537 double time, max_time = 0.0;
539 SD_CHECK_INIT_DONE();
540 xbt_assert0(task != NULL && workstation_nb > 0 && workstation_list != NULL
541 && computation_amount != NULL
542 && communication_amount != NULL, "Invalid parameter");
544 /* the task execution time is the maximum execution time of the parallel tasks */
546 for (i = 0; i < workstation_nb; i++) {
548 SD_workstation_get_computation_time(workstation_list[i],
549 computation_amount[i]);
551 for (j = 0; j < workstation_nb; j++) {
553 SD_route_get_communication_time(workstation_list[i],
555 communication_amount[i *
560 if (time > max_time) {
564 return max_time * SD_task_get_amount(task);
568 * \brief Schedules a task
570 * The task state must be #SD_NOT_SCHEDULED.
571 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
572 * i.e. when its dependencies are satisfied.
574 * \param task the task you want to schedule
575 * \param workstation_nb number of workstations on which the task will be executed
576 * \param workstation_list the workstations on which the task will be executed
577 * \param computation_amount computation amount for each workstation
578 * \param communication_amount communication amount between each pair of workstations
579 * \param rate task execution speed rate
580 * \see SD_task_unschedule()
582 void SD_task_schedule(SD_task_t task, int workstation_nb,
583 const SD_workstation_t * workstation_list,
584 const double *computation_amount,
585 const double *communication_amount, double rate)
588 int communication_nb;
590 SD_CHECK_INIT_DONE();
591 xbt_assert0(task != NULL, "Invalid parameter");
592 xbt_assert0(workstation_nb > 0, "workstation_nb must be positive");
594 if (!__SD_task_is_not_scheduled(task))
595 THROW1(arg_error, 0, "Task '%s' has already been scheduled",
596 SD_task_get_name(task));
598 task->workstation_nb = workstation_nb;
601 task->computation_amount = xbt_new(double, workstation_nb);
602 memcpy(task->computation_amount, computation_amount,
603 sizeof(double) * workstation_nb);
605 communication_nb = workstation_nb * workstation_nb;
606 task->communication_amount = xbt_new(double, communication_nb);
607 memcpy(task->communication_amount, communication_amount,
608 sizeof(double) * communication_nb);
610 task->workstation_list = xbt_new(SD_workstation_t, workstation_nb);
611 memcpy(task->workstation_list, workstation_list,
612 sizeof(SD_workstation_t) * workstation_nb);
614 /* update the task state */
615 if (xbt_dynar_length(task->tasks_before) == 0)
616 __SD_task_set_state(task, SD_READY);
618 __SD_task_set_state(task, SD_SCHEDULED);
622 * \brief Unschedules a task
624 * The task state must be #SD_SCHEDULED, #SD_READY, #SD_RUNNING or #SD_FAILED.
625 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
626 * Call SD_task_schedule() to schedule it again.
628 * \param task the task you want to unschedule
629 * \see SD_task_schedule()
631 void SD_task_unschedule(SD_task_t task)
633 SD_CHECK_INIT_DONE();
634 xbt_assert0(task != NULL, "Invalid parameter");
636 if (task->state_set != sd_global->scheduled_task_set &&
637 task->state_set != sd_global->ready_task_set &&
638 task->state_set != sd_global->running_task_set &&
639 task->state_set != sd_global->failed_task_set)
641 "Task %s: the state must be SD_SCHEDULED, SD_READY, SD_RUNNING or SD_FAILED",
642 SD_task_get_name(task));
644 if (__SD_task_is_scheduled_or_ready(task)) /* if the task is scheduled or ready */
645 __SD_task_destroy_scheduling_data(task);
647 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
648 surf_workstation_model->common_public->action_cancel(task->surf_action);
650 __SD_task_set_state(task, SD_NOT_SCHEDULED);
651 task->remains = task->amount;
652 task->start_time = -1.0;
655 /* Destroys the data memorised by SD_task_schedule. Task state must be SD_SCHEDULED or SD_READY.
657 static void __SD_task_destroy_scheduling_data(SD_task_t task)
659 SD_CHECK_INIT_DONE();
660 if (!__SD_task_is_scheduled_or_ready(task) && !__SD_task_is_in_fifo(task))
662 "Task '%s' must be SD_SCHEDULED, SD_READY or SD_IN_FIFO",
663 SD_task_get_name(task));
665 xbt_free(task->computation_amount);
666 xbt_free(task->communication_amount);
669 /* Runs a task. This function is directly called by __SD_task_try_to_run if the task
670 * doesn't have to wait in fifos. Otherwise, it is called by __SD_task_just_done when
671 * the task gets out of its fifos.
673 void __SD_task_really_run(SD_task_t task)
677 void **surf_workstations;
679 SD_CHECK_INIT_DONE();
680 xbt_assert0(task != NULL, "Invalid parameter");
681 xbt_assert2(__SD_task_is_ready_or_in_fifo(task),
682 "Task '%s' is not ready or in a fifo! Task state: %d",
683 SD_task_get_name(task), SD_task_get_state(task));
684 xbt_assert1(task->workstation_list != NULL,
685 "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
689 DEBUG1("Really running task '%s'", SD_task_get_name(task));
691 /* set this task as current task for the workstations in sequential mode */
692 for (i = 0; i < task->workstation_nb; i++) {
693 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
694 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
695 task->workstation_list[i]->current_task = task;
696 xbt_assert0(__SD_workstation_is_busy(task->workstation_list[i]),
697 "The workstation should be busy now");
701 DEBUG1("Task '%s' set as current task for its workstations",
702 SD_task_get_name(task));
706 /* we have to create a Surf workstation array instead of the SimDag workstation array */
707 surf_workstations = xbt_new(void *, task->workstation_nb);
709 for (i = 0; i < task->workstation_nb; i++) {
710 surf_workstations[i] = task->workstation_list[i]->surf_workstation;
713 task->surf_action = NULL;
714 if ((task->workstation_nb == 1) && (task->communication_amount[0] == 0.0)) {
716 surf_workstation_model->extension_public->execute(surf_workstations[0],
720 } else if ((task->workstation_nb == 1)
721 && (task->computation_amount[0] == 0.0)) {
723 surf_workstation_model->
724 extension_public->communicate(surf_workstations[0],
725 surf_workstations[0],
726 task->communication_amount[0],
728 } else if ((task->workstation_nb == 2)
729 && (task->computation_amount[0] == 0.0)
730 && (task->computation_amount[1] == 0.0)) {
734 for (i = 0; i < task->workstation_nb * task->workstation_nb; i++) {
735 if (task->communication_amount[i] > 0.0) {
737 value = task->communication_amount[i];
742 surf_workstation_model->
743 extension_public->communicate(surf_workstations[0],
744 surf_workstations[1], value,
748 if (!task->surf_action) {
749 double *computation_amount = xbt_new(double, task->workstation_nb);
750 double *communication_amount = xbt_new(double, task->workstation_nb *
751 task->workstation_nb);
753 memcpy(computation_amount, task->computation_amount, sizeof(double) *
754 task->workstation_nb);
755 memcpy(communication_amount, task->communication_amount,
756 sizeof(double) * task->workstation_nb * task->workstation_nb);
759 surf_workstation_model->extension_public->execute_parallel_task(task->
763 communication_amount,
769 xbt_free(surf_workstations);
772 surf_workstation_model->common_public->action_set_data(task->surf_action,
775 DEBUG1("surf_action = %p", task->surf_action);
777 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
778 __SD_task_set_state(task, SD_RUNNING);
779 xbt_assert2(__SD_task_is_running(task), "Bad state of task '%s': %d",
780 SD_task_get_name(task), SD_task_get_state(task));
784 /* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_READY
785 * (ie when its dependencies are satisfied).
786 * If one of the workstations where the task is scheduled on is busy (in sequential mode),
787 * the task doesn't start.
788 * Returns whether the task has started.
790 int __SD_task_try_to_run(SD_task_t task)
795 SD_workstation_t workstation;
797 SD_CHECK_INIT_DONE();
798 xbt_assert0(task != NULL, "Invalid parameter");
799 xbt_assert2(__SD_task_is_ready(task),
800 "Task '%s' is not ready! Task state: %d",
801 SD_task_get_name(task), SD_task_get_state(task));
804 for (i = 0; i < task->workstation_nb; i++) {
805 can_start = !__SD_workstation_is_busy(task->workstation_list[i]);
808 DEBUG2("Task '%s' can start: %d", SD_task_get_name(task), can_start);
810 if (!can_start) { /* if the task cannot start and is not in the fifos yet */
811 for (i = 0; i < task->workstation_nb; i++) {
812 workstation = task->workstation_list[i];
813 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
814 DEBUG2("Pushing task '%s' in the fifo of workstation '%s'",
815 SD_task_get_name(task), SD_workstation_get_name(workstation));
816 xbt_fifo_push(workstation->task_fifo, task);
819 __SD_task_set_state(task, SD_IN_FIFO);
820 xbt_assert2(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
821 SD_task_get_name(task), SD_task_get_state(task));
822 DEBUG1("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
824 __SD_task_really_run(task);
830 /* This function is called by SD_simulate when a task is done.
831 * It updates task->state and task->action and executes if necessary the tasks
832 * which were waiting in fifos for the end of `task'
834 void __SD_task_just_done(SD_task_t task)
837 SD_workstation_t workstation;
840 int candidate_nb = 0;
841 int candidate_capacity = 8;
842 SD_task_t *candidates;
845 SD_CHECK_INIT_DONE();
846 xbt_assert0(task != NULL, "Invalid parameter");
847 xbt_assert1(__SD_task_is_running(task),
848 "The task must be running! Task state: %d",
849 SD_task_get_state(task));
850 xbt_assert1(task->workstation_list != NULL,
851 "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
854 candidates = xbt_new(SD_task_t, 8);
856 __SD_task_set_state(task, SD_DONE);
857 surf_workstation_model->common_public->action_free(task->surf_action);
858 task->surf_action = NULL;
860 DEBUG0("Looking for candidates");
862 /* if the task was executed on sequential workstations,
863 maybe we can execute the next task of the fifo for each workstation */
864 for (i = 0; i < task->workstation_nb; i++) {
865 workstation = task->workstation_list[i];
866 DEBUG2("Workstation '%s': access_mode = %d",
867 SD_workstation_get_name(workstation), workstation->access_mode);
868 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
869 xbt_assert1(workstation->task_fifo != NULL,
870 "Workstation '%s' has sequential access but no fifo!",
871 SD_workstation_get_name(workstation));
872 xbt_assert2(workstation->current_task =
873 task, "Workstation '%s': current task should be '%s'",
874 SD_workstation_get_name(workstation),
875 SD_task_get_name(task));
877 /* the task is over so we can release the workstation */
878 workstation->current_task = NULL;
880 DEBUG0("Getting candidate in fifo");
882 xbt_fifo_get_item_content(xbt_fifo_get_first_item
883 (workstation->task_fifo));
885 if (candidate != NULL) {
886 DEBUG1("Candidate: '%s'", SD_task_get_name(candidate));
887 xbt_assert2(__SD_task_is_in_fifo(candidate),
888 "Bad state of candidate '%s': %d",
889 SD_task_get_name(candidate),
890 SD_task_get_state(candidate));
893 DEBUG1("Candidate in fifo: %p", candidate);
895 /* if there was a task waiting for my place */
896 if (candidate != NULL) {
897 /* Unfortunately, we are not sure yet that we can execute the task now,
898 because the task can be waiting more deeply in some other workstation's fifos...
899 So we memorize all candidate tasks, and then we will check for each candidate
900 whether or not all its workstations are available. */
902 /* realloc if necessary */
903 if (candidate_nb == candidate_capacity) {
904 candidate_capacity *= 2;
906 xbt_realloc(candidates, sizeof(SD_task_t) * candidate_capacity);
909 /* register the candidate */
910 candidates[candidate_nb++] = candidate;
911 candidate->fifo_checked = 0;
916 DEBUG1("Candidates found: %d", candidate_nb);
918 /* now we check every candidate task */
919 for (i = 0; i < candidate_nb; i++) {
920 candidate = candidates[i];
922 if (candidate->fifo_checked) {
923 continue; /* we have already evaluated that task */
926 xbt_assert2(__SD_task_is_in_fifo(candidate),
927 "Bad state of candidate '%s': %d",
928 SD_task_get_name(candidate), SD_task_get_state(candidate));
930 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
931 workstation = candidate->workstation_list[j];
933 /* I can start on this workstation if the workstation is shared
934 or if I am the first task in the fifo */
935 can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS ||
937 xbt_fifo_get_item_content(xbt_fifo_get_first_item
938 (workstation->task_fifo));
941 DEBUG2("Candidate '%s' can start: %d", SD_task_get_name(candidate),
944 /* now we are sure that I can start! */
946 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
947 workstation = candidate->workstation_list[j];
949 /* update the fifo */
950 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
951 candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */
952 DEBUG1("Head of the fifo: '%s'",
953 (candidate != NULL) ? SD_task_get_name(candidate) : "NULL");
954 xbt_assert0(candidate == candidates[i],
955 "Error in __SD_task_just_done: bad first task in the fifo");
957 } /* for each workstation */
959 /* finally execute the task */
960 DEBUG2("Task '%s' state: %d", SD_task_get_name(candidate),
961 SD_task_get_state(candidate));
962 __SD_task_really_run(candidate);
965 ("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
966 SD_task_get_name(candidate), candidate->state_set,
967 sd_global->running_task_set, __SD_task_is_running(candidate));
968 xbt_assert2(__SD_task_is_running(candidate),
969 "Bad state of task '%s': %d", SD_task_get_name(candidate),
970 SD_task_get_state(candidate));
971 DEBUG0("Okay, the task is running.");
974 candidate->fifo_checked = 1;
975 } /* for each candidate */
977 xbt_free(candidates);
980 /* Remove all dependencies associated with a task. This function is called when the task is destroyed.
982 static void __SD_task_remove_dependencies(SD_task_t task)
984 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
985 because each one is stored twice */
986 SD_dependency_t dependency;
987 while (xbt_dynar_length(task->tasks_before) > 0) {
988 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
989 SD_task_dependency_remove(dependency->src, dependency->dst);
992 while (xbt_dynar_length(task->tasks_after) > 0) {
993 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
994 SD_task_dependency_remove(dependency->src, dependency->dst);
999 * \brief Returns the start time of a task
1001 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1003 * \param task: a task
1004 * \return the start time of this task
1006 double SD_task_get_start_time(SD_task_t task)
1008 SD_CHECK_INIT_DONE();
1009 xbt_assert0(task != NULL, "Invalid parameter");
1010 if (task->surf_action)
1011 return surf_workstation_model->common_public->action_get_start_time(task->
1014 return task->start_time;
1018 * \brief Returns the finish time of a task
1020 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1021 * If the state is not completed yet, the returned value is an
1022 * estimation of the task finish time. This value can fluctuate
1023 * until the task is completed.
1025 * \param task: a task
1026 * \return the start time of this task
1028 double SD_task_get_finish_time(SD_task_t task)
1030 SD_CHECK_INIT_DONE();
1031 xbt_assert0(task != NULL, "Invalid parameter");
1033 if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
1034 return surf_workstation_model->common_public->
1035 action_get_finish_time(task->surf_action);
1037 return task->finish_time;
1041 * \brief Destroys a task.
1043 * The user data (if any) should have been destroyed first.
1045 * \param task the task you want to destroy
1046 * \see SD_task_create()
1048 void SD_task_destroy(SD_task_t task)
1050 SD_CHECK_INIT_DONE();
1051 xbt_assert0(task != NULL, "Invalid parameter");
1053 DEBUG1("Destroying task %s...", SD_task_get_name(task));
1055 __SD_task_remove_dependencies(task);
1057 /* if the task was scheduled or ready we have to free the scheduling parameters */
1058 if (__SD_task_is_scheduled_or_ready(task))
1059 __SD_task_destroy_scheduling_data(task);
1061 if (task->name != NULL)
1062 xbt_free(task->name);
1064 if (task->surf_action != NULL)
1065 surf_workstation_model->common_public->action_free(task->surf_action);
1067 if (task->workstation_list != NULL)
1068 xbt_free(task->workstation_list);
1070 xbt_dynar_free(&task->tasks_before);
1071 xbt_dynar_free(&task->tasks_after);
1074 sd_global->task_number--;
1076 DEBUG0("Task destroyed.");