diff --git a/src/core/efw/CoroutineManager.hpp b/src/core/efw/CoroutineManager.hpp index 9a98b3c2..18d2ce6a 100644 --- a/src/core/efw/CoroutineManager.hpp +++ b/src/core/efw/CoroutineManager.hpp @@ -60,6 +60,10 @@ public: * calls to toggle(). */ void resume(); + /** + * Returns the number of added coroutines. + */ + unsigned size() { return m_Flows.size(); } /** * Retrieves the current (active) coroutine (= flow). * @return the current experiment flow. diff --git a/src/core/sal/SimulatorController.cc b/src/core/sal/SimulatorController.cc index d7830e28..c40462b9 100644 --- a/src/core/sal/SimulatorController.cc +++ b/src/core/sal/SimulatorController.cc @@ -38,7 +38,14 @@ BaseListener* SimulatorController::resume(void) void SimulatorController::startup(int& argc, char **& argv) { - if (argv) { + if (argv && argc > 0) { + // Collect invocation name and strip dirname + m_argv0 = std::string(argv[0]); + auto const pos = m_argv0.find_last_of('/'); + if (pos != std::string::npos) { + m_argv0 = m_argv0.substr(pos+1); + } + CommandLine::Inst().collect_args(argc, argv); } startup(); @@ -47,14 +54,60 @@ void SimulatorController::startup(int& argc, char **& argv) void SimulatorController::startup() { // Some greetings to the user: - std::cout << "[SimulatorController] Initializing..." << std::endl; - // TODO: Log-Level? + m_log << "Initializing..." << std::endl; // Set FAIL* as initialized m_isInitialized = true; // Activate previously added experiments to allow initialization: initExperiments(); + + if (m_Experiments.size() == 0) { + // Experiment was initialized indirecty, therefore there + // should be at least one experiment flow. + assert(m_flows.size() > 0 && "No experiment was added (directly or indirectly)"); + } else { + std::string experiment_name; + + if (m_Experiments.size() == 1) { + // exactly one experiment. choose it + experiment_name = m_Experiments.begin()->first; + } else { + m_log << "Multiple experiments are available: " << std::endl;; + for (auto experiment : m_Experiments) { + m_log << " - " << experiment.first << std::endl; + } + + // Check against environment variable + const char *env_name = getenv("FAIL_EXPERIMENT"); + if (env_name) { + for (auto experiment : m_Experiments) { + if (experiment.first == env_name) { + experiment_name = experiment.first; + break; + } + } + } + + // Check against invocation name (higher priority than environment) + if (m_argv0 != "") { + for (auto experiment : m_Experiments) { + if (strstr(m_argv0.c_str(), experiment.first.c_str())) { + experiment_name = experiment.first; + break; + } + } + } + } + + if (experiment_name == "") { + m_log << "ERROR, no experiment selected. Use FAIL_EXPERIMENT or change argv[0]" << std::endl; + exit(1); + } + + m_log << "Starting experiment: " << experiment_name << std::endl; + addFlow(m_Experiments[experiment_name]); + } } void SimulatorController::initExperiments() @@ -193,6 +246,11 @@ ConcreteCPU& SimulatorController::getCPU(size_t i) const return *m_CPUs[i]; } +void SimulatorController::addExperiment(const std::string &name, ExperimentFlow* flow) +{ + m_Experiments[name] = flow; +} + void SimulatorController::addFlow(ExperimentFlow* flow) { // Store the (flow,corohandle)-tuple internally and create its coroutine: diff --git a/src/core/sal/SimulatorController.hpp b/src/core/sal/SimulatorController.hpp index 3ea269f7..7abb5ad7 100644 --- a/src/core/sal/SimulatorController.hpp +++ b/src/core/sal/SimulatorController.hpp @@ -10,6 +10,8 @@ #include "ListenerManager.hpp" #include "SALConfig.hpp" #include "ConcreteCPU.hpp" +#include "util/Logger.hpp" + /// All classes, functions, constants, etc. are encapsulated in the namespace "fail". @@ -34,15 +36,26 @@ class MemoryManager; */ class SimulatorController { protected: + fail::Logger m_log; bool m_isInitialized; ListenerManager m_LstList; //!< storage where listeners are being buffered + std::map m_Experiments; //!< registered experiments, one is chosen on startup CoroutineManager m_Flows; //!< managed experiment flows MemoryManager *m_Mem; //!< access to memory pool std::vector m_CPUs; //!< list of CPUs in the target system friend class ListenerManager; //!< "outsources" the listener management + std::string m_argv0; //!< Invocation name of simulator process public: - SimulatorController() : m_isInitialized(false), m_Mem(NULL) { } - SimulatorController(MemoryManager* mem) : m_isInitialized(false), m_Mem(mem) { } + SimulatorController() + : m_log("SimulatorController", false), + m_isInitialized(false), + m_Mem(nullptr) + { /* blank */ } + SimulatorController(MemoryManager* mem) + : m_log("SimulatorController", false), + m_isInitialized(false), + m_Mem(mem) + { /* blank */ } virtual ~SimulatorController() { } /** * @brief Initialization function each implementation needs to call on @@ -171,6 +184,14 @@ public: /* ******************************************************************** * Experiment-Flow & Listener Management API: * ********************************************************************/ + /** + * Register the specified experiment with FAIL* under a given + * name. On startup, FAIL* will select one experiment and + * instantiate a coroutine with addFlow(). + * @param name the experiment name + * @param flow the experiment flow object to be added + */ + void addExperiment(const std::string &name, ExperimentFlow* flow); /** * Adds the specified experiment or plugin and creates a coroutine to run it in. * @param flow the experiment flow object to be added diff --git a/src/experiments/CMakeLists.txt b/src/experiments/CMakeLists.txt index 931c52d9..f6a71aeb 100644 --- a/src/experiments/CMakeLists.txt +++ b/src/experiments/CMakeLists.txt @@ -2,5 +2,10 @@ set(EXPERIMENTS_ACTIVATED "" CACHE STRING "Activated experiments (a semicolon-separated list of fail/src/experiments/ subdirectories)") foreach(experiment_name ${EXPERIMENTS_ACTIVATED}) - add_subdirectory(${experiment_name}) + add_subdirectory(${experiment_name}) + # Create symlink + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink + ${EXECUTABLE_OUTPUT_PATH}/fail-client + ${EXECUTABLE_OUTPUT_PATH}/fail-${experiment_name} + ) endforeach(experiment_name) diff --git a/src/experiments/instantiate-experiment.ah.in b/src/experiments/instantiate-experiment.ah.in index d6cb24b1..5a254c6e 100644 --- a/src/experiments/instantiate-experiment.ah.in +++ b/src/experiments/instantiate-experiment.ah.in @@ -12,7 +12,7 @@ aspect @EXPERIMENT_TYPE@ExperimentHook { advice execution ("void fail::SimulatorController::initExperiments()") : after () { - fail::simulator.addFlow(new @EXPERIMENT_TYPE@); + fail::simulator.addExperiment("@EXPERIMENT_NAME@", new @EXPERIMENT_TYPE@); } };