-/* Copyright (c) 2007-2009 Da SimGrid Team. All rights reserved. */
+/* Copyright (c) 2006, 2007, 2008, 2009, 2010. The SimGrid Team.
+ * All rights reserved. */
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
/* general information */
task->data = data; /* user data */
task->name = xbt_strdup(name);
- task->kind = 0;
+ task->kind = SD_TASK_NOT_TYPED;
task->state_hookup.prev = NULL;
task->state_hookup.next = NULL;
task->state_set = sd_global->not_scheduled_task_set;
return task->name;
}
+/** @brief Allows to change the name of a task */
+void SD_task_set_name(SD_task_t task, const char *name) {
+ xbt_free(task->name);
+ task->name = xbt_strdup(name);
+}
+
/** @brief Returns the dynar of the parents of a task
*
* \param task a task
}
/**
- * \brief Returns the total amount of a task
+ * \brief Returns the total amount of work contained in a task
*
* \param task a task
- * \return the total amount of this task
+ * \return the total amount of work (computation or data transfer) for this task
* \see SD_task_get_remaining_amount()
*/
double SD_task_get_amount(SD_task_t task)
}
/**
- * \brief Returns the remaining amount of a task
+ * \brief Returns the remaining amount work to do till the completion of a task
*
* \param task a task
- * \return the remaining amount of this task
+ * \return the remaining amount of work (computation or data transfer) of this task
* \see SD_task_get_amount()
*/
double SD_task_get_remaining_amount(SD_task_t task)
return task->remains;
}
+int SD_task_get_kind(SD_task_t task) {
+ return task->kind;
+}
+
/** @brief Displays debugging informations about a task */
void SD_task_dump(SD_task_t task)
{
unsigned int counter;
SD_dependency_t dependency;
+ char *statename;
INFO1("Displaying task %s",SD_task_get_name(task));
- INFO1(" - amount: %.0f",SD_task_get_amount(task));
+ statename=bprintf("%s %s %s %s %s %s %s",
+ (task->state&SD_NOT_SCHEDULED?"not scheduled":""),
+ (task->state&SD_SCHEDULED?"scheduled":""),
+ (task->state&SD_READY?"ready":"not ready"),
+ (task->state&SD_IN_FIFO?"in fifo":""),
+ (task->state&SD_RUNNING?"running":""),
+ (task->state&SD_DONE?"done":""),
+ (task->state&SD_FAILED?"failed":""));
+ INFO1(" - state: %s",statename);
+ free(statename);
+
if (task->kind!=0) {
switch(task->kind){
case SD_TASK_COMM_E2E:
INFO1(" - (unknown kind %d)",task->kind);
}
}
+ INFO1(" - amount: %.0f",SD_task_get_amount(task));
if (xbt_dynar_length(task->tasks_before)) {
INFO0(" - pre-dependencies:");
xbt_dynar_foreach(task->tasks_before,counter,dependency) {
void SD_task_dotty(SD_task_t task,void* out) {
unsigned int counter;
SD_dependency_t dependency;
- fprintf(out, " T%d [label=\"%.10s\"",(unsigned int)task,task->name);
+ fprintf(out, " T%p [label=\"%.20s\"",task, task->name);
switch(task->kind){
case SD_TASK_COMM_E2E:
fprintf(out,", shape=box");
case SD_TASK_COMP_SEQ:
fprintf(out,", shape=circle");
break;
+ default:
+ xbt_die("Unknown task type!");
}
fprintf(out,"];\n");
xbt_dynar_foreach(task->tasks_before,counter,dependency) {
- fprintf(out," T%d -> T%d;\n",(unsigned int)dependency->src,(unsigned int)dependency->dst);
+ fprintf(out," T%p -> T%p;\n",dependency->src, dependency->dst);
}
}
* \param workstation_list the workstations on which the task would be executed
* \param computation_amount computation amount for each workstation
* \param communication_amount communication amount between each pair of workstations
- * \param rate task execution speed rate
* \see SD_schedule()
*/
double SD_task_get_execution_time(SD_task_t task,
int workstation_nb,
const SD_workstation_t * workstation_list,
const double *computation_amount,
- const double *communication_amount,
- double rate)
+ const double *communication_amount)
{
double time, max_time = 0.0;
int i, j;
SD_CHECK_INIT_DONE();
- xbt_assert0(task != NULL && workstation_nb > 0 && workstation_list != NULL
- && computation_amount != NULL
- && communication_amount != NULL, "Invalid parameter");
+ xbt_assert0(task != NULL && workstation_nb > 0 && workstation_list != NULL,
+ "Invalid parameter");
/* the task execution time is the maximum execution time of the parallel tasks */
for (i = 0; i < workstation_nb; i++) {
- time =
- SD_workstation_get_computation_time(workstation_list[i],
- computation_amount[i]);
-
- for (j = 0; j < workstation_nb; j++) {
- time +=
- SD_route_get_communication_time(workstation_list[i],
- workstation_list[j],
- communication_amount[i *
- workstation_nb +
- j]);
- }
+ time = 0.0;
+ if (computation_amount != NULL)
+ time =
+ SD_workstation_get_computation_time(workstation_list[i],
+ computation_amount[i]);
+
+ if (communication_amount != NULL)
+ for (j = 0; j < workstation_nb; j++) {
+ time +=
+ SD_route_get_communication_time(workstation_list[i],
+ workstation_list[j],
+ communication_amount[i *
+ workstation_nb +
+ j]);
+ }
if (time > max_time) {
max_time = time;
}
}
- return max_time * SD_task_get_amount(task);
+ return max_time;
+}
+static inline void SD_task_do_schedule(SD_task_t task) {
+ SD_CHECK_INIT_DONE();
+
+ if (!__SD_task_is_not_scheduled(task))
+ THROW1(arg_error, 0, "Task '%s' has already been scheduled",
+ SD_task_get_name(task));
+
+ /* update the task state */
+ if (xbt_dynar_length(task->tasks_before) == 0)
+ __SD_task_set_state(task, SD_READY);
+ else
+ __SD_task_set_state(task, SD_SCHEDULED);
}
/**
* \param rate task execution speed rate
* \see SD_task_unschedule()
*/
-void SD_task_schedule(SD_task_t task, int workstation_nb,
+void SD_task_schedule(SD_task_t task, int workstation_count,
const SD_workstation_t * workstation_list,
const double *computation_amount,
const double *communication_amount, double rate)
{
+ xbt_assert0(workstation_count > 0, "workstation_nb must be positive");
int communication_nb;
- SD_CHECK_INIT_DONE();
- xbt_assert0(task != NULL, "Invalid parameter");
- xbt_assert0(workstation_nb > 0, "workstation_nb must be positive");
-
- if (!__SD_task_is_not_scheduled(task))
- THROW1(arg_error, 0, "Task '%s' has already been scheduled",
- SD_task_get_name(task));
-
- task->workstation_nb = workstation_nb;
+ task->workstation_nb = workstation_count;
task->rate = rate;
- task->computation_amount = xbt_new(double, workstation_nb);
- memcpy(task->computation_amount, computation_amount,
- sizeof(double) * workstation_nb);
+ if (computation_amount) {
+ task->computation_amount = xbt_new(double, workstation_count);
+ memcpy(task->computation_amount, computation_amount,
+ sizeof(double) * workstation_count);
+ } else {
+ task->computation_amount = NULL;
+ }
- communication_nb = workstation_nb * workstation_nb;
- task->communication_amount = xbt_new(double, communication_nb);
- memcpy(task->communication_amount, communication_amount,
- sizeof(double) * communication_nb);
+ communication_nb = workstation_count * workstation_count;
+ if (communication_amount) {
+ task->communication_amount = xbt_new(double, communication_nb);
+ memcpy(task->communication_amount, communication_amount,
+ sizeof(double) * communication_nb);
+ } else {
+ task->communication_amount = NULL;
+ }
- task->workstation_list = xbt_new(SD_workstation_t, workstation_nb);
+ task->workstation_list = xbt_new(SD_workstation_t, workstation_count);
memcpy(task->workstation_list, workstation_list,
- sizeof(SD_workstation_t) * workstation_nb);
+ sizeof(SD_workstation_t) * workstation_count);
- /* update the task state */
- if (xbt_dynar_length(task->tasks_before) == 0)
- __SD_task_set_state(task, SD_READY);
- else
- __SD_task_set_state(task, SD_SCHEDULED);
+ SD_task_do_schedule(task);
}
-
/**
* \brief Unschedules a task
*
"Task %s: the state must be SD_SCHEDULED, SD_READY, SD_RUNNING or SD_FAILED",
SD_task_get_name(task));
- if (__SD_task_is_scheduled_or_ready(task)) /* if the task is scheduled or ready */
+ if (__SD_task_is_scheduled_or_ready(task) /* if the task is scheduled or ready */
+ && task->kind == SD_TASK_NOT_TYPED) /* Don't free scheduling data for typed tasks */
__SD_task_destroy_scheduling_data(task);
if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
xbt_free(task->computation_amount);
xbt_free(task->communication_amount);
+ task->computation_amount = task->communication_amount = NULL;
}
/* Runs a task. This function is directly called by __SD_task_try_to_run if the task
/* we have to create a Surf workstation array instead of the SimDag workstation array */
surf_workstations = xbt_new(void *, task->workstation_nb);
- for (i = 0; i < task->workstation_nb; i++) {
+ for (i = 0; i < task->workstation_nb; i++)
surf_workstations[i] = task->workstation_list[i]->surf_workstation;
- }
+
+ /* It's allowed to pass a NULL vector as cost to mean vector of 0.0 (easing user's life). Let's deal with it */
+#define cost_or_zero(array,pos) ((array)?(array)[pos]:0.0)
task->surf_action = NULL;
- if ((task->workstation_nb == 1) && (task->communication_amount[0] == 0.0)) {
+ if ((task->workstation_nb == 1) && (cost_or_zero(task->communication_amount,0) == 0.0)) {
task->surf_action =
surf_workstation_model->extension.
- workstation.execute(surf_workstations[0], task->computation_amount[0]);
+ workstation.execute(surf_workstations[0], cost_or_zero(task->computation_amount,0));
} else if ((task->workstation_nb == 1)
- && (task->computation_amount[0] == 0.0)) {
+ && (cost_or_zero(task->computation_amount,0) == 0.0)) {
+
task->surf_action =
surf_workstation_model->extension.
workstation.communicate(surf_workstations[0], surf_workstations[0],
- task->communication_amount[0], task->rate);
+ cost_or_zero(task->communication_amount,0), task->rate);
} else if ((task->workstation_nb == 2)
- && (task->computation_amount[0] == 0.0)
- && (task->computation_amount[1] == 0.0)) {
+ && (cost_or_zero(task->computation_amount,0) == 0.0)
+ && (cost_or_zero(task->computation_amount,1) == 0.0)) {
int nb = 0;
double value = 0.0;
for (i = 0; i < task->workstation_nb * task->workstation_nb; i++) {
- if (task->communication_amount[i] > 0.0) {
+ if (cost_or_zero(task->communication_amount,i) > 0.0) {
nb++;
- value = task->communication_amount[i];
+ value = cost_or_zero(task->communication_amount,i);
}
}
if (nb == 1) {
value, task->rate);
}
}
+#undef cost_or_zero
+
if (!task->surf_action) {
double *computation_amount = xbt_new(double, task->workstation_nb);
double *communication_amount = xbt_new(double, task->workstation_nb *
DEBUG1("Destroying task %s...", SD_task_get_name(task));
__SD_task_remove_dependencies(task);
-
/* if the task was scheduled or ready we have to free the scheduling parameters */
if (__SD_task_is_scheduled_or_ready(task))
__SD_task_destroy_scheduling_data(task);
+ xbt_swag_remove(task,task->state_set);
if (task->name != NULL)
xbt_free(task->name);
if (task->workstation_list != NULL)
xbt_free(task->workstation_list);
+ if (task->communication_amount)
+ xbt_free(task->communication_amount);
+
+ if (task->computation_amount)
+ xbt_free(task->computation_amount);
+
xbt_dynar_free(&task->tasks_before);
xbt_dynar_free(&task->tasks_after);
xbt_free(task);
}
+static inline SD_task_t SD_task_create_sized(const char*name,void*data,double amount,int ws_count) {
+ SD_task_t task = SD_task_create(name,data,amount);
+ task->communication_amount = xbt_new0(double,ws_count*ws_count);
+ task->computation_amount = xbt_new0(double,ws_count);
+ task->workstation_nb = ws_count;
+ task->workstation_list = xbt_new0(SD_workstation_t,ws_count);
+ return task;
+}
/** @brief create a end-to-end communication task that can then be auto-scheduled
*
* Auto-scheduling mean that the task can be used with SD_task_schedulev(). This
* specified at creation is sent from hosts[0] to hosts[1].
*/
SD_task_t SD_task_create_comm_e2e(const char*name, void *data, double amount) {
- SD_task_t res = SD_task_create(name,data,amount);
+ SD_task_t res = SD_task_create_sized(name,data,amount,2);
+ res->communication_amount[2] = amount;
res->kind=SD_TASK_COMM_E2E;
return res;
}
* specified at creation to be run on hosts[0].
*/
SD_task_t SD_task_create_comp_seq(const char*name, void *data, double amount) {
- SD_task_t res = SD_task_create(name,data,amount);
+ SD_task_t res = SD_task_create_sized(name,data,amount,1);
+ res->computation_amount[0]=amount;
res->kind=SD_TASK_COMP_SEQ;
return res;
}
* - idem+ internal communication. Task type not enough since we cannot store comm cost alongside to comp one)
*/
void SD_task_schedulev(SD_task_t task, int count, const SD_workstation_t*list) {
+ int i;
xbt_assert1(task->kind != 0,"Task %s is not typed. Cannot automatically schedule it.",SD_task_get_name(task));
- double *comp,*comms;
switch(task->kind) {
case SD_TASK_COMM_E2E:
- xbt_assert2(count == 2,
- "Task %s is end to end communication, but scheduled with %d hosts",
- SD_task_get_name(task),count);
- comms=xbt_new(double,count);
- comms[0]=0;
- comms[1]=SD_task_get_amount(task);
- SD_task_schedule(task,count,list,NULL,comms,1);
- break;
case SD_TASK_COMP_SEQ:
- xbt_assert2(count==1,
- "Task %s is sequential computation, but scheduled with %d hosts",
- SD_task_get_name(task),count);
- comp=xbt_new(double,count);
- comp[0]=SD_task_get_amount(task);
- SD_task_schedule(task,count,list,comp,NULL,1);
+ xbt_assert(task->workstation_nb==count);
+ for (i=0;i<count;i++)
+ task->workstation_list[i]=list[i];
+ SD_task_do_schedule(task);
break;
default:
xbt_die(bprintf("Kind of task %s not supported by SD_task_schedulev()",
SD_task_get_name(task)));
}
+ if (task->kind == SD_TASK_COMM_E2E) {
+ VERB4("Schedule comm task %s between %s -> %s. It costs %.f bytes",
+ SD_task_get_name(task),
+ SD_workstation_get_name(task->workstation_list[0]),SD_workstation_get_name(task->workstation_list[1]),
+ task->communication_amount[2]);
+
+ }
+ /* Iterate over all childs and parent being COMM_E2E to say where I am located (and start them if ready) */
+ if (task->kind == SD_TASK_COMP_SEQ) {
+ VERB3("Schedule computation task %s on %s. It costs %.f flops",
+ SD_task_get_name(task),SD_workstation_get_name(task->workstation_list[0]),
+ task->computation_amount[0]);
+ SD_dependency_t dep;
+ unsigned int cpt;
+ xbt_dynar_foreach(task->tasks_before,cpt,dep) {
+ SD_task_t before = dep->src;
+ if (before->kind == SD_TASK_COMM_E2E) {
+ before->workstation_list[1] = task->workstation_list[0];
+ if (before->workstation_list[0] && __SD_task_is_not_scheduled(before)) {
+ SD_task_do_schedule(before);
+ VERB4("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
+ SD_task_get_name(before),
+ SD_workstation_get_name(before->workstation_list[0]),SD_workstation_get_name(before->workstation_list[1]),
+ before->communication_amount[2]);
+ }
+ }
+ }
+ xbt_dynar_foreach(task->tasks_after,cpt,dep) {
+ SD_task_t after = dep->dst;
+ if (after->kind == SD_TASK_COMM_E2E) {
+ after->workstation_list[0] = task->workstation_list[0];
+ if (after->workstation_list[1] && __SD_task_is_not_scheduled(after)) {
+ SD_task_do_schedule(after);
+ VERB4("Auto-Schedule comm task %s between %s -> %s. It costs %.f bytes",
+ SD_task_get_name(after),
+ SD_workstation_get_name(after->workstation_list[0]),SD_workstation_get_name(after->workstation_list[1]),
+ after->communication_amount[2]);
+
+ }
+ }
+ }
+ }
}
/** @brief autoschedule a task on a list of workstations
*
}
va_end(ap);
SD_task_schedulev(task,count,list);
+ free(list);
}