+ xbt_free(task->workstation_list);
+ task->workstation_list=NULL;
+ task->workstation_nb = 0;
+ }
+
+ if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
+ surf_action_cancel(task->surf_action);
+ else {
+ if (task->unsatisfied_dependencies == 0)
+ __SD_task_set_state(task, SD_SCHEDULABLE);
+ else
+ __SD_task_set_state(task, SD_NOT_SCHEDULED);
+ }
+ task->remains = task->amount;
+ task->start_time = -1.0;
+}
+
+/* Destroys the data memorized by SD_task_schedule.
+ * Task state must be SD_SCHEDULED or SD_RUNNABLE.
+ */
+static void __SD_task_destroy_scheduling_data(SD_task_t task)
+{
+ if (!__SD_task_is_scheduled_or_runnable(task)
+ && !__SD_task_is_in_fifo(task))
+ THROWF(arg_error, 0,
+ "Task '%s' must be SD_SCHEDULED, SD_RUNNABLE or SD_IN_FIFO",
+ SD_task_get_name(task));
+
+ xbt_free(task->flops_amount);
+ xbt_free(task->bytes_amount);
+ task->flops_amount = task->bytes_amount = NULL;
+}
+
+/* Runs a task. This function is directly called by __SD_task_try_to_run if
+ * the task doesn't have to wait in FIFOs. Otherwise, it is called by
+ * __SD_task_just_done when the task gets out of its FIFOs.
+ */
+void __SD_task_really_run(SD_task_t task)
+{
+
+ int i;
+ void **surf_hosts;
+
+ xbt_assert(__SD_task_is_runnable_or_in_fifo(task),
+ "Task '%s' is not runnable or in a fifo! Task state: %d",
+ SD_task_get_name(task), (int)SD_task_get_state(task));
+ xbt_assert(task->workstation_list != NULL,
+ "Task '%s': workstation_list is NULL!",
+ SD_task_get_name(task));
+
+ XBT_DEBUG("Really running task '%s'", SD_task_get_name(task));
+ int host_nb = task->workstation_nb;
+
+ /* set this task as current task for the workstations in sequential mode */
+ for (i = 0; i < host_nb; i++) {
+ if (SD_workstation_get_access_mode(task->workstation_list[i]) ==
+ SD_WORKSTATION_SEQUENTIAL_ACCESS) {
+ SD_workstation_priv(task->workstation_list[i])->current_task = task;
+ xbt_assert(__SD_workstation_is_busy(task->workstation_list[i]),
+ "The workstation should be busy now");
+ }
+ }
+
+ XBT_DEBUG("Task '%s' set as current task for its workstations",
+ SD_task_get_name(task));
+
+ /* start the task */
+
+ /* we have to create a Surf workstation array instead of the SimDag
+ * workstation array */
+ surf_hosts = xbt_new(void *, host_nb);
+
+ for (i = 0; i < host_nb; i++)
+ surf_hosts[i] = surf_host_resource_priv(task->workstation_list[i]);
+
+ double *flops_amount = xbt_new0(double, host_nb);
+ double *bytes_amount = xbt_new0(double, host_nb * host_nb);
+
+
+ if(task->flops_amount)
+ memcpy(flops_amount, task->flops_amount, sizeof(double) *
+ host_nb);
+ if(task->bytes_amount)
+ memcpy(bytes_amount, task->bytes_amount,
+ sizeof(double) * host_nb * host_nb);
+
+ task->surf_action = surf_host_model_execute_parallel_task((surf_host_model_t)surf_host_model,
+ host_nb,
+ surf_hosts,
+ flops_amount,
+ bytes_amount,
+ task->rate);
+
+ surf_action_set_data(task->surf_action, task);
+
+ XBT_DEBUG("surf_action = %p", task->surf_action);
+
+ if (task->category)
+ TRACE_surf_action(task->surf_action, task->category);
+
+ __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
+ __SD_task_set_state(task, SD_RUNNING);
+ xbt_assert(__SD_task_is_running(task), "Bad state of task '%s': %d",
+ SD_task_get_name(task), (int)SD_task_get_state(task));
+
+}
+
+/* Tries to run a task. This function is called by SD_simulate() when a
+ * scheduled task becomes SD_RUNNABLE (i.e., when its dependencies are
+ * satisfied).
+ * If one of the workstations where the task is scheduled on is busy (in
+ * sequential mode), the task doesn't start.
+ * Returns whether the task has started.
+ */
+int __SD_task_try_to_run(SD_task_t task)
+{
+
+ int can_start = 1;
+ int i;
+ SD_workstation_t workstation;
+
+ xbt_assert(__SD_task_is_runnable(task),
+ "Task '%s' is not runnable! Task state: %d",
+ SD_task_get_name(task), (int)SD_task_get_state(task));
+
+
+ for (i = 0; i < task->workstation_nb; i++) {
+ can_start = can_start &&
+ !__SD_workstation_is_busy(task->workstation_list[i]);
+ }
+
+ XBT_DEBUG("Task '%s' can start: %d", SD_task_get_name(task), can_start);
+
+ if (!can_start) { /* if the task cannot start and is not in the FIFOs yet */
+ for (i = 0; i < task->workstation_nb; i++) {
+ workstation = task->workstation_list[i];
+ if (SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
+ XBT_DEBUG("Pushing task '%s' in the FIFO of workstation '%s'",
+ SD_task_get_name(task),
+ SD_workstation_get_name(workstation));
+ xbt_fifo_push(SD_workstation_priv(workstation)->task_fifo, task);
+ }
+ }
+ __SD_task_set_state(task, SD_IN_FIFO);
+ xbt_assert(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
+ SD_task_get_name(task), (int)SD_task_get_state(task));
+ XBT_DEBUG("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
+ } else {
+ __SD_task_really_run(task);
+ }
+
+ return can_start;
+}
+
+/* This function is called by SD_simulate when a task is done.
+ * It updates task->state and task->action and executes if necessary the tasks
+ * which were waiting in FIFOs for the end of `task'
+ */
+void __SD_task_just_done(SD_task_t task)
+{
+ int i, j;
+ SD_workstation_t workstation;
+
+ SD_task_t candidate;
+ int candidate_nb = 0;
+ int candidate_capacity = 8;
+ SD_task_t *candidates;
+ int can_start = 1;
+
+ xbt_assert(__SD_task_is_running(task),
+ "The task must be running! Task state: %d",
+ (int)SD_task_get_state(task));
+ xbt_assert(task->workstation_list != NULL,
+ "Task '%s': workstation_list is NULL!",
+ SD_task_get_name(task));
+
+
+ candidates = xbt_new(SD_task_t, 8);
+
+ __SD_task_set_state(task, SD_DONE);
+ surf_action_unref(task->surf_action);
+ task->surf_action = NULL;
+
+ XBT_DEBUG("Looking for candidates");
+
+ /* if the task was executed on sequential workstations,
+ maybe we can execute the next task of the FIFO for each workstation */
+ for (i = 0; i < task->workstation_nb; i++) {
+ workstation = task->workstation_list[i];
+ XBT_DEBUG("Workstation '%s': access_mode = %d",
+ SD_workstation_get_name(workstation), (int)SD_workstation_priv(workstation)->access_mode);
+ if (SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
+ xbt_assert(SD_workstation_priv(workstation)->task_fifo != NULL,
+ "Workstation '%s' has sequential access but no FIFO!",
+ SD_workstation_get_name(workstation));
+ xbt_assert(SD_workstation_priv(workstation)->current_task =
+ task, "Workstation '%s': current task should be '%s'",
+ SD_workstation_get_name(workstation),
+ SD_task_get_name(task));
+
+ /* the task is over so we can release the workstation */
+ SD_workstation_priv(workstation)->current_task = NULL;
+
+ XBT_DEBUG("Getting candidate in FIFO");
+ candidate =
+ xbt_fifo_get_item_content(xbt_fifo_get_first_item
+ (SD_workstation_priv(workstation)->task_fifo));
+
+ if (candidate != NULL) {
+ XBT_DEBUG("Candidate: '%s'", SD_task_get_name(candidate));
+ xbt_assert(__SD_task_is_in_fifo(candidate),
+ "Bad state of candidate '%s': %d",
+ SD_task_get_name(candidate),
+ (int)SD_task_get_state(candidate));
+ }
+
+ XBT_DEBUG("Candidate in fifo: %p", candidate);
+
+ /* if there was a task waiting for my place */
+ if (candidate != NULL) {
+ /* Unfortunately, we are not sure yet that we can execute the task now,
+ because the task can be waiting more deeply in some other
+ workstation's FIFOs ...
+ So we memorize all candidate tasks, and then we will check for each
+ candidate whether or not all its workstations are available. */
+
+ /* realloc if necessary */
+ if (candidate_nb == candidate_capacity) {
+ candidate_capacity *= 2;
+ candidates =
+ xbt_realloc(candidates,
+ sizeof(SD_task_t) * candidate_capacity);
+ }
+
+ /* register the candidate */
+ candidates[candidate_nb++] = candidate;
+ candidate->fifo_checked = 0;
+ }
+ }
+ }
+
+ XBT_DEBUG("Candidates found: %d", candidate_nb);
+
+ /* now we check every candidate task */
+ for (i = 0; i < candidate_nb; i++) {
+ candidate = candidates[i];
+
+ if (candidate->fifo_checked) {
+ continue; /* we have already evaluated that task */
+ }
+
+ xbt_assert(__SD_task_is_in_fifo(candidate),
+ "Bad state of candidate '%s': %d",
+ SD_task_get_name(candidate), (int)SD_task_get_state(candidate));
+
+ for (j = 0; j < candidate->workstation_nb && can_start; j++) {
+ workstation = candidate->workstation_list[j];
+
+ /* I can start on this workstation if the workstation is shared
+ or if I am the first task in the FIFO */
+ can_start = SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SHARED_ACCESS
+ || candidate ==
+ xbt_fifo_get_item_content(xbt_fifo_get_first_item
+ (SD_workstation_priv(workstation)->task_fifo));
+ }
+
+ XBT_DEBUG("Candidate '%s' can start: %d", SD_task_get_name(candidate),
+ can_start);
+
+ /* now we are sure that I can start! */
+ if (can_start) {
+ for (j = 0; j < candidate->workstation_nb && can_start; j++) {
+ workstation = candidate->workstation_list[j];