X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/509e8eaf9d87061013538f79a0fba44865c58c0a..bb1158bb1e02c633571b8731326e1af36a86306a:/src/simdag/sd_task.c diff --git a/src/simdag/sd_task.c b/src/simdag/sd_task.c index ba5c414033..64870f97e7 100644 --- a/src/simdag/sd_task.c +++ b/src/simdag/sd_task.c @@ -1,3 +1,8 @@ +/* Copyright (c) 2007-2009 Da 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. */ + #include "private.h" #include "simdag/simdag.h" #include "xbt/sysdep.h" @@ -28,11 +33,8 @@ SD_task_t SD_task_create(const char *name, void *data, double amount) /* general information */ task->data = data; /* user data */ - if (name != NULL) - task->name = xbt_strdup(name); - else - task->name = NULL; - + task->name = xbt_strdup(name); + task->kind = 0; task->state_hookup.prev = NULL; task->state_hookup.next = NULL; task->state_set = sd_global->not_scheduled_task_set; @@ -129,14 +131,12 @@ void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state) case SD_RUNNING: task->state_set = sd_global->running_task_set; task->start_time = - surf_workstation_model->common_public.action_get_start_time(task-> - surf_action); + surf_workstation_model->action_get_start_time(task->surf_action); break; case SD_DONE: task->state_set = sd_global->done_task_set; task->finish_time = - surf_workstation_model->common_public.action_get_finish_time(task-> - surf_action); + surf_workstation_model->action_get_finish_time(task->surf_action); task->remains = 0; break; case SD_FAILED: @@ -168,6 +168,77 @@ const char *SD_task_get_name(SD_task_t task) return task->name; } +/** @brief Returns the dynar of the parents of a task + * + * \param task a task + * \return a newly allocated dynar comprising the parents of this task + */ + +xbt_dynar_t SD_task_get_parents(SD_task_t task) +{ + unsigned int i; + xbt_dynar_t parents; + SD_dependency_t dep; + SD_CHECK_INIT_DONE(); + xbt_assert0(task != NULL, "Invalid parameter"); + + parents = xbt_dynar_new(sizeof(SD_task_t), NULL); + xbt_dynar_foreach(task->tasks_before, i, dep){ + xbt_dynar_push(parents, &(dep->src)); + } + return parents; +} + +/** @brief Returns the dynar of the parents of a task + * + * \param task a task + * \return a newly allocated dynar comprising the parents of this task + */ +xbt_dynar_t SD_task_get_children(SD_task_t task) +{ + unsigned int i; + xbt_dynar_t children; + SD_dependency_t dep; + SD_CHECK_INIT_DONE(); + xbt_assert0(task != NULL, "Invalid parameter"); + + children = xbt_dynar_new(sizeof(SD_task_t), NULL); + xbt_dynar_foreach(task->tasks_after, i, dep){ + xbt_dynar_push(children, &(dep->dst)); + } + return children; +} + +/** + * \brief Returns the amount of workstations involved in a task + * + * Only call this on already scheduled tasks! + * \param task a task + */ +int SD_task_get_workstation_count(SD_task_t task) +{ + SD_CHECK_INIT_DONE(); + xbt_assert0(task != NULL, "Invalid parameter"); + // xbt_assert1( task->state_set != sd_global->scheduled_task_set, + // "Unscheduled task %s", task->name); + return task->workstation_nb; +} + +/** + * \brief Returns the list of workstations involved in a task + * + * Only call this on already scheduled tasks! + * \param task a task + */ +SD_workstation_t* SD_task_get_workstation_list(SD_task_t task) +{ + SD_CHECK_INIT_DONE(); + xbt_assert0(task != NULL, "Invalid parameter"); + //xbt_assert1( task->state_set != sd_global->scheduled_task_set, + // "Unscheduled task %s", task->name); + return task->workstation_list; +} + /** * \brief Returns the total amount of a task * @@ -195,40 +266,77 @@ double SD_task_get_remaining_amount(SD_task_t task) xbt_assert0(task != NULL, "Invalid parameter"); if (task->surf_action) - return task->surf_action->remains; + return surf_workstation_model->get_remains(task->surf_action); else return task->remains; } -/* temporary function for debbuging */ -static void __SD_print_dependencies(SD_task_t task) +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) { - xbt_dynar_t dynar; - int length; - int i; + unsigned int counter; SD_dependency_t dependency; - - INFO1("The following tasks must be executed before %s:", - SD_task_get_name(task)); - dynar = task->tasks_before; - length = xbt_dynar_length(dynar); - - - for (i = 0; i < length; i++) { - xbt_dynar_get_cpy(dynar, i, &dependency); - INFO1(" %s", SD_task_get_name(dependency->src)); + char *statename; + + INFO1("Displaying task %s",SD_task_get_name(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: + INFO0(" - kind: end-to-end communication"); + break; + case SD_TASK_COMP_SEQ: + INFO0(" - kind: sequential computation"); + break; + default: + INFO1(" - (unknown kind %d)",task->kind); + } } - - INFO1("The following tasks must be executed after %s:", - SD_task_get_name(task)); - - dynar = task->tasks_after; - length = xbt_dynar_length(dynar); - for (i = 0; i < length; i++) { - xbt_dynar_get_cpy(dynar, i, &dependency); - INFO1(" %s", SD_task_get_name(dependency->dst)); + 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) { + INFO1(" %s",SD_task_get_name(dependency->src)); + } + } + if (xbt_dynar_length(task->tasks_after)) { + INFO0(" - post-dependencies:"); + xbt_dynar_foreach(task->tasks_after,counter,dependency) { + INFO1(" %s",SD_task_get_name(dependency->dst)); + } + } +} +/** @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%d [label=\"%.20s\"",(unsigned int)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; + } + 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); } - INFO0("----------------------------"); } /* Destroys a dependency between two tasks. @@ -267,8 +375,6 @@ void SD_task_dependency_add(const char *name, void *data, SD_task_t src, dynar = src->tasks_after; length = xbt_dynar_length(dynar); - - if (src == dst) THROW1(arg_error, 0, "Cannot add a dependency between task '%s' and itself", @@ -302,11 +408,7 @@ void SD_task_dependency_add(const char *name, void *data, SD_task_t src, dependency = xbt_new(s_SD_dependency_t, 1); - if (name != NULL) - dependency->name = xbt_strdup(name); - else - dependency->name = NULL; - + dependency->name = xbt_strdup(name); /* xbt_strdup is cleaver enough to deal with NULL args itself */ dependency->data = data; dependency->src = src; dependency->dst = dst; @@ -332,24 +434,29 @@ void SD_task_dependency_add(const char *name, void *data, SD_task_t src, * * \param src a task * \param dst a task depending on \a src + * + * If src is NULL, checks whether dst has any pre-dependency. + * If dst is NULL, checks whether src has any post-dependency. */ int SD_task_dependency_exists(SD_task_t src, SD_task_t dst) { - xbt_dynar_t dynar; - int length; - int i; + unsigned int counter; SD_dependency_t dependency; SD_CHECK_INIT_DONE(); - xbt_assert0(src != NULL && dst != NULL, "Invalid parameter"); + xbt_assert0(src != NULL || dst != NULL, "Invalid parameter: both src and dst are NULL"); - dynar = src->tasks_after; - length = xbt_dynar_length(dynar); - - for (i = 0; i < length; i++) { - xbt_dynar_get_cpy(dynar, i, &dependency); - if (dependency->dst == dst) - return 1; + if (src) { + if (dst) { + xbt_dynar_foreach(src->tasks_after,counter,dependency) { + if (dependency->dst == dst) + return 1; + } + } else { + return xbt_dynar_length(src->tasks_after); + } + } else { + return xbt_dynar_length(dst->tasks_before); } return 0; } @@ -563,6 +670,19 @@ double SD_task_get_execution_time(SD_task_t task, } return max_time * SD_task_get_amount(task); } +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); +} /** * \brief Schedules a task @@ -579,45 +699,33 @@ 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); + task->computation_amount = xbt_new(double, workstation_count); memcpy(task->computation_amount, computation_amount, - sizeof(double) * workstation_nb); + sizeof(double) * workstation_count); - communication_nb = workstation_nb * workstation_nb; + communication_nb = workstation_count * workstation_count; task->communication_amount = xbt_new(double, communication_nb); memcpy(task->communication_amount, communication_amount, sizeof(double) * communication_nb); - 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 * @@ -645,7 +753,7 @@ void SD_task_unschedule(SD_task_t task) __SD_task_destroy_scheduling_data(task); if (__SD_task_is_running(task)) /* the task should become SD_FAILED */ - surf_workstation_model->common_public.action_cancel(task->surf_action); + surf_workstation_model->action_cancel(task->surf_action); else __SD_task_set_state(task, SD_NOT_SCHEDULED); task->remains = task->amount; @@ -713,18 +821,14 @@ void __SD_task_really_run(SD_task_t task) task->surf_action = NULL; if ((task->workstation_nb == 1) && (task->communication_amount[0] == 0.0)) { task->surf_action = - surf_workstation_model->extension_public->execute(surf_workstations[0], - task-> - computation_amount - [0]); + surf_workstation_model->extension. + workstation.execute(surf_workstations[0], task->computation_amount[0]); } else if ((task->workstation_nb == 1) && (task->computation_amount[0] == 0.0)) { task->surf_action = - surf_workstation_model-> - extension_public->communicate(surf_workstations[0], - surf_workstations[0], - task->communication_amount[0], - task->rate); + surf_workstation_model->extension. + workstation.communicate(surf_workstations[0], surf_workstations[0], + task->communication_amount[0], task->rate); } else if ((task->workstation_nb == 2) && (task->computation_amount[0] == 0.0) && (task->computation_amount[1] == 0.0)) { @@ -739,10 +843,9 @@ void __SD_task_really_run(SD_task_t task) } if (nb == 1) { task->surf_action = - surf_workstation_model-> - extension_public->communicate(surf_workstations[0], - surf_workstations[1], value, - task->rate); + surf_workstation_model->extension. + workstation.communicate(surf_workstations[0], surf_workstations[1], + value, task->rate); } } if (!task->surf_action) { @@ -756,21 +859,16 @@ void __SD_task_really_run(SD_task_t task) sizeof(double) * task->workstation_nb * task->workstation_nb); task->surf_action = - surf_workstation_model->extension_public->execute_parallel_task(task-> - workstation_nb, - surf_workstations, - computation_amount, - communication_amount, - task-> - amount, - task-> - rate); + surf_workstation_model->extension. + workstation.execute_parallel_task(task->workstation_nb, + surf_workstations, computation_amount, + communication_amount, task->amount, + task->rate); } else { xbt_free(surf_workstations); } - surf_workstation_model->common_public.action_set_data(task->surf_action, - task); + surf_workstation_model->action_data_set(task->surf_action, task); DEBUG1("surf_action = %p", task->surf_action); @@ -854,7 +952,7 @@ void __SD_task_just_done(SD_task_t task) candidates = xbt_new(SD_task_t, 8); __SD_task_set_state(task, SD_DONE); - surf_workstation_model->common_public.action_free(task->surf_action); + surf_workstation_model->action_unref(task->surf_action); task->surf_action = NULL; DEBUG0("Looking for candidates"); @@ -1008,8 +1106,7 @@ double SD_task_get_start_time(SD_task_t task) SD_CHECK_INIT_DONE(); xbt_assert0(task != NULL, "Invalid parameter"); if (task->surf_action) - return surf_workstation_model->common_public.action_get_start_time(task-> - surf_action); + return surf_workstation_model->action_get_start_time(task->surf_action); else return task->start_time; } @@ -1031,8 +1128,7 @@ double SD_task_get_finish_time(SD_task_t task) xbt_assert0(task != NULL, "Invalid parameter"); if (task->surf_action) /* should never happen as actions are destroyed right after their completion */ - return surf_workstation_model->common_public. - action_get_finish_time(task->surf_action); + return surf_workstation_model->action_get_finish_time(task->surf_action); else return task->finish_time; } @@ -1053,16 +1149,16 @@ 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); if (task->surf_action != NULL) - surf_workstation_model->common_public.action_free(task->surf_action); + surf_workstation_model->action_unref(task->surf_action); if (task->workstation_list != NULL) xbt_free(task->workstation_list); @@ -1075,3 +1171,141 @@ void SD_task_destroy(SD_task_t task) DEBUG0("Task destroyed."); } + + +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 + * allows to specify the task costs at creation, and decorelate them from the + * scheduling process where you just specify which resource should deliver the + * mandatory power. + * + * A end-to-end communication must be scheduled on 2 hosts, and the amount + * 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_sized(name,data,amount,2); + res->communication_amount[2] = amount; + res->kind=SD_TASK_COMM_E2E; + return res; +} +/** @brief create a sequential computation task that can then be auto-scheduled + * + * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This + * allows to specify the task costs at creation, and decorelate them from the + * scheduling process where you just specify which resource should deliver the + * mandatory power. + * + * A sequential computation must be scheduled on 1 host, and the 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_sized(name,data,amount,1); + res->computation_amount[0]=amount; + res->kind=SD_TASK_COMP_SEQ; + return res; +} + +/** @brief Auto-schedules a task. + * + * Auto-scheduling mean that the task can be used with SD_task_schedulev(). This + * allows to specify the task costs at creation, and decorelate them from the + * scheduling process where you just specify which resource should deliver the + * mandatory power. + * + * To be auto-schedulable, a task must be created with SD_task_create_comm_e2e() or + * SD_task_create_comp_seq(). Check their definitions for the exact semantic of each + * of them. + * + * @todo + * We should create tasks kind for the following categories: + * - Point to point communication (done) + * - Sequential computation (done) + * - group communication (redistribution, several kinds) + * - parallel tasks with no internal communication (one kind per speedup model such as amdal) + * - 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)); + switch(task->kind) { + case SD_TASK_COMM_E2E: + case SD_TASK_COMP_SEQ: + 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 + * + * This function is very similar to SD_task_schedulev(), + * but takes the list of workstations to schedule onto as separate parameters. + * It builds a proper vector of workstations and then call SD_task_schedulev() + */ +void SD_task_schedulel(SD_task_t task, int count, ...) { + va_list ap; + SD_workstation_t *list=xbt_new(SD_workstation_t,count); + int i; + va_start(ap,count); + for (i=0;i