From 0c4998db54add422f8b4fbb7410a75d032ef2ff9 Mon Sep 17 00:00:00 2001 From: thiery Date: Mon, 31 Jul 2006 09:40:31 +0000 Subject: [PATCH] Add a sequential mode to the workstations. In this mode, only one task can be executed on the workstation and the other wait in a fifo. git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@2652 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- examples/simdag/sd_test.c | 14 +-- include/simdag/datatypes.h | 24 +++- include/simdag/simdag.h | 3 + src/simdag/private.h | 27 ++++- src/simdag/sd_global.c | 44 +++---- src/simdag/sd_task.c | 233 +++++++++++++++++++++++++++++++++--- src/simdag/sd_workstation.c | 83 ++++++++++++- 7 files changed, 374 insertions(+), 54 deletions(-) diff --git a/examples/simdag/sd_test.c b/examples/simdag/sd_test.c index a54db33104..b791034a7d 100644 --- a/examples/simdag/sd_test.c +++ b/examples/simdag/sd_test.c @@ -13,7 +13,7 @@ int main(int argc, char **argv) { /* initialisation of SD */ SD_init(&argc, argv); - /* xbt_log_control_set("sd.thres=debug"); */ + /* xbt_log_control_set("sd.thres=debug");*/ if (argc < 2) { INFO1("Usage: %s platform_file", argv[0]); @@ -29,6 +29,7 @@ int main(int argc, char **argv) { const SD_workstation_t *workstations = SD_workstation_get_list(); SD_workstation_t w1 = workstations[0]; SD_workstation_t w2 = workstations[1]; + SD_workstation_set_access_mode(w2, SD_WORKSTATION_SEQUENTIAL_ACCESS); const char *name1 = SD_workstation_get_name(w1); const char *name2 = SD_workstation_get_name(w2); const double computation_amount1 = 2000000; @@ -151,12 +152,6 @@ int main(int argc, char **argv) { SD_task_t *changed_tasks; changed_tasks = SD_simulate(-1.0); - xbt_assert0(changed_tasks[0] == taskD && - changed_tasks[1] == taskB && - changed_tasks[2] == taskC && - changed_tasks[3] == NULL, - "Unexpected simulation results"); - for (i = 0; changed_tasks[i] != NULL; i++) { INFO3("Task '%s' start time: %f, finish time: %f", SD_task_get_name(changed_tasks[i]), @@ -164,6 +159,11 @@ int main(int argc, char **argv) { SD_task_get_finish_time(changed_tasks[i])); } + xbt_assert0(changed_tasks[0] == taskD && + changed_tasks[1] == taskB && + changed_tasks[2] == NULL, + "Unexpected simulation results"); + xbt_free(changed_tasks); DEBUG0("Destroying tasks..."); diff --git a/include/simdag/datatypes.h b/include/simdag/datatypes.h index 391f469f1b..6613f54b37 100644 --- a/include/simdag/datatypes.h +++ b/include/simdag/datatypes.h @@ -11,6 +11,21 @@ @see SD_workstation_management */ typedef struct SD_workstation *SD_workstation_t; +/** @brief Workstation access mode + @ingroup SD_datatypes_management + + By default, a workstation resource is shared, i.e. several tasks + can be executed at the same time on a workstation. The CPU power of + the workstation is shared between the running tasks on the workstation. + In sequential mode, only one task can use the workstation, and the other + tasks wait in a FIFO. + + @see SD_workstation_get_access_mode(), SD_workstation_set_access_mode() */ +typedef enum { + SD_WORKSTATION_SHARED_ACCESS, /**< @brief Several tasks can be executed at the same time */ + SD_WORKSTATION_SEQUENTIAL_ACCESS /**< @brief Only one task can be executed, the others wait in a FIFO. */ +} e_SD_workstation_access_mode_t; + /** @brief Link datatype @ingroup SD_datatypes_management @@ -41,10 +56,11 @@ typedef enum { SD_NOT_SCHEDULED = 0, /**< @brief Initial state (not valid for SD_watch and SD_unwatch). */ SD_SCHEDULED = 0x0001, /**< @brief A task becomes SD_SCHEDULED when you call function SD_task_schedule. SD_simulate will execute it when it becomes SD_READY. */ - SD_READY = 0x0002, /**< @brief A scheduled task becomes ready as soon as its dependencies are satisfied. */ - SD_RUNNING = 0x0004, /**< @brief When a task is ready, it is launched in the function SD_simulate and becomes SD_RUNNING. */ - SD_DONE = 0x0008, /**< @brief The task is successfuly finished. */ - SD_FAILED = 0x0010 /**< @brief A problem occured during the execution of the task. */ + SD_READY = 0x0002, /**< @brief A scheduled task becomes ready is SD_simulate as soon as its dependencies are satisfied. */ + SD_IN_FIFO = 0x0004, /**< @brief A ready task can have to wait in a workstation fifo if the workstation is sequential */ + SD_RUNNING = 0x0008, /**< @brief An SD_READY or SD_IN_FIFO becomes SD_RUNNING when it is launched. */ + SD_DONE = 0x0010, /**< @brief The task is successfuly finished. */ + SD_FAILED = 0x0020 /**< @brief A problem occured during the execution of the task. */ } e_SD_task_state_t; #endif diff --git a/include/simdag/simdag.h b/include/simdag/simdag.h index effb3eb5ed..d4d1414ea4 100644 --- a/include/simdag/simdag.h +++ b/include/simdag/simdag.h @@ -55,6 +55,9 @@ SD_link_t* SD_route_get_list(SD_workstation_t src, SD_workstation_t int SD_route_get_size(SD_workstation_t src, SD_workstation_t dst); double SD_workstation_get_power(SD_workstation_t workstation); double SD_workstation_get_available_power(SD_workstation_t workstation); +e_SD_workstation_access_mode_t SD_workstation_get_access_mode(SD_workstation_t workstation); +void SD_workstation_set_access_mode(SD_workstation_t workstation, + e_SD_workstation_access_mode_t access_mode); double SD_workstation_get_computation_time(SD_workstation_t workstation, double computation_amount); double SD_route_get_current_latency(SD_workstation_t src, SD_workstation_t dst); diff --git a/src/simdag/private.h b/src/simdag/private.h index de4e6535a3..35bcbc5848 100644 --- a/src/simdag/private.h +++ b/src/simdag/private.h @@ -3,6 +3,7 @@ #include "xbt/dict.h" #include "xbt/dynar.h" +#include "xbt/fifo.h" #include "simdag/simdag.h" #include "simdag/datatypes.h" #include "surf/surf.h" @@ -29,6 +30,7 @@ typedef struct SD_global { xbt_swag_t not_scheduled_task_set; xbt_swag_t scheduled_task_set; xbt_swag_t ready_task_set; + xbt_swag_t in_fifo_task_set; xbt_swag_t running_task_set; xbt_swag_t done_task_set; xbt_swag_t failed_task_set; @@ -47,6 +49,10 @@ typedef struct SD_link { typedef struct SD_workstation { void *surf_workstation; /* surf object */ void *data; /* user data */ + e_SD_workstation_access_mode_t access_mode; + + xbt_fifo_t task_fifo; /* only used in sequential mode */ + SD_task_t current_task; /* only used in sequential mode */ } s_SD_workstation_t; /* Task */ @@ -61,8 +67,11 @@ typedef struct SD_task { double finish_time; surf_action_t surf_action; unsigned short watch_points; + int state_changed; /* used only by SD_simulate, to make sure we put the task only once in the returning array */ + int fifo_checked; /* used by SD_task_just_done to make sure we evaluate + the task only once */ /* dependencies */ xbt_dynar_t tasks_before; @@ -70,7 +79,7 @@ typedef struct SD_task { /* scheduling parameters (only exist in state SD_SCHEDULED) */ int workstation_nb; - void **workstation_list; /* surf workstations */ + SD_workstation_t *workstation_list; /* surf workstations */ double *computation_amount; double *communication_amount; double rate; @@ -92,9 +101,12 @@ void __SD_link_destroy(void *link); SD_workstation_t __SD_workstation_create(void *surf_workstation, void *data); void __SD_workstation_destroy(void *workstation); +int __SD_workstation_is_busy(SD_workstation_t workstation); void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state); -surf_action_t __SD_task_run(SD_task_t task); +void __SD_task_really_run(SD_task_t task); +int __SD_task_try_to_run(SD_task_t task); +void __SD_task_just_done(SD_task_t task); /* Functions to test if the task is in a given state. These functions are faster than using SD_task_get_state() */ @@ -120,6 +132,17 @@ static _XBT_INLINE int __SD_task_is_ready(SD_task_t task) { return task->state_set == sd_global->ready_task_set; } +/* Returns whether the state of the given task is SD_IN_FIFO. */ +static _XBT_INLINE int __SD_task_is_in_fifo(SD_task_t task) { + return task->state_set == sd_global->in_fifo_task_set; +} + +/* Returns whether the state of the given task is SD_READY or SD_IN_FIFO. */ +static _XBT_INLINE int __SD_task_is_ready_or_in_fifo(SD_task_t task) { + return task->state_set == sd_global->ready_task_set || + task->state_set == sd_global->in_fifo_task_set; +} + /* Returns whether the state of the given task is SD_RUNNING. */ static _XBT_INLINE int __SD_task_is_running(SD_task_t task) { return task->state_set == sd_global->running_task_set; diff --git a/src/simdag/sd_global.c b/src/simdag/sd_global.c index c464c47e03..c6087f498d 100644 --- a/src/simdag/sd_global.c +++ b/src/simdag/sd_global.c @@ -37,6 +37,7 @@ void SD_init(int *argc, char **argv) { sd_global->not_scheduled_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup)); sd_global->scheduled_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup)); sd_global->ready_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup)); + sd_global->in_fifo_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup)); sd_global->running_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup)); sd_global->done_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup)); sd_global->failed_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup)); @@ -74,10 +75,12 @@ void SD_create_environment(const char *platform_file) { surf_timer_resource_init(platform_file); /* tell Surf to create the environnement */ + DEBUG0("Calling surf_workstation_resource_init"); surf_workstation_resource_init_KCCFLN05(platform_file); -/* surf_workstation_resource_init_CLM03(platform_file); */ + /* surf_workstation_resource_init_CLM03(platform_file); */ /* now let's create the SD wrappers for workstations and links */ + DEBUG0("Creating SimDags hosts and links"); xbt_dict_foreach(workstation_set, cursor, name, surf_workstation) { __SD_workstation_create(surf_workstation, NULL); } @@ -130,16 +133,14 @@ SD_task_t* SD_simulate(double how_long) /* explore the ready tasks */ xbt_swag_foreach(task, sd_global->ready_task_set) { INFO1("Executing task '%s'", SD_task_get_name(task)); - __SD_task_run(task); - surf_workstation_resource->common_public->action_set_data(task->surf_action, task); - task->state_changed = 1; - - changed_tasks[changed_task_number++] = task; /* replace NULL by the task */ - if (changed_task_number == changed_task_capacity) { - changed_task_capacity *= 2; - changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity); + if ((task->state_changed = __SD_task_try_to_run(task))) { + changed_tasks[changed_task_number++] = task; /* replace NULL by the task */ + if (changed_task_number == changed_task_capacity) { + changed_task_capacity *= 2; + changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity); + } + changed_tasks[changed_task_number] = NULL; } - changed_tasks[changed_task_number] = NULL; } /* main loop */ @@ -159,9 +160,9 @@ SD_task_t* SD_simulate(double how_long) while ((action = xbt_swag_extract(surf_workstation_resource->common_public->states.done_action_set))) { task = action->data; INFO1("Task '%s' done", SD_task_get_name(task)); - __SD_task_set_state(task, SD_DONE); - surf_workstation_resource->common_public->action_free(action); - task->surf_action = NULL; + DEBUG0("Calling __SD_task_just_done"); + __SD_task_just_done(task); + INFO1("__SD_task_just_done called on task '%s'", SD_task_get_name(task)); /* the state has changed */ if (!task->state_changed) { @@ -183,16 +184,14 @@ SD_task_t* SD_simulate(double how_long) /* is dst ready now? */ if (__SD_task_is_ready(dst) && !sd_global->watch_point_reached) { INFO1("Executing task '%s'", SD_task_get_name(dst)); - dst->surf_action = __SD_task_run(dst); - surf_workstation_resource->common_public->action_set_data(dst->surf_action, dst); - dst->state_changed = 1; - - changed_tasks[changed_task_number++] = dst; - if (changed_task_number == changed_task_capacity) { - changed_task_capacity *= 2; - changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity); + if (__SD_task_try_to_run(dst)) { + changed_tasks[changed_task_number++] = dst; + if (changed_task_number == changed_task_capacity) { + changed_task_capacity *= 2; + changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity); + } + changed_tasks[changed_task_number] = NULL; } - changed_tasks[changed_task_number] = NULL; } } } @@ -267,6 +266,7 @@ void SD_exit(void) { xbt_swag_free(sd_global->not_scheduled_task_set); xbt_swag_free(sd_global->scheduled_task_set); xbt_swag_free(sd_global->ready_task_set); + xbt_swag_free(sd_global->in_fifo_task_set); xbt_swag_free(sd_global->running_task_set); xbt_swag_free(sd_global->done_task_set); xbt_swag_free(sd_global->failed_task_set); diff --git a/src/simdag/sd_task.c b/src/simdag/sd_task.c index 237483a671..cfc066de76 100644 --- a/src/simdag/sd_task.c +++ b/src/simdag/sd_task.c @@ -104,6 +104,8 @@ e_SD_task_state_t SD_task_get_state(SD_task_t task) { return SD_RUNNING; if (task->state_set == sd_global->ready_task_set) return SD_READY; + if (task->state_set == sd_global->in_fifo_task_set) + return SD_IN_FIFO; if (task->state_set == sd_global->not_scheduled_task_set) return SD_NOT_SCHEDULED; return SD_FAILED; @@ -123,6 +125,9 @@ void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state) { case SD_READY: task->state_set = sd_global->ready_task_set; break; + case SD_IN_FIFO: + task->state_set = sd_global->in_fifo_task_set; + break; case SD_RUNNING: task->state_set = sd_global->running_task_set; task->start_time = surf_workstation_resource->common_public-> @@ -503,12 +508,8 @@ void SD_task_schedule(SD_task_t task, int workstation_nb, task->communication_amount = xbt_new0(double, communication_nb); memcpy(task->communication_amount, communication_amount, sizeof(double) * communication_nb); - /* we have to create a Surf workstation array instead of the SimDag workstation array */ - task->workstation_list = xbt_new0(void*, workstation_nb); - int i; - for (i = 0; i < workstation_nb; i++) { - task->workstation_list[i] = workstation_list[i]->surf_workstation; - } + task->workstation_list = xbt_new0(SD_workstation_t, workstation_nb); + memcpy(task->workstation_list, workstation_list, sizeof(SD_workstation_t) * workstation_nb); /* update the task state */ if (xbt_dynar_length(task->tasks_before) == 0) @@ -553,40 +554,235 @@ void SD_task_unschedule(SD_task_t task) { */ static void __SD_task_destroy_scheduling_data(SD_task_t task) { SD_CHECK_INIT_DONE(); - if (!__SD_task_is_scheduled_or_ready(task)) - THROW1(arg_error, 0, "Task '%s' must be SD_SCHEDULED or SD_READY", SD_task_get_name(task)); + if (!__SD_task_is_scheduled_or_ready(task) && !__SD_task_is_in_fifo(task)) + THROW1(arg_error, 0, "Task '%s' must be SD_SCHEDULED, SD_READY or SD_IN_FIFO", SD_task_get_name(task)); - xbt_free(task->workstation_list); xbt_free(task->computation_amount); xbt_free(task->communication_amount); } -/* Runs a task. This function is called by SD_simulate() when a scheduled task can start - * (ie when its dependencies are satisfied). +/* 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. */ -surf_action_t __SD_task_run(SD_task_t task) { +void __SD_task_really_run(SD_task_t task) { SD_CHECK_INIT_DONE(); xbt_assert0(task != NULL, "Invalid parameter"); - - if (!__SD_task_is_ready(task)) - THROW2(arg_error, 0, "Task '%s' is not ready! Task state: %d", + xbt_assert2(__SD_task_is_ready_or_in_fifo(task), "Task '%s' is not ready or in a fifo! Task state: %d", SD_task_get_name(task), SD_task_get_state(task)); + xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task)); + + int i; + void **surf_workstations; + + DEBUG1("Really running task '%s'", SD_task_get_name(task)); + + /* set this task as current task for the workstations in sequential mode */ + for (i = 0; i < task->workstation_nb; i++) { + if (SD_workstation_get_access_mode(task->workstation_list[i]) == SD_WORKSTATION_SEQUENTIAL_ACCESS) { + task->workstation_list[i]->current_task = task; + xbt_assert0(__SD_workstation_is_busy(task->workstation_list[i]), "The workstation should be busy now"); + } + } + + DEBUG1("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_workstations = xbt_new0(void*, task->workstation_nb); + + for (i = 0; i < task->workstation_nb; i++) { + surf_workstations[i] = task->workstation_list[i]->surf_workstation; + } + task->surf_action = surf_workstation_resource->extension_public-> execute_parallel_task(task->workstation_nb, - task->workstation_list, + surf_workstations, task->computation_amount, task->communication_amount, task->amount, task->rate); + surf_workstation_resource->common_public->action_set_data(task->surf_action, task); + task->state_changed = 1; DEBUG1("surf_action = %p", task->surf_action); + xbt_free(surf_workstations); __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */ __SD_task_set_state(task, SD_RUNNING); + xbt_assert2(__SD_task_is_running(task), "Bad state of task '%s': %d", + SD_task_get_name(task), SD_task_get_state(task)); - return task->surf_action; } + +/* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_READY + * (ie 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) { + SD_CHECK_INIT_DONE(); + xbt_assert0(task != NULL, "Invalid parameter"); + xbt_assert2(__SD_task_is_ready(task), "Task '%s' is not ready! Task state: %d", + SD_task_get_name(task), SD_task_get_state(task)); + + int can_start = 1; + int i; + SD_workstation_t workstation; + + for (i = 0; i < task->workstation_nb; i++) { + can_start = !__SD_workstation_is_busy(task->workstation_list[i]); + } + + DEBUG2("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 (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) { + DEBUG2("Pushing task '%s' in the fifo of workstation '%s'", SD_task_get_name(task), + SD_workstation_get_name(workstation)); + xbt_fifo_push(workstation->task_fifo, task); + } + } + __SD_task_set_state(task, SD_IN_FIFO); + xbt_assert2(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d", + SD_task_get_name(task), SD_task_get_state(task)); + DEBUG1("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) { + SD_CHECK_INIT_DONE(); + xbt_assert0(task != NULL, "Invalid parameter"); + xbt_assert1(__SD_task_is_running(task), "The task must be running! Task state: %d", SD_task_get_state(task)); + xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task)); + + int i, j; + SD_workstation_t workstation; + + SD_task_t candidate; + int candidate_nb = 0; + int candidate_capacity = 8; + SD_task_t *candidates = xbt_new0(SD_task_t, 8); + int can_start = 1; + + __SD_task_set_state(task, SD_DONE); + surf_workstation_resource->common_public->action_free(task->surf_action); + task->surf_action = NULL; + + DEBUG0("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]; + DEBUG2("Workstation '%s': access_mode = %d", SD_workstation_get_name(workstation), workstation->access_mode); + if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) { + xbt_assert1(workstation->task_fifo != NULL, "Workstation '%s' has sequential access but no fifo!", + SD_workstation_get_name(workstation)); + xbt_assert2(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 */ + workstation->current_task = NULL; + + DEBUG0("Getting candidate in fifo"); + candidate = xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo)); + + if (candidate != NULL) { + DEBUG1("Candidate: '%s'", SD_task_get_name(candidate)); + xbt_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d", + SD_task_get_name(candidate), SD_task_get_state(candidate)); + } + + DEBUG1("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; + } + } + } + + DEBUG1("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_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d", + SD_task_get_name(candidate), 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 = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS || + candidate == xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo)); + } + + DEBUG2("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]; + + /* update the fifo */ + if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) { + candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */ + DEBUG1("Head of the fifo: '%s'", (candidate != NULL) ? SD_task_get_name(candidate) : "NULL"); + xbt_assert0(candidate == candidates[i], "Error in __SD_task_just_done: bad first task in the fifo"); + } + } /* for each workstation */ + + /* finally execute the task */ + DEBUG2("Task '%s' state: %d", SD_task_get_name(candidate), SD_task_get_state(candidate)); + __SD_task_really_run(candidate); + + DEBUG4("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d", + SD_task_get_name(candidate), candidate->state_set, sd_global->running_task_set, __SD_task_is_running(candidate)); + xbt_assert2(__SD_task_is_running(candidate), "Bad state of task '%s': %d", + SD_task_get_name(candidate), SD_task_get_state(candidate)); + DEBUG0("Okay, the task is running."); + + } /* can start */ + candidate->fifo_checked = 1; + } /* for each candidate */ + + xbt_free(candidates); +} + /* Remove all dependencies associated with a task. This function is called when the task is destroyed. */ static void __SD_task_remove_dependencies(SD_task_t task) { @@ -668,6 +864,9 @@ void SD_task_destroy(SD_task_t task) { if (task->surf_action != NULL) surf_workstation_resource->common_public->action_free(task->surf_action); + if (task->workstation_list != NULL) + xbt_free(task->workstation_list); + xbt_dynar_free(&task->tasks_before); xbt_dynar_free(&task->tasks_after); xbt_free(task); diff --git a/src/simdag/sd_workstation.c b/src/simdag/sd_workstation.c index 84a2a0eac4..a66d29fc5f 100644 --- a/src/simdag/sd_workstation.c +++ b/src/simdag/sd_workstation.c @@ -13,6 +13,8 @@ SD_workstation_t __SD_workstation_create(void *surf_workstation, void *data) { SD_workstation_t workstation = xbt_new0(s_SD_workstation_t, 1); workstation->surf_workstation = surf_workstation; workstation->data = data; /* user data */ + SD_workstation_set_access_mode(workstation, SD_WORKSTATION_SHARED_ACCESS); /* default mode is shared */ + workstation->task_fifo = NULL; const char *name = SD_workstation_get_name(workstation); xbt_dict_set(sd_global->workstations, name, workstation, __SD_workstation_destroy); /* add the workstation to the dictionary */ @@ -45,7 +47,7 @@ SD_workstation_t SD_workstation_get_by_name(const char *name) { * \return an array of \ref SD_workstation_t containing all workstations * \see SD_workstation_get_number() */ -const SD_workstation_t* SD_workstation_get_list(void) { +const SD_workstation_t* SD_workstation_get_list(void) { SD_CHECK_INIT_DONE(); xbt_assert0(SD_workstation_get_number() > 0, "There is no workstation!"); @@ -296,11 +298,88 @@ double SD_route_get_communication_time(SD_workstation_t src, SD_workstation_t ds return latency + (communication_amount / min_bandwidth); } +/** + * \brief Returns the access mode of this workstation. + * + * \param workstation a workstation + * \return the access mode for the tasks running on this workstation: + * SD_WORKSTATION_SHARED_ACCESS or SD_WORKSTATION_SEQUENTIAL_ACCESS + * + * \see SD_workstation_set_access_mode(), e_SD_workstation_access_mode_t + */ + e_SD_workstation_access_mode_t SD_workstation_get_access_mode(SD_workstation_t workstation) { + SD_CHECK_INIT_DONE(); + xbt_assert0(workstation != NULL, "Invalid parameter"); + return workstation->access_mode; +} + +/** + * \brief Sets the access mode for the tasks that will be executed on a workstation + * + * By default, a workstation resource is shared, i.e. several tasks + * can be executed at the same time on a workstation. The CPU power of + * the workstation is shared between the running tasks on the workstation. + * In sequential mode, only one task can use the workstation, and the other + * tasks wait in a FIFO. + * + * \param workstation a workstation + * \param access_mode the access mode you want to set to this workstation: + * SD_WORKSTATION_SHARED_ACCESS or SD_WORKSTATION_SEQUENTIAL_ACCESS + * + * \see SD_workstation_get_access_mode(), e_SD_workstation_access_mode_t + */ +void SD_workstation_set_access_mode(SD_workstation_t workstation, e_SD_workstation_access_mode_t access_mode) { + SD_CHECK_INIT_DONE(); + xbt_assert0(workstation != NULL, "Invalid parameter"); + + if (access_mode == workstation->access_mode) { + return; // nothing is changed + } + + workstation->access_mode = access_mode; + + if (access_mode == SD_WORKSTATION_SHARED_ACCESS) { + xbt_fifo_free(workstation->task_fifo); + workstation->task_fifo = NULL; + } + else { + workstation->task_fifo = xbt_fifo_new(); + } +} + +/* Returns whether a task can start now on a workstation. + *//* +int __SD_workstation_can_start(SD_workstation_t workstation, SD_task_t task) { + SD_CHECK_INIT_DONE(); + xbt_assert0(workstation != NULL && task != NULL, "Invalid parameter"); + + return !__SD_workstation_is_busy(workstation) && + (xbt_fifo_size(workstation->task_fifo) == 0) || xbt_fifo_get_first_item(workstation->task_fifo) == task); +} +*/ + +/* Returns whether a workstation is busy. A workstation is busy is it is + * in sequential mode and a task is running on it or the fifo is not empty. + */ +int __SD_workstation_is_busy(SD_workstation_t workstation) { + SD_CHECK_INIT_DONE(); + xbt_assert0(workstation != NULL, "Invalid parameter"); + + return workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS && + (workstation->current_task != NULL || xbt_fifo_size(workstation->task_fifo) > 0); +} + /* Destroys a workstation. */ void __SD_workstation_destroy(void *workstation) { SD_CHECK_INIT_DONE(); xbt_assert0(workstation != NULL, "Invalid parameter"); /* workstation->surf_workstation is freed by surf_exit and workstation->data is freed by the user */ - xbt_free(workstation); + + SD_workstation_t w = (SD_workstation_t) workstation; + + if (w->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) { + xbt_fifo_free(w->task_fifo); + } + xbt_free(w); } -- 2.20.1