1 /* Copyright (c) 2007-2009 Da SimGrid Team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
7 #include "simdag/simdag.h"
8 #include "xbt/sysdep.h"
11 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_task, sd,
12 "Logging specific to SimDag (task)");
14 static void __SD_task_remove_dependencies(SD_task_t task);
15 static void __SD_task_destroy_scheduling_data(SD_task_t task);
18 * \brief Creates a new task.
20 * \param name the name of the task (can be \c NULL)
21 * \param data the user data you want to associate with the task (can be \c NULL)
22 * \param amount amount of the task
23 * \return the new task
24 * \see SD_task_destroy()
26 SD_task_t SD_task_create(const char *name, void *data, double amount)
32 task = xbt_new(s_SD_task_t, 1);
34 /* general information */
35 task->data = data; /* user data */
37 task->name = xbt_strdup(name);
41 task->state_hookup.prev = NULL;
42 task->state_hookup.next = NULL;
43 task->state_set = sd_global->not_scheduled_task_set;
44 task->state = SD_NOT_SCHEDULED;
45 xbt_swag_insert(task, task->state_set);
47 task->amount = amount;
48 task->remains = amount;
49 task->start_time = -1.0;
50 task->finish_time = -1.0;
51 task->surf_action = NULL;
52 task->watch_points = 0;
55 task->tasks_before = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
56 task->tasks_after = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
58 /* scheduling parameters */
59 task->workstation_nb = 0;
60 task->workstation_list = NULL;
61 task->computation_amount = NULL;
62 task->communication_amount = NULL;
65 sd_global->task_number++;
71 * \brief Returns the user data of a task
74 * \return the user data associated with this task (can be \c NULL)
75 * \see SD_task_set_data()
77 void *SD_task_get_data(SD_task_t task)
80 xbt_assert0(task != NULL, "Invalid parameter");
85 * \brief Sets the user data of a task
87 * The new data can be \c NULL. The old data should have been freed first
88 * if it was not \c NULL.
91 * \param data the new data you want to associate with this task
92 * \see SD_task_get_data()
94 void SD_task_set_data(SD_task_t task, void *data)
97 xbt_assert0(task != NULL, "Invalid parameter");
102 * \brief Returns the state of a task
105 * \return the current \ref e_SD_task_state_t "state" of this task:
106 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_READY, #SD_RUNNING, #SD_DONE or #SD_FAILED
107 * \see e_SD_task_state_t
109 e_SD_task_state_t SD_task_get_state(SD_task_t task)
111 SD_CHECK_INIT_DONE();
112 xbt_assert0(task != NULL, "Invalid parameter");
116 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
118 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
120 xbt_swag_remove(task, task->state_set);
122 case SD_NOT_SCHEDULED:
123 task->state_set = sd_global->not_scheduled_task_set;
126 task->state_set = sd_global->scheduled_task_set;
129 task->state_set = sd_global->ready_task_set;
132 task->state_set = sd_global->in_fifo_task_set;
135 task->state_set = sd_global->running_task_set;
137 surf_workstation_model->action_get_start_time(task->surf_action);
140 task->state_set = sd_global->done_task_set;
142 surf_workstation_model->action_get_finish_time(task->surf_action);
146 task->state_set = sd_global->failed_task_set;
149 xbt_assert0(0, "Invalid state");
151 xbt_swag_insert(task, task->state_set);
152 task->state = new_state;
154 if (task->watch_points & new_state) {
155 INFO1("Watch point reached with task '%s'!", SD_task_get_name(task));
156 sd_global->watch_point_reached = 1;
157 SD_task_unwatch(task, new_state); /* remove the watch point */
162 * \brief Returns the name of a task
165 * \return the name of this task (can be \c NULL)
167 const char *SD_task_get_name(SD_task_t task)
169 SD_CHECK_INIT_DONE();
170 xbt_assert0(task != NULL, "Invalid parameter");
175 * \brief Returns the total amount of a task
178 * \return the total amount of this task
179 * \see SD_task_get_remaining_amount()
181 double SD_task_get_amount(SD_task_t task)
183 SD_CHECK_INIT_DONE();
184 xbt_assert0(task != NULL, "Invalid parameter");
189 * \brief Returns the remaining amount of a task
192 * \return the remaining amount of this task
193 * \see SD_task_get_amount()
195 double SD_task_get_remaining_amount(SD_task_t task)
197 SD_CHECK_INIT_DONE();
198 xbt_assert0(task != NULL, "Invalid parameter");
200 if (task->surf_action)
201 return surf_workstation_model->get_remains(task->surf_action);
203 return task->remains;
206 /* temporary function for debbuging */
207 static void __SD_print_dependencies(SD_task_t task)
212 SD_dependency_t dependency;
214 INFO1("The following tasks must be executed before %s:",
215 SD_task_get_name(task));
216 dynar = task->tasks_before;
217 length = xbt_dynar_length(dynar);
220 for (i = 0; i < length; i++) {
221 xbt_dynar_get_cpy(dynar, i, &dependency);
222 INFO1(" %s", SD_task_get_name(dependency->src));
225 INFO1("The following tasks must be executed after %s:",
226 SD_task_get_name(task));
228 dynar = task->tasks_after;
229 length = xbt_dynar_length(dynar);
230 for (i = 0; i < length; i++) {
231 xbt_dynar_get_cpy(dynar, i, &dependency);
232 INFO1(" %s", SD_task_get_name(dependency->dst));
234 INFO0("----------------------------");
237 /* Destroys a dependency between two tasks.
239 static void __SD_task_dependency_destroy(void *dependency)
241 if (((SD_dependency_t) dependency)->name != NULL)
242 xbt_free(((SD_dependency_t) dependency)->name);
243 xbt_free(dependency);
247 * \brief Adds a dependency between two tasks
249 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
250 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_READY.
252 * \param name the name of the new dependency (can be \c NULL)
253 * \param data the user data you want to associate with this dependency (can be \c NULL)
254 * \param src the task which must be executed first
255 * \param dst the task you want to make depend on \a src
256 * \see SD_task_dependency_remove()
258 void SD_task_dependency_add(const char *name, void *data, SD_task_t src,
265 SD_dependency_t dependency;
267 SD_CHECK_INIT_DONE();
268 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
270 dynar = src->tasks_after;
271 length = xbt_dynar_length(dynar);
277 "Cannot add a dependency between task '%s' and itself",
278 SD_task_get_name(src));
280 if (!__SD_task_is_not_scheduled(src)
281 && !__SD_task_is_scheduled_or_ready(src))
283 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY",
284 SD_task_get_name(src));
286 if (!__SD_task_is_not_scheduled(dst)
287 && !__SD_task_is_scheduled_or_ready(dst))
289 "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY",
290 SD_task_get_name(dst));
292 DEBUG2("SD_task_dependency_add: src = %s, dst = %s", SD_task_get_name(src),
293 SD_task_get_name(dst));
294 for (i = 0; i < length && !found; i++) {
295 xbt_dynar_get_cpy(dynar, i, &dependency);
296 found = (dependency->dst == dst);
297 DEBUG2("Dependency %d: dependency->dst = %s", i,
298 SD_task_get_name(dependency->dst));
303 "A dependency already exists between task '%s' and task '%s'",
304 SD_task_get_name(src), SD_task_get_name(dst));
306 dependency = xbt_new(s_SD_dependency_t, 1);
309 dependency->name = xbt_strdup(name);
311 dependency->name = NULL;
313 dependency->data = data;
314 dependency->src = src;
315 dependency->dst = dst;
317 /* src must be executed before dst */
318 xbt_dynar_push(src->tasks_after, &dependency);
319 xbt_dynar_push(dst->tasks_before, &dependency);
321 /* if the task was ready, then dst->tasks_before is not empty anymore,
322 so we must go back to state SD_SCHEDULED */
323 if (__SD_task_is_ready(dst)) {
324 DEBUG1("SD_task_dependency_add: %s was ready and becomes scheduled!",
325 SD_task_get_name(dst));
326 __SD_task_set_state(dst, SD_SCHEDULED);
329 /* __SD_print_dependencies(src);
330 __SD_print_dependencies(dst); */
334 * \brief Indacates whether there is a dependency between two tasks.
337 * \param dst a task depending on \a src
339 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst)
344 SD_dependency_t dependency;
346 SD_CHECK_INIT_DONE();
347 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
349 dynar = src->tasks_after;
350 length = xbt_dynar_length(dynar);
352 for (i = 0; i < length; i++) {
353 xbt_dynar_get_cpy(dynar, i, &dependency);
354 if (dependency->dst == dst)
361 * \brief Remove a dependency between two tasks
364 * \param dst a task depending on \a src
365 * \see SD_task_dependency_add()
367 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
374 SD_dependency_t dependency;
376 SD_CHECK_INIT_DONE();
377 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
379 /* remove the dependency from src->tasks_after */
380 dynar = src->tasks_after;
381 length = xbt_dynar_length(dynar);
383 for (i = 0; i < length && !found; i++) {
384 xbt_dynar_get_cpy(dynar, i, &dependency);
385 if (dependency->dst == dst) {
386 xbt_dynar_remove_at(dynar, i, NULL);
392 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
393 SD_task_get_name(src), SD_task_get_name(dst),
394 SD_task_get_name(dst), SD_task_get_name(src));
396 /* remove the dependency from dst->tasks_before */
397 dynar = dst->tasks_before;
398 length = xbt_dynar_length(dynar);
401 for (i = 0; i < length && !found; i++) {
402 xbt_dynar_get_cpy(dynar, i, &dependency);
403 if (dependency->src == src) {
404 xbt_dynar_remove_at(dynar, i, NULL);
405 __SD_task_dependency_destroy(dependency);
409 /* should never happen... */
411 "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
412 SD_task_get_name(dst), SD_task_get_name(src),
413 SD_task_get_name(src), SD_task_get_name(dst));
415 /* if the task was scheduled and dst->tasks_before is empty now, we can make it ready */
416 if (xbt_dynar_length(dst->tasks_before) == 0 && __SD_task_is_scheduled(dst))
417 __SD_task_set_state(dst, SD_READY);
419 /* __SD_print_dependencies(src);
420 __SD_print_dependencies(dst); */
424 * \brief Returns the user data associated with a dependency between two tasks
427 * \param dst a task depending on \a src
428 * \return the user data associated with this dependency (can be \c NULL)
429 * \see SD_task_dependency_add()
431 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst)
438 SD_dependency_t dependency;
441 SD_CHECK_INIT_DONE();
442 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
444 dynar = src->tasks_after;
445 length = xbt_dynar_length(dynar);
447 for (i = 0; i < length && !found; i++) {
448 xbt_dynar_get_cpy(dynar, i, &dependency);
449 found = (dependency->dst == dst);
452 THROW2(arg_error, 0, "No dependency found between task '%s' and '%s'",
453 SD_task_get_name(src), SD_task_get_name(dst));
454 return dependency->data;
457 /* temporary function for debugging */
458 static void __SD_print_watch_points(SD_task_t task)
460 static const int state_masks[] =
461 { SD_SCHEDULED, SD_RUNNING, SD_READY, SD_DONE, SD_FAILED };
462 static const char *state_names[] =
463 { "scheduled", "running", "ready", "done", "failed" };
466 INFO2("Task '%s' watch points (%x): ", SD_task_get_name(task),
470 for (i = 0; i < 5; i++) {
471 if (task->watch_points & state_masks[i])
472 INFO1("%s ", state_names[i]);
477 * \brief Adds a watch point to a task
479 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
480 * task becomes the one given in argument. The
481 * watch point is then automatically removed.
484 * \param state the \ref e_SD_task_state_t "state" you want to watch
485 * (cannot be #SD_NOT_SCHEDULED)
486 * \see SD_task_unwatch()
488 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
490 SD_CHECK_INIT_DONE();
491 xbt_assert0(task != NULL, "Invalid parameter");
493 if (state & SD_NOT_SCHEDULED)
495 "Cannot add a watch point for state SD_NOT_SCHEDULED");
497 task->watch_points = task->watch_points | state;
498 /* __SD_print_watch_points(task); */
502 * \brief Removes a watch point from a task
505 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
506 * \see SD_task_watch()
508 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
510 SD_CHECK_INIT_DONE();
511 xbt_assert0(task != NULL, "Invalid parameter");
512 xbt_assert0(state != SD_NOT_SCHEDULED,
513 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
515 task->watch_points = task->watch_points & ~state;
516 /* __SD_print_watch_points(task); */
520 * \brief Returns an approximative estimation of the execution time of a task.
522 * The estimation is very approximative because the value returned is the time
523 * the task would take if it was executed now and if it was the only task.
525 * \param task the task to evaluate
526 * \param workstation_nb number of workstations on which the task would be executed
527 * \param workstation_list the workstations on which the task would be executed
528 * \param computation_amount computation amount for each workstation
529 * \param communication_amount communication amount between each pair of workstations
530 * \param rate task execution speed rate
533 double SD_task_get_execution_time(SD_task_t task,
535 const SD_workstation_t * workstation_list,
536 const double *computation_amount,
537 const double *communication_amount,
540 double time, max_time = 0.0;
542 SD_CHECK_INIT_DONE();
543 xbt_assert0(task != NULL && workstation_nb > 0 && workstation_list != NULL
544 && computation_amount != NULL
545 && communication_amount != NULL, "Invalid parameter");
547 /* the task execution time is the maximum execution time of the parallel tasks */
549 for (i = 0; i < workstation_nb; i++) {
551 SD_workstation_get_computation_time(workstation_list[i],
552 computation_amount[i]);
554 for (j = 0; j < workstation_nb; j++) {
556 SD_route_get_communication_time(workstation_list[i],
558 communication_amount[i *
563 if (time > max_time) {
567 return max_time * SD_task_get_amount(task);
571 * \brief Schedules a task
573 * The task state must be #SD_NOT_SCHEDULED.
574 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
575 * i.e. when its dependencies are satisfied.
577 * \param task the task you want to schedule
578 * \param workstation_nb number of workstations on which the task will be executed
579 * \param workstation_list the workstations on which the task will be executed
580 * \param computation_amount computation amount for each workstation
581 * \param communication_amount communication amount between each pair of workstations
582 * \param rate task execution speed rate
583 * \see SD_task_unschedule()
585 void SD_task_schedule(SD_task_t task, int workstation_nb,
586 const SD_workstation_t * workstation_list,
587 const double *computation_amount,
588 const double *communication_amount, double rate)
591 int communication_nb;
593 SD_CHECK_INIT_DONE();
594 xbt_assert0(task != NULL, "Invalid parameter");
595 xbt_assert0(workstation_nb > 0, "workstation_nb must be positive");
597 if (!__SD_task_is_not_scheduled(task))
598 THROW1(arg_error, 0, "Task '%s' has already been scheduled",
599 SD_task_get_name(task));
601 task->workstation_nb = workstation_nb;
604 task->computation_amount = xbt_new(double, workstation_nb);
605 memcpy(task->computation_amount, computation_amount,
606 sizeof(double) * workstation_nb);
608 communication_nb = workstation_nb * workstation_nb;
609 task->communication_amount = xbt_new(double, communication_nb);
610 memcpy(task->communication_amount, communication_amount,
611 sizeof(double) * communication_nb);
613 task->workstation_list = xbt_new(SD_workstation_t, workstation_nb);
614 memcpy(task->workstation_list, workstation_list,
615 sizeof(SD_workstation_t) * workstation_nb);
617 /* update the task state */
618 if (xbt_dynar_length(task->tasks_before) == 0)
619 __SD_task_set_state(task, SD_READY);
621 __SD_task_set_state(task, SD_SCHEDULED);
625 * \brief Unschedules a task
627 * The task state must be #SD_SCHEDULED, #SD_READY, #SD_RUNNING or #SD_FAILED.
628 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
629 * Call SD_task_schedule() to schedule it again.
631 * \param task the task you want to unschedule
632 * \see SD_task_schedule()
634 void SD_task_unschedule(SD_task_t task)
636 SD_CHECK_INIT_DONE();
637 xbt_assert0(task != NULL, "Invalid parameter");
639 if (task->state_set != sd_global->scheduled_task_set &&
640 task->state_set != sd_global->ready_task_set &&
641 task->state_set != sd_global->running_task_set &&
642 task->state_set != sd_global->failed_task_set)
644 "Task %s: the state must be SD_SCHEDULED, SD_READY, SD_RUNNING or SD_FAILED",
645 SD_task_get_name(task));
647 if (__SD_task_is_scheduled_or_ready(task)) /* if the task is scheduled or ready */
648 __SD_task_destroy_scheduling_data(task);
650 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
651 surf_workstation_model->action_cancel(task->surf_action);
653 __SD_task_set_state(task, SD_NOT_SCHEDULED);
654 task->remains = task->amount;
655 task->start_time = -1.0;
658 /* Destroys the data memorised by SD_task_schedule. Task state must be SD_SCHEDULED or SD_READY.
660 static void __SD_task_destroy_scheduling_data(SD_task_t task)
662 SD_CHECK_INIT_DONE();
663 if (!__SD_task_is_scheduled_or_ready(task) && !__SD_task_is_in_fifo(task))
665 "Task '%s' must be SD_SCHEDULED, SD_READY or SD_IN_FIFO",
666 SD_task_get_name(task));
668 xbt_free(task->computation_amount);
669 xbt_free(task->communication_amount);
672 /* Runs a task. This function is directly called by __SD_task_try_to_run if the task
673 * doesn't have to wait in fifos. Otherwise, it is called by __SD_task_just_done when
674 * the task gets out of its fifos.
676 void __SD_task_really_run(SD_task_t task)
680 void **surf_workstations;
682 SD_CHECK_INIT_DONE();
683 xbt_assert0(task != NULL, "Invalid parameter");
684 xbt_assert2(__SD_task_is_ready_or_in_fifo(task),
685 "Task '%s' is not ready or in a fifo! Task state: %d",
686 SD_task_get_name(task), SD_task_get_state(task));
687 xbt_assert1(task->workstation_list != NULL,
688 "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
692 DEBUG1("Really running task '%s'", SD_task_get_name(task));
694 /* set this task as current task for the workstations in sequential mode */
695 for (i = 0; i < task->workstation_nb; i++) {
696 if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
697 SD_WORKSTATION_SEQUENTIAL_ACCESS) {
698 task->workstation_list[i]->current_task = task;
699 xbt_assert0(__SD_workstation_is_busy(task->workstation_list[i]),
700 "The workstation should be busy now");
704 DEBUG1("Task '%s' set as current task for its workstations",
705 SD_task_get_name(task));
709 /* we have to create a Surf workstation array instead of the SimDag workstation array */
710 surf_workstations = xbt_new(void *, task->workstation_nb);
712 for (i = 0; i < task->workstation_nb; i++) {
713 surf_workstations[i] = task->workstation_list[i]->surf_workstation;
716 task->surf_action = NULL;
717 if ((task->workstation_nb == 1) && (task->communication_amount[0] == 0.0)) {
719 surf_workstation_model->extension.
720 workstation.execute(surf_workstations[0], task->computation_amount[0]);
721 } else if ((task->workstation_nb == 1)
722 && (task->computation_amount[0] == 0.0)) {
724 surf_workstation_model->extension.
725 workstation.communicate(surf_workstations[0], surf_workstations[0],
726 task->communication_amount[0], task->rate);
727 } else if ((task->workstation_nb == 2)
728 && (task->computation_amount[0] == 0.0)
729 && (task->computation_amount[1] == 0.0)) {
733 for (i = 0; i < task->workstation_nb * task->workstation_nb; i++) {
734 if (task->communication_amount[i] > 0.0) {
736 value = task->communication_amount[i];
741 surf_workstation_model->extension.
742 workstation.communicate(surf_workstations[0], surf_workstations[1],
746 if (!task->surf_action) {
747 double *computation_amount = xbt_new(double, task->workstation_nb);
748 double *communication_amount = xbt_new(double, task->workstation_nb *
749 task->workstation_nb);
751 memcpy(computation_amount, task->computation_amount, sizeof(double) *
752 task->workstation_nb);
753 memcpy(communication_amount, task->communication_amount,
754 sizeof(double) * task->workstation_nb * task->workstation_nb);
757 surf_workstation_model->extension.
758 workstation.execute_parallel_task(task->workstation_nb,
759 surf_workstations, computation_amount,
760 communication_amount, task->amount,
763 xbt_free(surf_workstations);
766 surf_workstation_model->action_data_set(task->surf_action, task);
768 DEBUG1("surf_action = %p", task->surf_action);
770 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
771 __SD_task_set_state(task, SD_RUNNING);
772 xbt_assert2(__SD_task_is_running(task), "Bad state of task '%s': %d",
773 SD_task_get_name(task), SD_task_get_state(task));
777 /* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_READY
778 * (ie when its dependencies are satisfied).
779 * If one of the workstations where the task is scheduled on is busy (in sequential mode),
780 * the task doesn't start.
781 * Returns whether the task has started.
783 int __SD_task_try_to_run(SD_task_t task)
788 SD_workstation_t workstation;
790 SD_CHECK_INIT_DONE();
791 xbt_assert0(task != NULL, "Invalid parameter");
792 xbt_assert2(__SD_task_is_ready(task),
793 "Task '%s' is not ready! Task state: %d",
794 SD_task_get_name(task), SD_task_get_state(task));
797 for (i = 0; i < task->workstation_nb; i++) {
798 can_start = !__SD_workstation_is_busy(task->workstation_list[i]);
801 DEBUG2("Task '%s' can start: %d", SD_task_get_name(task), can_start);
803 if (!can_start) { /* if the task cannot start and is not in the fifos yet */
804 for (i = 0; i < task->workstation_nb; i++) {
805 workstation = task->workstation_list[i];
806 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
807 DEBUG2("Pushing task '%s' in the fifo of workstation '%s'",
808 SD_task_get_name(task), SD_workstation_get_name(workstation));
809 xbt_fifo_push(workstation->task_fifo, task);
812 __SD_task_set_state(task, SD_IN_FIFO);
813 xbt_assert2(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
814 SD_task_get_name(task), SD_task_get_state(task));
815 DEBUG1("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
817 __SD_task_really_run(task);
823 /* This function is called by SD_simulate when a task is done.
824 * It updates task->state and task->action and executes if necessary the tasks
825 * which were waiting in fifos for the end of `task'
827 void __SD_task_just_done(SD_task_t task)
830 SD_workstation_t workstation;
833 int candidate_nb = 0;
834 int candidate_capacity = 8;
835 SD_task_t *candidates;
838 SD_CHECK_INIT_DONE();
839 xbt_assert0(task != NULL, "Invalid parameter");
840 xbt_assert1(__SD_task_is_running(task),
841 "The task must be running! Task state: %d",
842 SD_task_get_state(task));
843 xbt_assert1(task->workstation_list != NULL,
844 "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
847 candidates = xbt_new(SD_task_t, 8);
849 __SD_task_set_state(task, SD_DONE);
850 surf_workstation_model->action_unref(task->surf_action);
851 task->surf_action = NULL;
853 DEBUG0("Looking for candidates");
855 /* if the task was executed on sequential workstations,
856 maybe we can execute the next task of the fifo for each workstation */
857 for (i = 0; i < task->workstation_nb; i++) {
858 workstation = task->workstation_list[i];
859 DEBUG2("Workstation '%s': access_mode = %d",
860 SD_workstation_get_name(workstation), workstation->access_mode);
861 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
862 xbt_assert1(workstation->task_fifo != NULL,
863 "Workstation '%s' has sequential access but no fifo!",
864 SD_workstation_get_name(workstation));
865 xbt_assert2(workstation->current_task =
866 task, "Workstation '%s': current task should be '%s'",
867 SD_workstation_get_name(workstation),
868 SD_task_get_name(task));
870 /* the task is over so we can release the workstation */
871 workstation->current_task = NULL;
873 DEBUG0("Getting candidate in fifo");
875 xbt_fifo_get_item_content(xbt_fifo_get_first_item
876 (workstation->task_fifo));
878 if (candidate != NULL) {
879 DEBUG1("Candidate: '%s'", SD_task_get_name(candidate));
880 xbt_assert2(__SD_task_is_in_fifo(candidate),
881 "Bad state of candidate '%s': %d",
882 SD_task_get_name(candidate),
883 SD_task_get_state(candidate));
886 DEBUG1("Candidate in fifo: %p", candidate);
888 /* if there was a task waiting for my place */
889 if (candidate != NULL) {
890 /* Unfortunately, we are not sure yet that we can execute the task now,
891 because the task can be waiting more deeply in some other workstation's fifos...
892 So we memorize all candidate tasks, and then we will check for each candidate
893 whether or not all its workstations are available. */
895 /* realloc if necessary */
896 if (candidate_nb == candidate_capacity) {
897 candidate_capacity *= 2;
899 xbt_realloc(candidates, sizeof(SD_task_t) * candidate_capacity);
902 /* register the candidate */
903 candidates[candidate_nb++] = candidate;
904 candidate->fifo_checked = 0;
909 DEBUG1("Candidates found: %d", candidate_nb);
911 /* now we check every candidate task */
912 for (i = 0; i < candidate_nb; i++) {
913 candidate = candidates[i];
915 if (candidate->fifo_checked) {
916 continue; /* we have already evaluated that task */
919 xbt_assert2(__SD_task_is_in_fifo(candidate),
920 "Bad state of candidate '%s': %d",
921 SD_task_get_name(candidate), SD_task_get_state(candidate));
923 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
924 workstation = candidate->workstation_list[j];
926 /* I can start on this workstation if the workstation is shared
927 or if I am the first task in the fifo */
928 can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS ||
930 xbt_fifo_get_item_content(xbt_fifo_get_first_item
931 (workstation->task_fifo));
934 DEBUG2("Candidate '%s' can start: %d", SD_task_get_name(candidate),
937 /* now we are sure that I can start! */
939 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
940 workstation = candidate->workstation_list[j];
942 /* update the fifo */
943 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
944 candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */
945 DEBUG1("Head of the fifo: '%s'",
946 (candidate != NULL) ? SD_task_get_name(candidate) : "NULL");
947 xbt_assert0(candidate == candidates[i],
948 "Error in __SD_task_just_done: bad first task in the fifo");
950 } /* for each workstation */
952 /* finally execute the task */
953 DEBUG2("Task '%s' state: %d", SD_task_get_name(candidate),
954 SD_task_get_state(candidate));
955 __SD_task_really_run(candidate);
958 ("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
959 SD_task_get_name(candidate), candidate->state_set,
960 sd_global->running_task_set, __SD_task_is_running(candidate));
961 xbt_assert2(__SD_task_is_running(candidate),
962 "Bad state of task '%s': %d", SD_task_get_name(candidate),
963 SD_task_get_state(candidate));
964 DEBUG0("Okay, the task is running.");
967 candidate->fifo_checked = 1;
968 } /* for each candidate */
970 xbt_free(candidates);
973 /* Remove all dependencies associated with a task. This function is called when the task is destroyed.
975 static void __SD_task_remove_dependencies(SD_task_t task)
977 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
978 because each one is stored twice */
979 SD_dependency_t dependency;
980 while (xbt_dynar_length(task->tasks_before) > 0) {
981 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
982 SD_task_dependency_remove(dependency->src, dependency->dst);
985 while (xbt_dynar_length(task->tasks_after) > 0) {
986 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
987 SD_task_dependency_remove(dependency->src, dependency->dst);
992 * \brief Returns the start time of a task
994 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
996 * \param task: a task
997 * \return the start time of this task
999 double SD_task_get_start_time(SD_task_t task)
1001 SD_CHECK_INIT_DONE();
1002 xbt_assert0(task != NULL, "Invalid parameter");
1003 if (task->surf_action)
1004 return surf_workstation_model->action_get_start_time(task->surf_action);
1006 return task->start_time;
1010 * \brief Returns the finish time of a task
1012 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
1013 * If the state is not completed yet, the returned value is an
1014 * estimation of the task finish time. This value can fluctuate
1015 * until the task is completed.
1017 * \param task: a task
1018 * \return the start time of this task
1020 double SD_task_get_finish_time(SD_task_t task)
1022 SD_CHECK_INIT_DONE();
1023 xbt_assert0(task != NULL, "Invalid parameter");
1025 if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
1026 return surf_workstation_model->action_get_finish_time(task->surf_action);
1028 return task->finish_time;
1032 * \brief Destroys a task.
1034 * The user data (if any) should have been destroyed first.
1036 * \param task the task you want to destroy
1037 * \see SD_task_create()
1039 void SD_task_destroy(SD_task_t task)
1041 SD_CHECK_INIT_DONE();
1042 xbt_assert0(task != NULL, "Invalid parameter");
1044 DEBUG1("Destroying task %s...", SD_task_get_name(task));
1046 __SD_task_remove_dependencies(task);
1048 /* if the task was scheduled or ready we have to free the scheduling parameters */
1049 if (__SD_task_is_scheduled_or_ready(task))
1050 __SD_task_destroy_scheduling_data(task);
1052 if (task->name != NULL)
1053 xbt_free(task->name);
1055 if (task->surf_action != NULL)
1056 surf_workstation_model->action_unref(task->surf_action);
1058 if (task->workstation_list != NULL)
1059 xbt_free(task->workstation_list);
1061 xbt_dynar_free(&task->tasks_before);
1062 xbt_dynar_free(&task->tasks_after);
1065 sd_global->task_number--;
1067 DEBUG0("Task destroyed.");