From 3d27a1e82ea26521deee4ab0bab6543ab4339da9 Mon Sep 17 00:00:00 2001 From: mquinson Date: Wed, 8 Dec 2010 20:14:22 +0000 Subject: [PATCH] New trace replayer, as fast as hell, and as boring as hell, too git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@9099 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- buildtools/Cmake/DefinePackages.cmake | 4 + buildtools/Cmake/MakeExeLib.cmake | 2 + include/simix/simix.h | 4 + src/replay/CMakeLists.txt | 20 +++ src/replay/README | 112 +++++++++++++++ src/replay/replay.c | 52 +++++++ src/replay/replay.h | 44 ++++++ src/replay/replay_MPI.c | 196 ++++++++++++++++++++++++++ src/replay/replay_trace_reader.c | 62 ++++++++ src/replay/state_machine_context.c | 91 ++++++++++++ src/simix/smx_smurf.c | 2 + src/simix/smx_user.c | 172 ++++++++++++++++++++++ 12 files changed, 761 insertions(+) create mode 100644 src/replay/CMakeLists.txt create mode 100644 src/replay/README create mode 100644 src/replay/replay.c create mode 100644 src/replay/replay.h create mode 100644 src/replay/replay_MPI.c create mode 100644 src/replay/replay_trace_reader.c create mode 100644 src/replay/state_machine_context.c diff --git a/buildtools/Cmake/DefinePackages.cmake b/buildtools/Cmake/DefinePackages.cmake index 38abac8dea..4f44d6263c 100644 --- a/buildtools/Cmake/DefinePackages.cmake +++ b/buildtools/Cmake/DefinePackages.cmake @@ -215,6 +215,10 @@ set(SIMIX_SRC src/simix/smx_context_base.c src/simix/smx_user.c src/simix/smx_smurf.c + src/replay/replay.h + src/replay/replay.c + src/replay/state_machine_context.c + src/replay/replay_trace_reader.c ) set(MSG_SRC diff --git a/buildtools/Cmake/MakeExeLib.cmake b/buildtools/Cmake/MakeExeLib.cmake index 1d920f6480..d22304df30 100644 --- a/buildtools/Cmake/MakeExeLib.cmake +++ b/buildtools/Cmake/MakeExeLib.cmake @@ -239,3 +239,5 @@ add_subdirectory(${CMAKE_HOME_DIRECTORY}/examples/simdag/scheduling) if(enable_smpi) add_subdirectory(${CMAKE_HOME_DIRECTORY}/examples/smpi) endif(enable_smpi) + +add_subdirectory(${CMAKE_HOME_DIRECTORY}/src/replay) diff --git a/include/simix/simix.h b/include/simix/simix.h index b0117297ec..f2f2994276 100644 --- a/include/simix/simix.h +++ b/include/simix/simix.h @@ -230,5 +230,9 @@ XBT_PUBLIC(void) SIMIX_req_sem_acquire_timeout(smx_sem_t sem, XBT_PUBLIC(unsigned int) SIMIX_req_sem_acquire_any(xbt_dynar_t sems); XBT_PUBLIC(int) SIMIX_req_sem_get_capacity(smx_sem_t sem); +/* functions to let the state machine context factory mess with simix flow */ +XBT_PUBLIC(void*) SIMIX_request_get_result(int id); +XBT_PUBLIC(int) SIMIX_request_last_id(void); + SG_END_DECL() #endif /* _SIMIX_SIMIX_H */ diff --git a/src/replay/CMakeLists.txt b/src/replay/CMakeLists.txt new file mode 100644 index 0000000000..880ef44b4a --- /dev/null +++ b/src/replay/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 2.6) + +set(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}") + +add_executable(replay replay_MPI.c) + +### Add definitions for compile +target_link_libraries(replay simgrid m ) + +### Get our action files in the archive +#set(EXTRA_DIST ${EXTRA_DIST} +# examples/msg/actions/actions_allReduce.txt +# examples/msg/actions/actions_barrier.txt +# examples/msg/actions/actions_bcast.txt +# examples/msg/actions/actions_reduce.txt +# examples/msg/actions/actions_split_p0.txt +# examples/msg/actions/actions_split_p1.txt +# examples/msg/actions/actions.txt +# examples/msg/actions/actions_with_isend.txt +# ) \ No newline at end of file diff --git a/src/replay/README b/src/replay/README new file mode 100644 index 0000000000..c57b4c67b7 --- /dev/null +++ b/src/replay/README @@ -0,0 +1,112 @@ +This directory constitutes an attempt to code a new trace replayer for +MPI actions, aiming at maximal performances. Modifying it is not for +faint of heart, since it could be compared to a mixure of the assembly +and basic programming philosophy (in worse) reserved to SimGrid experts. + +Shiny side: glance at interface +=============================== + +It uses a new simix context factory: state_machine. Each user process +is a state machine. There is no system mystery such as pthread or +ucontextes to save its stack. As a result, there is no stack. Each +user process only have a user-provided structure describing its state, +and only compute its next state based on that. Your main() can be as +simple as: + + #include "replay.h" + + int main() { + SG_replay_init(&argc,argv); + SG_replay_set_functions(init_fun, run_fun, fini_fun); + SG_replay("platform.xml","deployment.xml"); + return 0; + } + + * init_fun: user function in charge of creating the structure for + each process in the simulation. + * run_fun: user function called each time that a process must run. It + takes as first argument the structure describing the + current process. + * fini_fun: user function in charge of freeing the memory allocated to + the structure describing a process. + +This way of organizing the code saves a *huge amount* of memory +(regular contextes have 128kb stacks per user process, threads are +even more expensive) and greatly speeds things up (there is absolutely +no nothing to ask to the system, and everything can be done in user +space). + +A simple to use and efficient trace parser is also provided: + /* constructor/destructor */ + replay_trace_reader_t replay_trace_reader_new(const char*filename); + void replay_trace_reader_free(replay_trace_reader_t *reader); + /* get a new event. Don't free the content, strdup what you want to + keep after next call to reader_get() */ + const char * const*replay_trace_reader_get(replay_trace_reader_t r); + /* return a "file:pos" description of the last thing we read. */ + const char *replay_trace_reader_position(replay_trace_reader_t r); +Check replay_trace_reader.c for souce code, and replay_MPI.c for +example of use. + + + +Dark side: restrictions on user code +==================================== + +The incredible performance of this approach comes at a price: using +SimGrid this way is a *real* pain in the ass. You cannot use MSG nor +GRAS nor SMPI nor nothing (because none of these interfaces were coded +with the *extrem* requirement of the state_machine in mind), and you +can only rely on SIMIX. From SIMIX, you can only use requests (ie, the +SIMIX_req_* functions). Moreover, you must know that each blocking +request will result in an interruption of your execution flow. + +Let's take an example: If your code contains: + smx_action_t act = SIMIX_req_comm_isend(......); + SIMIX_req_comm_wait(act); + SIMIX_req_comm_destroy(act); + +The execution flow is interrupted brutally somewhere within +SIMIX_req_comm_isend(), the variable act will never be set (and any +code written after the first line is discarded). + +Indeed each SIMIX syscall results in an interruption of the calling +process, but in state_machine there is only one system stack and the +whole state describing the process is in the structure describing it. +So, when we need to remove one process from the system, to pause it, +we do it the hard way: the stack [of maestro] is restored to the state +in which maestro put it, whatever what the user process put on it. + +In short, each time simix wants to interrupt a process, state_machine +does a longjmp(2) to the point just before calling the user code. As a +result, each time you do a syscall, your stack is destroyed to restore +it in the state where maestro put it before calling your code. + +This means that you cannot do anything after a syscall, and that the +stack is not a safe storing area for your data. + +So, you have to write your code as a state machine, with a big ugly +switch. The previous code must be written something like: + +run_fun(globals, res) { + + switch (globals->state) { + case l1: /* default value st. we take that branch the first time */ + globals->state = l2; + SIMIX_req_comm_isend(....); /* syscall=>hard interrupt on our code*/ + case l2: /* we'll take that branch the second time we're scheduled */ + globals->comm = res; + globals->state = l3; + SIMIX_req_comm_wait(globals->comm); /* syscall=>interrupt */ + case l3: + globals->state = where_you_want_to_go_today; + SIMIX_req_comm_destroy(globals->comm); + } +} + +As you can see, the result of the /previous/ syscall is passed as second +argument to the run_fun(). + + +Isn't all this beautifully awful?? A few gotos in your code are just +what you need to go 20 years back to the good old time of gwbasic... \ No newline at end of file diff --git a/src/replay/replay.c b/src/replay/replay.c new file mode 100644 index 0000000000..494803cd35 --- /dev/null +++ b/src/replay/replay.c @@ -0,0 +1,52 @@ +/* Specific user API allowing to replay traces without context switches */ + +/* Copyright (c) 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. */ + +#include "simgrid_config.h" /* getline */ +#include "replay.h" +#include "simix/simix.h" + +XBT_LOG_NEW_DEFAULT_CATEGORY(replay,"trace replaying"); + +replay_init_func_t replay_func_init=NULL; +replay_run_func_t replay_func_run=NULL; +replay_fini_func_t replay_func_fini=NULL; + +static int replay_get_PID(void); +static int replay_get_PID(void) { + /* FIXME: implement it */ + return 0; +} + +static int replay_wrapper(int argc, char*argv[]) { + THROW_UNIMPLEMENTED; +} +/** \brief initialize the replay mechanism */ +void SG_replay_init(int *argc, char **argv) { + factory_initializer_to_use = statem_factory_init; + xbt_getpid = replay_get_PID; + SIMIX_global_init(argc, argv); + + /* Restore the default exception handlers: we have no real processes */ + __xbt_running_ctx_fetch = &__xbt_ex_ctx_default; + __xbt_ex_terminate = &__xbt_ex_terminate_default; + + SIMIX_function_register_default(replay_wrapper); +} +void SG_replay_set_functions(replay_init_func_t init, replay_run_func_t run,replay_fini_func_t fini) { + replay_func_init =init; + replay_func_run =run; + replay_func_fini =fini; +} + +/** \brief Loads a platform and deployment from the given file. Trace must be loaded from deployment */ +void SG_replay(const char *environment_file, const char *deploy_file) { + SIMIX_create_environment(environment_file); + SIMIX_launch_application(deploy_file); + + SIMIX_run(); +} diff --git a/src/replay/replay.h b/src/replay/replay.h new file mode 100644 index 0000000000..a145f97cb4 --- /dev/null +++ b/src/replay/replay.h @@ -0,0 +1,44 @@ +/* Specific user API allowing to replay traces without context switches */ + +/* Copyright (c) 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. */ + +#ifndef TRACE_REPLAY_H_ +#define TRACE_REPLAY_H_ + +#include "xbt/dynar.h" +#include "simix/simix.h" +#include "simix/context.h" + +/* function used in each process */ +int replay_runner(int argc, char *argv[]); +/* initialize my factory */ +void statem_factory_init(smx_context_factory_t * factory); + +void SG_replay_init(int *argc, char **argv); + +typedef void *(*replay_init_func_t)(int argc, char *argv[]); +typedef void (*replay_run_func_t)(void* data,void *syscall_result); +typedef void (*replay_fini_func_t)(void* data); + +replay_init_func_t replay_func_init; +replay_run_func_t replay_func_run; +replay_fini_func_t replay_func_fini; +void SG_replay_set_functions(replay_init_func_t init, replay_run_func_t run,replay_fini_func_t fini); + +void SG_replay(const char *environment_file, const char *deploy_file); + + +/* Trace parsing logic */ +typedef struct s_replay_trace_reader *replay_trace_reader_t; + +replay_trace_reader_t replay_trace_reader_new(const char*filename); +const char * const *replay_trace_reader_get(replay_trace_reader_t reader); +void replay_trace_reader_free(replay_trace_reader_t *reader); +const char *replay_trace_reader_position(replay_trace_reader_t reader); + + +#endif /* TRACE_REPLAY_H_ */ diff --git a/src/replay/replay_MPI.c b/src/replay/replay_MPI.c new file mode 100644 index 0000000000..3ba01a592d --- /dev/null +++ b/src/replay/replay_MPI.c @@ -0,0 +1,196 @@ +/* Example of traces replay without context switches, running MPI actions */ + +/* Copyright (c) 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. */ +#include +#include +#include +#include "replay.h" +#include "xbt/log.h" +#include "xbt/str.h" +#include "xbt/dynar.h" +#include "simix/smurf_private.h" + +XBT_LOG_NEW_DEFAULT_CATEGORY(mpi_replay,"MPI replayer"); + + +/* Helper function */ +static double parse_double(const char *string) { + double value; + char *endptr; + + value = strtod(string, &endptr); + if (*endptr != '\0') + THROW1(unknown_error, 0, "%s is not a double", string); + return value; +} +static int get_rank (const char *process_name){ + return atoi(&(process_name[1])); +} + +const char *state_name[] = { + "pump", + "compute0", "compute1", "compute2", + "send0","send1","send2","send3", + "irecv0", + "recv0", + "wait0", + "init0", "init1" +}; +typedef enum { + e_mpi_pump_evt_trace=0, + e_mpi_compute0,e_mpi_compute1,e_mpi_compute2, + e_mpi_send0,e_mpi_send1,e_mpi_send2,e_mpi_send3, + e_mpi_irecv0, + e_mpi_recv0, + e_mpi_wait0, + e_mpi_init0,e_mpi_init1 +} e_mpi_replay_state_t; + +typedef struct { + /* Myself */ + char *procname; + smx_host_t myhost; + e_mpi_replay_state_t state; + /* Parsing logic */ + replay_trace_reader_t reader; + const char * const*evt; + /* simix interface */ + smx_action_t act; + + xbt_dynar_t isends; /* of msg_comm_t, cleaned up automatically on send event */ +} s_mpi_replay_t, *mpi_replay_t; + +static void *mpi_replay_init(int argc, char *argv[]) { + + mpi_replay_t res = xbt_new0(s_mpi_replay_t,1); + res->procname = xbt_strdup(argv[0]); + res->state = e_mpi_pump_evt_trace; + + res->reader = replay_trace_reader_new(argv[1]); + return res; +} + +static void mpi_replay_run(void*data,void *syscall_res) { + mpi_replay_t g = (mpi_replay_t)data; /* my globals */ + + new_event: + INFO2("mpi_replay_run, state=%s (%d)",state_name[g->state],g->state); + + switch(g->state){ + + case e_mpi_pump_evt_trace: { /* nothing to do, parse next event and call function again */ + + g->evt = replay_trace_reader_get(g->reader); + if (strcmp(g->procname, g->evt[0])) { + WARN1("Ignore trace element not for me at %s", + replay_trace_reader_position(g->reader)); + goto new_event; + } + + if (!strcmp(g->evt[1],"send")) { + g->state = e_mpi_send0; + goto new_event; + } else if (!strcmp(g->evt[1],"recv")) { + g->state = e_mpi_recv0; + goto new_event; + } else if (!strcmp(g->evt[1],"irecv")||!strcmp(g->evt[1],"Irecv")) { + g->state = e_mpi_irecv0; + goto new_event; + } else if (!strcmp(g->evt[1],"wait")) { + g->state = e_mpi_wait0; + goto new_event; + } else if (!strcmp(g->evt[1],"compute")) { + g->state = e_mpi_compute0; + goto new_event; + } else if (!strcmp(g->evt[1],"init")) { + g->state = e_mpi_init0; + goto new_event; + } else { + WARN2("Ignoring unrecognized trace element at %s: %s", + replay_trace_reader_position(g->reader),g->evt[1]); + goto new_event; + } + } THROW_IMPOSSIBLE; + + /* *** Send *** */ + case e_mpi_send0: { + char to[250]; + sprintf(to, "%s_%s", g->procname, g->evt[2]); + + DEBUG2("Entering Send at %s (size: %lg)", + replay_trace_reader_position(g->reader), parse_double(g->evt[3])); + g->state = e_mpi_send1; + SIMIX_req_rdv_create(to); + } THROW_IMPOSSIBLE; + + case e_mpi_send1: + g->state = e_mpi_send2; + SIMIX_req_comm_isend(syscall_res, parse_double(g->evt[3]),-1, + NULL,0,//void *src_buff, size_t src_buff_size, + NULL,NULL);//int (*match_fun)(void *, void *), void *data) + THROW_IMPOSSIBLE; + case e_mpi_send2: + if (parse_double(g->evt[3])<65536) { + xbt_dynar_push(g->isends,&syscall_res); + g->state = e_mpi_pump_evt_trace; + goto new_event; + } + g->act = syscall_res; + g->state=e_mpi_send3; + SIMIX_req_comm_wait(g->act,-1); + case e_mpi_send3: + g->state=e_mpi_pump_evt_trace; + SIMIX_req_comm_destroy(g->act); + + /* *** Computation *** */ + case e_mpi_compute0: + g->state = e_mpi_compute1; + SIMIX_req_host_execute(replay_trace_reader_position(g->reader), + g->myhost,parse_double(g->evt[2])); + THROW_IMPOSSIBLE; + case e_mpi_compute1: + g->act = syscall_res; + g->state = e_mpi_compute2; + SIMIX_req_host_execution_wait(g->act); + THROW_IMPOSSIBLE; + case e_mpi_compute2: + g->state = e_mpi_pump_evt_trace; + SIMIX_req_host_execution_destroy(g->act); + THROW_IMPOSSIBLE; + + case e_mpi_irecv0: xbt_die("irecv0 unimplemented"); + case e_mpi_recv0: xbt_die("recv0 unimplemented"); + case e_mpi_wait0: xbt_die("wait0 unimplemented"); + case e_mpi_init0: + g->state = e_mpi_init1; + SIMIX_req_process_get_host(SIMIX_process_self()); + THROW_IMPOSSIBLE; + case e_mpi_init1: + g->myhost = syscall_res; + g->state = e_mpi_pump_evt_trace; + goto new_event; + + } + THROW_IMPOSSIBLE; +} +static void mpi_replay_fini(void *data) { + mpi_replay_t g = (mpi_replay_t)data; + replay_trace_reader_free(&g->reader); + free(data); +} + +int main(int argc, char *argv[]) { + SG_replay_init(&argc,argv); + if (argc<3) { + fprintf(stderr,"USAGE: replay platform_file deployment_file\n"); + exit(1); + } + SG_replay_set_functions(mpi_replay_init,mpi_replay_run,mpi_replay_fini); + SG_replay(argv[1],argv[2]); + + return 0; +} diff --git a/src/replay/replay_trace_reader.c b/src/replay/replay_trace_reader.c new file mode 100644 index 0000000000..b420ad0437 --- /dev/null +++ b/src/replay/replay_trace_reader.c @@ -0,0 +1,62 @@ +/* Copyright (c) 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. */ +#include +#include +#include +#include "replay.h" +#include "xbt/str.h" + +XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(replay); + +typedef struct s_replay_trace_reader { + FILE *fp; + char *line; + size_t line_len; + char *position; /* stable storage */ + char *filename; int linenum; +} s_replay_trace_reader_t; + +replay_trace_reader_t replay_trace_reader_new(const char*filename) { + replay_trace_reader_t res = xbt_new0(s_replay_trace_reader_t,1); + res->fp = fopen(filename, "r"); + xbt_assert2(res->fp != NULL, "Cannot open %s: %s", filename, + strerror(errno)); + res->filename = xbt_strdup(filename); + return res; +} + +const char *replay_trace_reader_position(replay_trace_reader_t reader) { + if (reader->position) + free(reader->position); + reader->position = bprintf("%s:%d",reader->filename,reader->linenum); + return (const char*)reader->position; +} +const char * const *replay_trace_reader_get(replay_trace_reader_t reader) { + ssize_t read; + read = getline(&reader->line, &reader->line_len, reader->fp); + //INFO1("got from trace: %s",reader->line); + reader->linenum++; + if (read==-1) + return NULL; /* end of file */ + char *comment = strchr(reader->line, '#'); + if (comment != NULL) + *comment = '\0'; + xbt_str_trim(reader->line, NULL); + if (reader->line[0] == '\0') + return replay_trace_reader_get(reader); /* Get next line */ + + return xbt_dynar_to_array(xbt_str_split_quoted_in_place(reader->line)); +} + +void replay_trace_reader_free(replay_trace_reader_t *reader) { + free((*reader)->filename); + if ((*reader)->position) + free((*reader)->position); + fclose((*reader)->fp); + free((*reader)->line); + free(*reader); + *reader=NULL; +} diff --git a/src/replay/state_machine_context.c b/src/replay/state_machine_context.c new file mode 100644 index 0000000000..dd2327ef73 --- /dev/null +++ b/src/replay/state_machine_context.c @@ -0,0 +1,91 @@ +/* Copyright (c) 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. */ + +#include +#include "replay.h" + +XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(replay); +typedef struct s_statem_context { + s_smx_ctx_base_t base; + void *user_data; + jmp_buf jump; + int syscall_id; /* Identifier of previous syscall to SIMIX */ +} s_statem_context_t,*statem_context_t; + +static smx_context_t +statem_create_context(xbt_main_func_t code, int argc, char **argv, + void_pfn_smxprocess_t cleanup_func, void *data); + +static void statem_ctx_free(smx_context_t context); +static void statem_ctx_suspend(smx_context_t context); +static void statem_ctx_resume(smx_context_t new_context); +static void statem_ctx_runall(xbt_swag_t processes); +static smx_context_t statem_ctx_self(void); + +void statem_factory_init(smx_context_factory_t * factory) { + /* instantiate the context factory */ + smx_ctx_base_factory_init(factory); + + (*factory)->create_context = statem_create_context; + (*factory)->free = statem_ctx_free; + (*factory)->suspend = statem_ctx_suspend; + (*factory)->runall = statem_ctx_runall; + (*factory)->name = "State Machine context factory"; +} + +static smx_context_t +statem_create_context(xbt_main_func_t code, int argc, char **argv, + void_pfn_smxprocess_t cleanup_func, void *data){ + if(argc>0 && !replay_func_init) { + fprintf(stderr,"variable replay_initer_function not set in replay_create_context. Severe issue!"); + } + + statem_context_t res = (statem_context_t) + smx_ctx_base_factory_create_context_sized(sizeof(s_statem_context_t), + code, argc, argv, + cleanup_func, + data); + + if (argc>0) /* not maestro */ + res->user_data = replay_func_init(argc,argv); + return (smx_context_t)res; +} + +static void statem_ctx_free(smx_context_t context) { + if (replay_func_fini) + replay_func_fini(((statem_context_t)context)->user_data); + else if (((statem_context_t)context)->user_data) + free(((statem_context_t)context)->user_data); + + smx_ctx_base_free(context); +} +/*static void replay_ctx_stop(smx_context_t context) { + THROW_UNIMPLEMENTED; +}*/ +static void statem_ctx_suspend(smx_context_t context) { + statem_context_t ctx = (statem_context_t)context; + ctx->syscall_id = SIMIX_request_last_id(); + longjmp(ctx->jump,1); +} +static void statem_ctx_resume(smx_context_t new_context) { + THROW_UNIMPLEMENTED; +} +static void statem_ctx_runall(xbt_swag_t processes) { + smx_context_t old_context; + smx_process_t process; + + INFO0("Run all"); + while ((process = xbt_swag_extract(processes))) { + statem_context_t ctx = (statem_context_t)SIMIX_process_get_context(process); + old_context = smx_current_context; + smx_current_context = SIMIX_process_get_context(process); + if (!setjmp(ctx->jump)) + replay_func_run(((statem_context_t)smx_current_context)->user_data, + ctx->syscall_id==0?NULL:SIMIX_request_get_result(ctx->syscall_id)); + smx_current_context = old_context; + } +} + diff --git a/src/simix/smx_smurf.c b/src/simix/smx_smurf.c index 65010aa411..59297c5903 100644 --- a/src/simix/smx_smurf.c +++ b/src/simix/smx_smurf.c @@ -37,6 +37,8 @@ void SIMIX_request_push() if (_surf_parallel_contexts) xbt_os_mutex_acquire(sync_req_positions); xbt_heap_push(req_todo,&issuer->request,issuer->pid); + DEBUG3("Pushed request %d of %s; now %d requests waiting", + issuer->request.call,issuer->name,xbt_heap_size(req_todo)); if (_surf_parallel_contexts) xbt_os_mutex_release(sync_req_positions); diff --git a/src/simix/smx_user.c b/src/simix/smx_user.c index 3d1f88064d..7c39d30260 100644 --- a/src/simix/smx_user.c +++ b/src/simix/smx_user.c @@ -1035,6 +1035,178 @@ int SIMIX_req_sem_get_capacity(smx_sem_t sem) SIMIX_request_push(); return req->sem_get_capacity.result; } +/* ************************************************************************** */ +/** @brief gets the result of previous syscall + * + * This function is only useful in state machine mechanism. + * + * In this case, the execution of every SIMIX_req_* function above was cut at + * SIMIX_request_push(), which calls yield() which calls suspend(), which longjmp + * to the point right before running the user code. When the control is passed + * back to the user, he needs to get the result of the syscall he did. + * That is why this function is made for. + * + * To extend this function, simply make sure that the end of the SIMIX_req_* + * function matches what is written in this big switch + */ +void *SIMIX_request_get_result(int kind) { + smx_req_t req = SIMIX_req_mine(); + switch ((e_smx_req_t) kind) { + case REQ_NO_REQ: + xbt_die("There is no request waiting, cannot provide the result"); + case REQ_HOST_GET_BY_NAME: + return req->host_get_by_name.result; + case REQ_HOST_GET_NAME: + return (void*)req->host_get_name.result; + case REQ_HOST_GET_PROPERTIES: + return req->host_get_properties.result; + case REQ_HOST_GET_SPEED: + return &req->host_get_speed.result; /* double */ + case REQ_HOST_GET_AVAILABLE_SPEED: + return &req->host_get_available_speed.result; /* double */ + case REQ_HOST_GET_STATE: + return &req->host_get_state.result; /* int */ + case REQ_HOST_GET_DATA: + return req->host_get_data.result; + case REQ_HOST_SET_DATA: + return NULL; /* void */ + case REQ_HOST_EXECUTE: + return req->host_execute.result; + case REQ_HOST_PARALLEL_EXECUTE: + return req->host_parallel_execute.result; + case REQ_HOST_EXECUTION_DESTROY: + return NULL; /* void */ + case REQ_HOST_EXECUTION_CANCEL: + return NULL; /* void */ + case REQ_HOST_EXECUTION_GET_REMAINS: + return &req->host_execution_get_remains.result; /* double */ + case REQ_HOST_EXECUTION_GET_STATE: + return &req->host_execution_get_state.result; /* e_smx_state_t */ + case REQ_HOST_EXECUTION_SET_PRIORITY: + return NULL; /* void */ + case REQ_HOST_EXECUTION_WAIT: + return NULL; /* void */ + case REQ_PROCESS_CREATE: + return req->process_create.result; + case REQ_PROCESS_KILL: + return NULL; /* void */ + case REQ_PROCESS_CHANGE_HOST: + return NULL; /* void */ + case REQ_PROCESS_SUSPEND: + return NULL; /* void */ + case REQ_PROCESS_RESUME: + return NULL; /* void */ + case REQ_PROCESS_COUNT: + return &req->process_count.result; /* int */ + case REQ_PROCESS_GET_DATA: + return req->process_get_data.result; + case REQ_PROCESS_SET_DATA: + return NULL; /* void */ + case REQ_PROCESS_GET_HOST: + return req->process_get_host.result; + case REQ_PROCESS_GET_NAME: + return (void*)req->process_get_name.result; + case REQ_PROCESS_IS_SUSPENDED: + return &req->process_is_suspended.result; /* int */ + case REQ_PROCESS_GET_PROPERTIES: + return req->process_get_properties.result; + case REQ_PROCESS_SLEEP: + return &req->process_sleep.result; /* e_smx_state_t */ + case REQ_RDV_CREATE: + return req->rdv_create.result; + case REQ_RDV_DESTROY: + return NULL; /* void */ + case REQ_RDV_GEY_BY_NAME: + return req->rdv_get_by_name.result; + case REQ_RDV_COMM_COUNT_BY_HOST: + return &req->rdv_comm_count_by_host.result; /* int */ + case REQ_RDV_GET_HEAD: + return req->rdv_get_head.result; + case REQ_COMM_ISEND: + return req->comm_isend.result; + case REQ_COMM_IRECV: + return req->comm_irecv.result; + case REQ_COMM_DESTROY: + case REQ_COMM_CANCEL: + return NULL; /* void */ + case REQ_COMM_WAITANY: + return &req->comm_waitany.result; + case REQ_COMM_TESTANY: + return &req->comm_testany.result; + case REQ_COMM_WAIT: + return NULL; /* void */ +#ifdef HAVE_TRACING + case REQ_SET_CATEGORY: + return NULL; /* void */ +#endif + case REQ_COMM_TEST: + return &req->comm_test.result; /* int */ + case REQ_COMM_GET_REMAINS: + return &req->comm_get_remains.result; /* double */ + case REQ_COMM_GET_STATE: + return &req->comm_get_state.result; /* e_smx_state_t */ + case REQ_COMM_GET_SRC_DATA: + return req->comm_get_src_data.result; + case REQ_COMM_GET_DST_DATA: + return req->comm_get_dst_data.result; + case REQ_COMM_GET_SRC_BUFF: + return req->comm_get_src_buff.result; + case REQ_COMM_GET_DST_BUFF: + return req->comm_get_dst_buff.result; + case REQ_COMM_GET_SRC_BUFF_SIZE: + return &req->comm_get_src_buff_size.result; /* size_t */ + case REQ_COMM_GET_DST_BUFF_SIZE: + return &req->comm_get_dst_buff_size.result; /* size_t */ + case REQ_COMM_GET_SRC_PROC: + return req->comm_get_src_proc.result; + case REQ_COMM_GET_DST_PROC: + return req->comm_get_dst_proc.result; + + #ifdef HAVE_LATENCY_BOUND_TRACKING + case REQ_COMM_IS_LATENCY_BOUNDED: + return &req->comm_is_latency_bounded.result; /* int */ + #endif + + case REQ_MUTEX_INIT: + return req->mutex_init.result; + case REQ_MUTEX_DESTROY: + case REQ_MUTEX_LOCK: + case REQ_MUTEX_UNLOCK: + return NULL; /* void */ + + case REQ_MUTEX_TRYLOCK: + return &req->mutex_trylock.result; /* int */ + + case REQ_COND_INIT: + return req->cond_init.result; + case REQ_COND_DESTROY: + case REQ_COND_SIGNAL: + case REQ_COND_WAIT: + case REQ_COND_WAIT_TIMEOUT: + case REQ_COND_BROADCAST: + return NULL; /* void */ + + case REQ_SEM_INIT: + return req->sem_init.result; + case REQ_SEM_DESTROY: + case REQ_SEM_RELEASE: + case REQ_SEM_ACQUIRE: + case REQ_SEM_ACQUIRE_TIMEOUT: + return NULL; /* void */ + + case REQ_SEM_WOULD_BLOCK: + return &req->sem_would_block.result; /* int */ + case REQ_SEM_GET_CAPACITY: + return &req->sem_get_capacity.result; /* int */ + } + THROW_IMPOSSIBLE; +} +/** @brief returns the id of the lastly done syscall + * Mainly (only?) useful for statemachine contextes + */ +int SIMIX_request_last_id() { + return SIMIX_req_mine()->call; +} -- 2.20.1