X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/a0cc317cf14daa574791724e79d9480a9372613d..c065f0f21ab43fa2749e992b3e14a68f88f8ffb1:/src/simdag/sd_task.c diff --git a/src/simdag/sd_task.c b/src/simdag/sd_task.c index 101c92cab2..42e71c0469 100644 --- a/src/simdag/sd_task.c +++ b/src/simdag/sd_task.c @@ -34,7 +34,7 @@ SD_task_t SD_task_create(const char *name, void *data, double amount) /* 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; @@ -168,6 +168,12 @@ const char *SD_task_get_name(SD_task_t task) 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 @@ -240,10 +246,10 @@ SD_workstation_t* SD_task_get_workstation_list(SD_task_t 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) @@ -254,10 +260,10 @@ 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) @@ -271,14 +277,29 @@ double SD_task_get_remaining_amount(SD_task_t task) return task->remains; } -/* temporary function for debbuging */ +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: @@ -291,6 +312,7 @@ void SD_task_dump(SD_task_t task) 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) { @@ -304,6 +326,26 @@ void SD_task_dump(SD_task_t task) } } } +/** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */ +void SD_task_dotty(SD_task_t task,void* out) { + unsigned int counter; + SD_dependency_t dependency; + fprintf(out, " T%p [label=\"%.20s\"",task, task->name); + switch(task->kind){ + case SD_TASK_COMM_E2E: + fprintf(out,", shape=box"); + break; + 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%p -> T%p;\n",dependency->src, dependency->dst); + } +} /* Destroys a dependency between two tasks. */ @@ -597,44 +639,57 @@ void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state) * \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); } /** @@ -652,45 +707,41 @@ double SD_task_get_execution_time(SD_task_t task, * \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 * @@ -714,7 +765,8 @@ void SD_task_unschedule(SD_task_t 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 */ @@ -737,6 +789,7 @@ static void __SD_task_destroy_scheduling_data(SD_task_t task) 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 @@ -779,31 +832,34 @@ void __SD_task_really_run(SD_task_t 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) { @@ -813,6 +869,8 @@ void __SD_task_really_run(SD_task_t task) 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 * @@ -1114,10 +1172,10 @@ void SD_task_destroy(SD_task_t task) 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); @@ -1128,6 +1186,12 @@ void SD_task_destroy(SD_task_t task) 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); @@ -1138,6 +1202,14 @@ void SD_task_destroy(SD_task_t 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 @@ -1149,7 +1221,8 @@ void SD_task_destroy(SD_task_t task) * 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; } @@ -1164,7 +1237,8 @@ SD_task_t SD_task_create_comm_e2e(const char*name, void *data, double amount) { * 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; } @@ -1189,30 +1263,62 @@ SD_task_t SD_task_create_comp_seq(const char*name, void *data, double amount) { * - 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;iworkstation_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 * @@ -1230,4 +1336,5 @@ void SD_task_schedulel(SD_task_t task, int count, ...) { } va_end(ap); SD_task_schedulev(task,count,list); + free(list); }