diff --git a/cmake/FindMySQL.cmake b/cmake/FindMySQL.cmake new file mode 100644 index 00000000..a8edcd3a --- /dev/null +++ b/cmake/FindMySQL.cmake @@ -0,0 +1,59 @@ +# Find the MySQL includes and client library +# This module defines +# MYSQL_INCLUDE_DIR, where to find mysql.h +# MYSQL_LIBRARIES, the libraries needed to use MySQL. +# MYSQL_FOUND, If false, do not try to use MySQL. + +set(MYSQL_CONFIG_PREFER_PATH "$ENV{MYSQL_HOME}/bin" CACHE FILEPATH + "preferred path to MySQL (mysql_config)") +find_program(MYSQL_CONFIG mysql_config + ${MYSQL_CONFIG_PREFER_PATH} + /usr/local/mysql/bin/ + /usr/local/bin/ + /usr/bin/ + ) + +if(MYSQL_CONFIG) + message(STATUS "Using mysql_config: ${MYSQL_CONFIG}") + # set INCLUDE_DIR + exec_program(${MYSQL_CONFIG} + ARGS --include + OUTPUT_VARIABLE MYSQL_INCLUDE_DIR) + + # set LIBRARY_DIR + exec_program(${MYSQL_CONFIG} + ARGS --libs_r + OUTPUT_VARIABLE MYSQL_LIBRARIES) + +else(MYSQL_CONFIG) + # FIXME incomplete + find_path(MYSQL_INCLUDE_DIR mysql.h + /usr/local/include + /usr/local/include/mysql + /usr/local/mysql/include + /usr/local/mysql/include/mysql + /usr/include + /usr/include/mysql + #find_library(mysqlclient ... + # PATHS + # ${MYSQL_ADD_LIBRARY_PATH} + # /usr/lib/mysql + # /usr/local/lib + # /usr/local/lib/mysql + # /usr/local/mysql/lib + #) +) +endif(MYSQL_CONFIG) + +set(MYSQL_INCLUDE_DIR ${MYSQL_INCLUDE_DIR} CACHE FILEPATH INTERNAL) +set(MYSQL_LIBRARIES ${MYSQL_LIBRARIES} CACHE FILEPATH INTERNAL) + +if(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) + set(MYSQL_FOUND TRUE CACHE INTERNAL "MySQL found") + message(STATUS "Found MySQL: ${MYSQL_INCLUDE_DIR}, ${MYSQL_LIBRARIES}") +else(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) + set(MYSQL_FOUND FALSE CACHE INTERNAL "MySQL found") + message(STATUS "MySQL not found.") +endif(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) + +mark_as_advanced(MYSQL_INCLUDE_DIR MYSQL_LIBRARIES) diff --git a/src/core/efw/CoroutineManager.cc b/src/core/efw/CoroutineManager.cc index 4dd35e4c..1b8be303 100644 --- a/src/core/efw/CoroutineManager.cc +++ b/src/core/efw/CoroutineManager.cc @@ -8,9 +8,9 @@ namespace fail { void CoroutineManager::m_invoke(void* pData) { - //std::cerr << "CORO m_invoke " << co_current() << std::endl; - // TODO: Log-Level? - reinterpret_cast(pData)->coroutine_entry(); + ExperimentFlow *flow = reinterpret_cast(pData); + flow->coroutine_entry(); + simulator.removeFlow(flow); //m_togglerstack.pop(); // FIXME: need to pop our caller co_exit(); // deletes the associated coroutine memory as well @@ -20,7 +20,12 @@ void CoroutineManager::m_invoke(void* pData) while (1); // freeze. } -CoroutineManager::~CoroutineManager() { } +CoroutineManager::~CoroutineManager() +{ + // Note that we do not destroy the associated coroutines; this causes + // problems when shutting down. + m_Flows.clear(); +} void CoroutineManager::toggle(ExperimentFlow* flow) { @@ -53,7 +58,9 @@ void CoroutineManager::remove(ExperimentFlow* flow) // find coroutine handle for this flow flowmap_t::iterator it = m_Flows.find(flow); if (it == m_Flows.end()) { - assert(false && "FATAL ERROR: Cannot remove flow"); + // Not finding the flow to remove is not an error; especially when + // shutting down this is the common case, as ~CoroutineManager probably + // clears the flow list before the ExperimentFlow destructors run. return; } corohandle_t coro = it->second; @@ -67,7 +74,9 @@ void CoroutineManager::remove(ExperimentFlow* flow) // delete coroutine (and handle the special case we're removing // ourselves) if (coro == co_current()) { - co_exit(); + if (!m_Terminated) { + co_exit(); + } } else { co_delete(coro); } diff --git a/src/core/efw/CoroutineManager.hpp b/src/core/efw/CoroutineManager.hpp index 13d9ce58..ec550f8e 100644 --- a/src/core/efw/CoroutineManager.hpp +++ b/src/core/efw/CoroutineManager.hpp @@ -29,10 +29,12 @@ private: std::stack m_togglerstack; //! manages the run-calls for each ExperimentFlow-object static void m_invoke(void* pData); + //! \c true if terminated explicitly using simulator.terminate() + bool m_Terminated; public: static const ExperimentFlow* SIM_FLOW; //!< the simulator coroutine flow - CoroutineManager() : m_simCoro(co_current()) { } + CoroutineManager() : m_simCoro(co_current()), m_Terminated(false) { } ~CoroutineManager(); /** * Creates a new coroutine for the specified experiment flow. @@ -63,6 +65,12 @@ public: * @return the current experiment flow. */ ExperimentFlow* getCurrent(); + /** + * Sets the termination flag. This should be called when Fail + * exists due to a call to \c ::exit() (used, e.g., in + * \c SimulatorController::terminate()). This cannot be undone. + */ + void setTerminated() { m_Terminated = true; } }; } // end-of-namespace: fail diff --git a/src/core/efw/ExperimentFlow.hpp b/src/core/efw/ExperimentFlow.hpp index 6279491f..0166a2fe 100644 --- a/src/core/efw/ExperimentFlow.hpp +++ b/src/core/efw/ExperimentFlow.hpp @@ -13,6 +13,11 @@ namespace fail { class ExperimentFlow { public: ExperimentFlow() { } + virtual ~ExperimentFlow() + { + simulator.clearListeners(this); // remove residual events + simulator.removeFlow(this); + } /** * Defines the experiment flow. * @return \c true if the experiment was successful, \c false otherwise diff --git a/src/core/sal/SimulatorController.cc b/src/core/sal/SimulatorController.cc index 26ea73dd..be5d9864 100644 --- a/src/core/sal/SimulatorController.cc +++ b/src/core/sal/SimulatorController.cc @@ -217,6 +217,8 @@ void SimulatorController::terminate(int exCode) // Attention: This could cause problems, e.g., because of non-closed sockets std::cout << "[FAIL] Exit called by experiment with exit code: " << exCode << std::endl; // TODO: (Non-)Verbose-Mode? Log-Level? + + m_Flows.setTerminated(); // we are about to terminate exit(exCode); } diff --git a/src/core/util/CMakeLists.txt b/src/core/util/CMakeLists.txt index de9ed96d..77775dc0 100644 --- a/src/core/util/CMakeLists.txt +++ b/src/core/util/CMakeLists.txt @@ -48,6 +48,10 @@ if(${LIB_IBERTY} STREQUAL LIB_IBERTY-NOTFOUND) message(FATAL_ERROR "libiberty not found. Try installing binutils-dev: [ sudo aptitude install binutils-dev ]") endif() +# libz required by gzstream +find_package(ZLIB REQUIRED) +include_directories(${ZLIB_INCLUDE_DIRS}) + # objdump required by Diassembler.cc set(THE_OBJDUMP "${ARCH_TOOL_PREFIX}objdump") @@ -61,7 +65,7 @@ mark_as_advanced(FAIL_OBJDUMP) add_library(fail-util ${SRCS}) add_dependencies(fail-util fail-comm) -target_link_libraries(fail-util ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${LIB_IBERTY} ) +target_link_libraries(fail-util ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${LIB_IBERTY} ${ZLIB_LIBRARIES}) option(BUILD_LLVM_DISASSEMBLER "Build the LLVM-based disassembler (LLVM 3.3 preferred, for 3.1 and 3.2 read doc/how-to-build.txt)" OFF) if (BUILD_LLVM_DISASSEMBLER) diff --git a/src/core/util/llvmdisassembler/LLVMDisassembler.cpp b/src/core/util/llvmdisassembler/LLVMDisassembler.cpp index f1154e44..590e3b11 100644 --- a/src/core/util/llvmdisassembler/LLVMDisassembler.cpp +++ b/src/core/util/llvmdisassembler/LLVMDisassembler.cpp @@ -1,4 +1,3 @@ -#ifndef __puma #include "LLVMDisassembler.hpp" using namespace fail; @@ -147,5 +146,3 @@ void LLVMDisassembler::disassemble() } void LLVMDisassembler::StringRefMemoryObject::anchor() {} - -#endif diff --git a/src/core/util/llvmdisassembler/LLVMDisassembler.hpp b/src/core/util/llvmdisassembler/LLVMDisassembler.hpp index 7a0a4fe9..75535053 100644 --- a/src/core/util/llvmdisassembler/LLVMDisassembler.hpp +++ b/src/core/util/llvmdisassembler/LLVMDisassembler.hpp @@ -1,8 +1,6 @@ #ifndef __LLVMDISASSEMBLER_HPP__ #define __LLVMDISASSEMBLER_HPP__ -#ifndef __puma - #include #include #include @@ -137,5 +135,4 @@ public: } -#endif // puma #endif // __LLVMDISASSEMBLER_HPP__ diff --git a/src/core/util/llvmdisassembler/LLVMtoFailBochs.cpp b/src/core/util/llvmdisassembler/LLVMtoFailBochs.cpp index f1b47325..22f8d38c 100644 --- a/src/core/util/llvmdisassembler/LLVMtoFailBochs.cpp +++ b/src/core/util/llvmdisassembler/LLVMtoFailBochs.cpp @@ -4,7 +4,6 @@ using namespace fail; LLVMtoFailBochs::LLVMtoFailBochs() { -#ifndef __puma /* These magic numbers are taken from the llvm compiler (MC), they do not appear in any header. They hopefully will never change */ @@ -19,12 +18,12 @@ LLVMtoFailBochs::LLVMtoFailBochs() { llvm_to_fail_map[45] = reginfo_t(RID_CBX, 32, 0); // EBX llvm_to_fail_map[9] = reginfo_t(RID_CCX, 8, 8); // CH - llvm_to_fail_map[10] = reginfo_t(RID_CCX, 0xff); // CL + llvm_to_fail_map[10] = reginfo_t(RID_CCX, 8, 0); // CL llvm_to_fail_map[28] = reginfo_t(RID_CCX, 16, 0); // CX llvm_to_fail_map[46] = reginfo_t(RID_CCX); // ECX llvm_to_fail_map[29] = reginfo_t(RID_CDX, 8, 8); // DH - llvm_to_fail_map[32] = reginfo_t(RID_CDX, 0xff); // DL + llvm_to_fail_map[32] = reginfo_t(RID_CDX, 8, 0); // DL llvm_to_fail_map[42] = reginfo_t(RID_CDX, 16, 0); // DX llvm_to_fail_map[48] = reginfo_t(RID_CDX); // EDX @@ -46,5 +45,4 @@ LLVMtoFailBochs::LLVMtoFailBochs() { llvm_to_fail_map[54] = reginfo_t(RID_CSP); // ESP llvm_to_fail_map[117] = reginfo_t(RID_CSP, 16, 0); // SP llvm_to_fail_map[118] = reginfo_t(RID_CSP, 8, 0); // SPL -#endif } diff --git a/src/core/util/llvmdisassembler/LLVMtoFailGem5.cpp b/src/core/util/llvmdisassembler/LLVMtoFailGem5.cpp index bac70b29..e89a6419 100644 --- a/src/core/util/llvmdisassembler/LLVMtoFailGem5.cpp +++ b/src/core/util/llvmdisassembler/LLVMtoFailGem5.cpp @@ -4,7 +4,6 @@ using namespace fail; LLVMtoFailGem5::LLVMtoFailGem5() { -#ifndef __puma /* These magic numbers are taken from the machine descriptions of LLVM they (hopefully) will not change, since they are not exported via a header */ @@ -24,5 +23,4 @@ LLVMtoFailGem5::LLVMtoFailGem5() { llvm_to_fail_map[105] = reginfo_t(RI_SP); llvm_to_fail_map[40] = reginfo_t(RI_LR); llvm_to_fail_map[43] = reginfo_t(RI_IP); -#endif } diff --git a/src/core/util/llvmdisassembler/LLVMtoFailTranslator.cpp b/src/core/util/llvmdisassembler/LLVMtoFailTranslator.cpp index 0d10e1a2..ea8d6a43 100644 --- a/src/core/util/llvmdisassembler/LLVMtoFailTranslator.cpp +++ b/src/core/util/llvmdisassembler/LLVMtoFailTranslator.cpp @@ -4,16 +4,14 @@ using namespace fail; const LLVMtoFailTranslator::reginfo_t & LLVMtoFailTranslator::getFailRegisterID(unsigned int regid) { -#ifndef __puma ltof_map_t::iterator it = llvm_to_fail_map.find(regid); if( it != llvm_to_fail_map.end() ) {// found return (*it).second; } else { // not found - std::cout << "Fail ID for LLVM Register id " << regid << " not found :(" << std::endl; + std::cout << "Fail ID for LLVM Register id " << std::dec << regid << " not found :(" << std::endl; //exit(EXIT_FAILURE); return notfound; } -#endif } regdata_t LLVMtoFailTranslator::getRegisterContent(ConcreteCPU& cpu, const reginfo_t ®info){ diff --git a/src/core/util/llvmdisassembler/LLVMtoFailTranslator.hpp b/src/core/util/llvmdisassembler/LLVMtoFailTranslator.hpp index 4e9444c2..54be9e84 100644 --- a/src/core/util/llvmdisassembler/LLVMtoFailTranslator.hpp +++ b/src/core/util/llvmdisassembler/LLVMtoFailTranslator.hpp @@ -13,6 +13,12 @@ namespace fail { */ class LLVMtoFailTranslator { public: + /** + * Maps registers to/from linear addresses usable for def/use-pruning + * purposes and storage in the database. Takes care that the linear + * addresses of x86 subregisters (e.g., AX represents the lower 16 bits of + * EAX) overlap with their siblings. + */ struct reginfo_t { int id; regwidth_t width; @@ -20,18 +26,17 @@ public: byte_t offset; int toDataAddress() const { - // .. 5 4 | 7 6 5 4 | 3 2 1 0 - // | | - return (id << 8) | ((width/8) << 4) | (offset / 8); + // .. 5 4 | 3 2 1 0 + // | + return (id << 4) | (offset / 8); } + // does not recreate width or mask static reginfo_t fromDataAddress(int addr) { - int id = addr >> 8; - regwidth_t width = ((addr >> 4) & 0xf) * 8; - byte_t offset = (addr & 0xf) * 8; - return reginfo_t(id, width, offset); + int id = addr >> 4; + byte_t offset = (addr & 0xf) * 8; + return reginfo_t(id, 0, offset); } - reginfo_t(int id=-1, regwidth_t width = 32, byte_t offs = 0) : id(id), width(width), mask((regwidth_t)((((long long)1 << width) - 1) << offs)), offset(offs) {}; }; @@ -39,13 +44,16 @@ protected: LLVMtoFailTranslator(){}; -#ifndef __puma typedef std::map ltof_map_t; ltof_map_t llvm_to_fail_map; -#endif - public: + /** + * Translates a backend-specific register ID to a Fail register ID. + * @param regid A backend-specific register ID. + * @return A Fail* register ID, or LLVMtoFailTranslator::notfound if no + * mapping was found. + */ const reginfo_t & getFailRegisterID(unsigned int regid); regdata_t getRegisterContent(ConcreteCPU & cpu, const reginfo_t & reg); @@ -58,7 +66,7 @@ public: } int getFailRegisterId(unsigned int regid) { return this->getFailRegisterID(regid).id; }; -private: + reginfo_t notfound; }; diff --git a/src/experiments/dciao-kernelstructs/CMakeLists.txt b/src/experiments/dciao-kernelstructs/CMakeLists.txt index a1834697..a14aacf7 100644 --- a/src/experiments/dciao-kernelstructs/CMakeLists.txt +++ b/src/experiments/dciao-kernelstructs/CMakeLists.txt @@ -21,6 +21,9 @@ find_package(Protobuf REQUIRED) include_directories(${PROTOBUF_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) +find_package(MySQL REQUIRED) +include_directories(${MYSQL_INCLUDE_DIR}) + PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS}) ## Build library @@ -30,6 +33,6 @@ target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY}) ## This is the example's campaign server distributing experiment parameters add_executable(${EXPERIMENT_NAME}-server main.cc) -target_link_libraries(${EXPERIMENT_NAME}-server -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} -lmysqlclient -Wl,--end-group) +target_link_libraries(${EXPERIMENT_NAME}-server -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${MYSQL_LIBRARIES} -Wl,--end-group) install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin) diff --git a/src/experiments/ecos_kernel_test/CMakeLists.txt b/src/experiments/ecos_kernel_test/CMakeLists.txt index 883e2039..7546f9c6 100644 --- a/src/experiments/ecos_kernel_test/CMakeLists.txt +++ b/src/experiments/ecos_kernel_test/CMakeLists.txt @@ -22,14 +22,17 @@ find_package(Protobuf REQUIRED) include_directories(${PROTOBUF_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) +find_package(MySQL REQUIRED) +include_directories(${MYSQL_INCLUDE_DIR}) + PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS}) ## Build library add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS}) add_dependencies(fail-${EXPERIMENT_NAME} fail-tracing fail-comm) -target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} -lmysqlclient_r) +target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} ${MYSQL_LIBRARIES}) ## This is the example's campaign server distributing experiment parameters add_executable(${EXPERIMENT_NAME}-server main.cc) -target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} -lmysqlclient_r) +target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${MYSQL_LIBRARIES}) install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin) diff --git a/src/experiments/ecos_kernel_test/instantiateExperiment.cc b/src/experiments/ecos_kernel_test/instantiateExperiment.cc index 520be8a3..414a7172 100644 --- a/src/experiments/ecos_kernel_test/instantiateExperiment.cc +++ b/src/experiments/ecos_kernel_test/instantiateExperiment.cc @@ -1,8 +1,7 @@ #include "experiment.hpp" #include "sal/SALInst.hpp" -static EcosKernelTestExperiment experiment; void instantiateEcosKernelTestExperiment() { - fail::simulator.addFlow(&experiment); + fail::simulator.addFlow(new EcosKernelTestExperiment); } diff --git a/src/experiments/instantiate-experiment-indirect.ah.in b/src/experiments/instantiate-experiment-indirect.ah.in index d309617b..b3a72752 100644 --- a/src/experiments/instantiate-experiment-indirect.ah.in +++ b/src/experiments/instantiate-experiment-indirect.ah.in @@ -12,6 +12,10 @@ // You need to provide the implementation of this function in your experiment // directory: void instantiate@EXPERIMENT_TYPE@(); +// The experiment needs to be instantiated dynamically (on the stack, or the +// heap), as the ExperimentFlow destructor deregisters from the +// CoroutineManager which may not exist anymore if the global +// construction/destruction order is inappropriate. aspect @EXPERIMENT_TYPE@ExperimentHook { advice execution ("void fail::SimulatorController::initExperiments()") : after () { diff --git a/src/experiments/instantiate-experiment.ah.in b/src/experiments/instantiate-experiment.ah.in index 765d7214..5bf1ed32 100644 --- a/src/experiments/instantiate-experiment.ah.in +++ b/src/experiments/instantiate-experiment.ah.in @@ -9,10 +9,14 @@ #include "../experiments/@EXPERIMENT_NAME@/experiment.hpp" #include "sal/SALInst.hpp" +// The experiment needs to be instantiated dynamically (on the stack, or the +// heap), as the ExperimentFlow destructor deregisters from the +// CoroutineManager which may not exist anymore if the global +// construction/destruction order is inappropriate. + aspect @EXPERIMENT_TYPE@ExperimentHook { - @EXPERIMENT_TYPE@ experiment; advice execution ("void fail::SimulatorController::initExperiments()") : after () { - fail::simulator.addFlow(&experiment); + fail::simulator.addFlow(new @EXPERIMENT_TYPE@); } }; diff --git a/src/experiments/kesorefs/CMakeLists.txt b/src/experiments/kesorefs/CMakeLists.txt index d3dfb253..37298030 100644 --- a/src/experiments/kesorefs/CMakeLists.txt +++ b/src/experiments/kesorefs/CMakeLists.txt @@ -21,6 +21,9 @@ find_package(Protobuf REQUIRED) include_directories(${PROTOBUF_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) +find_package(MySQL REQUIRED) +include_directories(${MYSQL_INCLUDE_DIR}) + PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS}) ## Build library @@ -30,5 +33,5 @@ target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY}) ## This is the example's campaign server distributing experiment parameters add_executable(${EXPERIMENT_NAME}-server main.cc) -target_link_libraries(${EXPERIMENT_NAME}-server -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} -lmysqlclient -Wl,--end-group) +target_link_libraries(${EXPERIMENT_NAME}-server -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${MYSQL_LIBRARIES} -Wl,--end-group) install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin) diff --git a/src/experiments/nanojpeg/instantiateExperiment.cc b/src/experiments/nanojpeg/instantiateExperiment.cc index 98493577..84e8a80d 100644 --- a/src/experiments/nanojpeg/instantiateExperiment.cc +++ b/src/experiments/nanojpeg/instantiateExperiment.cc @@ -1,8 +1,7 @@ #include "experiment.hpp" #include "sal/SALInst.hpp" -static NanoJPEGExperiment experiment; void instantiateNanoJPEGExperiment() { - fail::simulator.addFlow(&experiment); + fail::simulator.addFlow(new NanoJPEGExperiment); } diff --git a/src/experiments/rampage/instantiateExperiment.cc b/src/experiments/rampage/instantiateExperiment.cc index ed51e4b8..b1efb310 100644 --- a/src/experiments/rampage/instantiateExperiment.cc +++ b/src/experiments/rampage/instantiateExperiment.cc @@ -1,8 +1,7 @@ #include "experiment.hpp" #include "sal/SALInst.hpp" -static RAMpageExperiment experiment; void instantiateRAMpageExperiment() { - fail::simulator.addFlow(&experiment); + fail::simulator.addFlow(new RAMpageExperiment); } diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index ac2e2096..f11196d8 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,6 +1,7 @@ option(BUILD_DUMP_TRACE "Build the trace dump tool?" OFF) option(BUILD_IMPORT_TRACE "Build the trace import tool?" OFF) option(BUILD_PRUNE_TRACE "Build the trace prune tool?" OFF) +option(BUILD_CONVERT_TRACE "Build the trace converter tool?" OFF) ### Setup search paths for headers ## @@ -18,3 +19,7 @@ endif(BUILD_PRUNE_TRACE) if(BUILD_DUMP_TRACE) add_subdirectory(dump-trace) endif(BUILD_DUMP_TRACE) + +if(BUILD_CONVERT_TRACE) + add_subdirectory(convert-trace) +endif(BUILD_CONVERT_TRACE) diff --git a/tools/convert-trace/CMakeLists.txt b/tools/convert-trace/CMakeLists.txt new file mode 100644 index 00000000..a226a7c3 --- /dev/null +++ b/tools/convert-trace/CMakeLists.txt @@ -0,0 +1,10 @@ +set(SRCS + main.cc + Gem5Converter.cc + DumpConverter.cc +) + +add_executable(convert-trace ${SRCS}) +target_link_libraries(convert-trace fail-util fail-comm) + +install(TARGETS convert-trace RUNTIME DESTINATION bin) diff --git a/tools/convert-trace/DumpConverter.cc b/tools/convert-trace/DumpConverter.cc new file mode 100644 index 00000000..75e59eb9 --- /dev/null +++ b/tools/convert-trace/DumpConverter.cc @@ -0,0 +1,73 @@ +#include +#include +#include "util/Logger.hpp" +#include "comm/TracePlugin.pb.h" +#include "DumpConverter.hpp" + +using namespace fail; +using std::stringstream; +using std::endl; +using std::hex; +using std::dec; + +static Logger LOG("DumpConverter", true); + +// TODO: convert extended trace information, too +bool DumpConverter::convert() +{ + char buf[2048], dummy[1024]; + int64_t prev_cycle = 0, cycle; + + while (m_input.getline(buf, sizeof(buf))) { + Trace_Event ev; + // IP 1035c9 t=0 + // MEM R 123abc width 4 IP 1035c9 t=1 + // MEM W 123abc width 4 IP 1035c9 t=1 + + std::stringstream ss(buf); + std::string ev_type; + ss >> ev_type; + + if (ev_type == "MEM") { + std::string accesstype; + uint64_t data_address; + uint32_t data_width; + ss >> accesstype >> hex >> data_address >> dummy >> dec >> data_width >> ev_type; + if (!ss) { + LOG << "input mismatch (1), input = " << buf << endl; + continue; + } + ev.set_memaddr(data_address); + ev.set_width(data_width); + ev.set_accesstype(accesstype == "R" ? ev.READ : ev.WRITE); + } + assert(ev_type == "IP"); + + uint64_t instr_address; + ss >> hex >> instr_address >> dummy; + if (!ss || dummy[0] != 't' || dummy[1] != '=') { + LOG << "input mismatch (2), input = " << buf << endl; + continue; + } + ev.set_ip(instr_address); + ss.clear(); + ss.str(dummy + 2); + ss >> dec >> cycle; + if (!ss) { + LOG << "input mismatch (3), input = " << buf << endl; + continue; + } + + if (cycle - prev_cycle > 0) { + ev.set_time_delta(cycle - prev_cycle); + prev_cycle = cycle; + } else if (cycle - prev_cycle < 0) { + LOG << "ignoring time discontinuity " << dec << prev_cycle << " -> " << cycle << endl; + prev_cycle = cycle; + } + + m_ps.writeMessage(&ev); + } + + return true; +} diff --git a/tools/convert-trace/DumpConverter.hpp b/tools/convert-trace/DumpConverter.hpp new file mode 100644 index 00000000..5648ea0d --- /dev/null +++ b/tools/convert-trace/DumpConverter.hpp @@ -0,0 +1,11 @@ +#ifndef __DUMPCONVERTER_HPP__ +#define __DUMPCONVERTER_HPP__ + +#include "FormatConverter.hpp" + +class DumpConverter : public FormatConverter { +public: + DumpConverter(std::istream& input, fail::ProtoOStream& ps) : FormatConverter(input, ps) {} + bool convert(); +}; +#endif diff --git a/tools/convert-trace/FormatConverter.hpp b/tools/convert-trace/FormatConverter.hpp new file mode 100644 index 00000000..58922e9d --- /dev/null +++ b/tools/convert-trace/FormatConverter.hpp @@ -0,0 +1,16 @@ +#ifndef __FORMATCONVERTER_HPP__ +#define __FORMATCONVERTER_HPP__ + +#include +#include "util/ProtoStream.hpp" + +class FormatConverter { +public: + FormatConverter(std::istream& input, fail::ProtoOStream& ps) : m_input(input), m_ps(ps) {} + virtual bool convert() = 0; + +protected: + std::istream& m_input; + fail::ProtoOStream& m_ps; +}; +#endif diff --git a/tools/convert-trace/Gem5Converter.cc b/tools/convert-trace/Gem5Converter.cc new file mode 100644 index 00000000..0a4e16f7 --- /dev/null +++ b/tools/convert-trace/Gem5Converter.cc @@ -0,0 +1,93 @@ +#include +#include +#include "util/Logger.hpp" +#include "comm/TracePlugin.pb.h" +#include "Gem5Converter.hpp" + +using namespace fail; +using std::stringstream; +using std::endl; +using std::hex; +using std::dec; + +static Logger LOG("Gem5Converter", true); + +bool Gem5Converter::convert() +{ + char buf[2048], dummy[2048]; + int64_t prev_cycle = 0, cycle; + uint64_t cur_ip = 0; + bool ifetch_seen = false; + + while (m_input.getline(buf, sizeof(buf))) { + Trace_Event ev; + // reset ifetch_seen in case we're getting multiple concatenated gem5 traces + if (strstr(buf, "http://gem5.org")) { + ifetch_seen = false; + continue; + } + if (!strstr(buf, "system.physmem") || strstr(buf, "access wrote")) { + continue; + } + // 5000: system.physmem: access wrote 4 bytes to address f7ee8 + // 5000: system.physmem: Write of size 4 on address 0xf7ee8 data 0x61190 + // 6000: system.physmem: IFetch of size 4 on address 0xd58 data 0xe59f000c + // 6000: system.physmem: Read of size 4 on address 0xd6c data 0x8e2c + // 161000: system.physmem: 00000000 4c 69 6e 75 78 00 00 00 00 00 00 00 00 00 00 00 Linux + + std::stringstream ss(buf); + std::string access_type; + unsigned access_width; + uint64_t access_address; + ss >> dec >> cycle >> dummy >> dummy >> access_type + >> dummy >> dummy >> dec >> access_width + >> dummy >> dummy >> hex >> access_address; + if (!ss) { + if (ifetch_seen && !access_type.c_str()[0] == '0') { + LOG << "input mismatch, input = " << buf << endl; + } + continue; + } + + if (cycle - prev_cycle > 0) { + ev.set_time_delta(cycle - prev_cycle); + prev_cycle = cycle; + } else if (cycle - prev_cycle < 0) { + LOG << "ignoring time discontinuity " << dec << prev_cycle << " -> " << cycle << endl; + prev_cycle = cycle; + } + + if (access_type == "IFetch") { + ifetch_seen = true; + cur_ip = access_address; + ev.set_ip(cur_ip); + //LOG << "ip = " << hex << cur_ip << endl; + + } else { + bool is_read; + if (access_type == "Read") { + is_read = true; + } else if (access_type == "Write") { + is_read = false; + } else if (access_type.c_str()[0] == '0') { + continue; + } else { + LOG << "input mismatch, input = " << buf << endl; + continue; + } + + if (!ifetch_seen) { + // skip all accesses before the first ifetch + continue; + } + ev.set_ip(cur_ip); + ev.set_memaddr(access_address); + ev.set_width(access_width); + ev.set_accesstype(is_read ? ev.READ : ev.WRITE); + //cout << "ip = " << hex << cur_ip << " mem " << access_address << " " << access_width << " " << (is_read ? 'R' : 'W') << endl; + } + m_ps.writeMessage(&ev); + } + + return true; +} diff --git a/tools/convert-trace/Gem5Converter.hpp b/tools/convert-trace/Gem5Converter.hpp new file mode 100644 index 00000000..9842a629 --- /dev/null +++ b/tools/convert-trace/Gem5Converter.hpp @@ -0,0 +1,11 @@ +#ifndef __GEM5CONVERTER_HPP__ +#define __GEM5CONVERTER_HPP__ + +#include "FormatConverter.hpp" + +class Gem5Converter : public FormatConverter { +public: + Gem5Converter(std::istream& input, fail::ProtoOStream& ps) : FormatConverter(input, ps) {} + bool convert(); +}; +#endif diff --git a/tools/convert-trace/main.cc b/tools/convert-trace/main.cc new file mode 100644 index 00000000..359d3806 --- /dev/null +++ b/tools/convert-trace/main.cc @@ -0,0 +1,65 @@ +#include +#include + +#include "FormatConverter.hpp" +#include "Gem5Converter.hpp" +#include "DumpConverter.hpp" + +#include "util/CommandLine.hpp" +#include "util/gzstream/gzstream.h" +#include "util/Logger.hpp" + +using namespace fail; +using std::cin; +using std::endl; + +static Logger LOG("convert-trace", true); + +int main(int argc, char *argv[]) { + CommandLine &cmd = CommandLine::Inst(); + cmd.addOption("", "", Arg::None, "usage: convert-trace -f dump|gem5 -t tracefile.tc"); + CommandLine::option_handle HELP = + cmd.addOption("h", "help", Arg::None, "-h/--help \tPrint usage and exit"); + CommandLine::option_handle FORMAT = + cmd.addOption("f", "format", Arg::Required, "-f/--format FORMAT \tInput format (dump|gem5)"); + CommandLine::option_handle OUTFILE = + cmd.addOption("t", "trace", Arg::Required, "-t/--trace FILE \tOutput file"); + for (int i = 1; i < argc; ++i) { + cmd.add_args(argv[i]); + } + if (!cmd.parse()) { + LOG << "Error parsing arguments." << endl; + return 1; + } + + if (cmd[HELP] || !cmd[OUTFILE] || !cmd[FORMAT] || cmd.parser()->nonOptionsCount() != 0) { + cmd.printUsage(); + if (cmd[HELP]) { + exit(0); + } else { + exit(1); + } + } + + std::string format = cmd[FORMAT].first()->arg; + std::string trace_file = cmd[OUTFILE].first()->arg; + + ogzstream gz_stream(trace_file.c_str()); + std::ostream *os = &gz_stream; + ProtoOStream ps(os); + + FormatConverter *converter; + if (format == "gem5") { + converter = new Gem5Converter(cin, ps); + } else if (format == "dump") { + converter = new DumpConverter(cin, ps); + } else { + LOG << "unknown input format '" << format << "'" << endl; + return 1; + } + + if (!converter->convert()) { + LOG << "converter failed" << endl; + return 1; + } +} diff --git a/tools/dump-trace/DumpTrace.cc b/tools/dump-trace/DumpTrace.cc index b99952af..d2799072 100644 --- a/tools/dump-trace/DumpTrace.cc +++ b/tools/dump-trace/DumpTrace.cc @@ -122,7 +122,7 @@ int main(int argc, char *argv[]) if (!stats_only) { cout << "MEM " << (ev.accesstype() == Trace_Event_AccessType_READ ? "R" : "W") << " " - << ev.memaddr() + << hex << ev.memaddr() << dec << " width " << ev.width() << hex << " IP " << ev.ip() << dec << " t=" << acctime diff --git a/tools/import-trace/CMakeLists.txt b/tools/import-trace/CMakeLists.txt index 80fce373..561a9c9c 100644 --- a/tools/import-trace/CMakeLists.txt +++ b/tools/import-trace/CMakeLists.txt @@ -17,13 +17,14 @@ if (BUILD_LLVM_DISASSEMBLER) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_CXX_FLAGS} -fexceptions") endif(BUILD_LLVM_DISASSEMBLER) - +find_package(MySQL REQUIRED) +include_directories(${MYSQL_INCLUDE_DIR}) add_executable(import-trace main.cc ${SRCS}) target_link_libraries(import-trace ${PROTOBUF_LIBRARY} - -lmysqlclient + ${MYSQL_LIBRARIES} fail-util fail-comm fail-sal) diff --git a/tools/import-trace/InstructionImporter.cc b/tools/import-trace/InstructionImporter.cc index e5472f3e..a1e72f79 100644 --- a/tools/import-trace/InstructionImporter.cc +++ b/tools/import-trace/InstructionImporter.cc @@ -1,4 +1,3 @@ -#ifndef __puma #include #include #include "InstructionImporter.hpp" @@ -77,6 +76,3 @@ bool InstructionImporter::handle_ip_event(fail::simtime_t curtime, instruction_c return true; } - - -#endif // !__puma diff --git a/tools/import-trace/InstructionImporter.hpp b/tools/import-trace/InstructionImporter.hpp index a60f5f57..81b58436 100644 --- a/tools/import-trace/InstructionImporter.hpp +++ b/tools/import-trace/InstructionImporter.hpp @@ -3,16 +3,11 @@ #include "Importer.hpp" -#ifndef __puma #include "util/llvmdisassembler/LLVMDisassembler.hpp" -#endif - class InstructionImporter : public Importer { -#ifndef __puma llvm::OwningPtr binary; llvm::OwningPtr disas; -#endif public: virtual bool handle_ip_event(fail::simtime_t curtime, instruction_count_t instr, diff --git a/tools/import-trace/RandomJumpImporter.cc b/tools/import-trace/RandomJumpImporter.cc index b83f1851..857c0b28 100644 --- a/tools/import-trace/RandomJumpImporter.cc +++ b/tools/import-trace/RandomJumpImporter.cc @@ -1,4 +1,3 @@ -#ifndef __puma #include #include #include "util/Logger.hpp" @@ -129,6 +128,3 @@ bool RandomJumpImporter::handle_ip_event(fail::simtime_t curtime, instruction_co return true; } - - -#endif // !__puma diff --git a/tools/import-trace/RandomJumpImporter.hpp b/tools/import-trace/RandomJumpImporter.hpp index 088f58ca..e9e38575 100644 --- a/tools/import-trace/RandomJumpImporter.hpp +++ b/tools/import-trace/RandomJumpImporter.hpp @@ -5,16 +5,11 @@ #include "util/CommandLine.hpp" #include "Importer.hpp" -#ifndef __puma #include "util/llvmdisassembler/LLVMDisassembler.hpp" -#endif - class RandomJumpImporter : public Importer { -#ifndef __puma llvm::OwningPtr binary; llvm::OwningPtr disas; -#endif fail::CommandLine::option_handle FROM, TO; diff --git a/tools/import-trace/RegisterImporter.cc b/tools/import-trace/RegisterImporter.cc index 6b44969e..a2b4a410 100644 --- a/tools/import-trace/RegisterImporter.cc +++ b/tools/import-trace/RegisterImporter.cc @@ -1,4 +1,3 @@ -#ifndef __puma #include #include #include "RegisterImporter.hpp" @@ -33,9 +32,8 @@ bool RegisterImporter::addRegisterTrace(simtime_t curtime, instruction_count_t i const Trace_Event &ev, const LLVMtoFailTranslator::reginfo_t &info, char access_type) { - LLVMtoFailTranslator::reginfo_t one_byte_window = info; - one_byte_window.width = 8; - address_t from = one_byte_window.toDataAddress(), to = one_byte_window.toDataAddress() + (info.width) / 8; + address_t from = info.toDataAddress(); + address_t to = from + info.width / 8; // Iterate over all accessed bytes for (address_t data_address = from; data_address < to; ++data_address) { @@ -131,6 +129,12 @@ bool RegisterImporter::handle_ip_event(fail::simtime_t curtime, instruction_coun for (std::vector::const_iterator it = opcode.reg_uses.begin(); it != opcode.reg_uses.end(); ++it) { const LLVMtoFailTranslator::reginfo_t &info = ltof.getFailRegisterID(*it); + if (&info == <of.notfound) { + LOG << "Could not find a mapping for LLVM input register #" << std::dec << *it + << " at IP " << std::hex << ev.ip() + << ", skipping" << std::endl; + continue; + } /* if not tracing flags, but flags register -> ignore it if not tracing gp, but ! flags -> ignore it*/ @@ -147,6 +151,13 @@ bool RegisterImporter::handle_ip_event(fail::simtime_t curtime, instruction_coun for (std::vector::const_iterator it = opcode.reg_defs.begin(); it != opcode.reg_defs.end(); ++it) { const LLVMtoFailTranslator::reginfo_t &info = ltof.getFailRegisterID(*it); + if (&info == <of.notfound) { + LOG << "Could not find a mapping for LLVM output register #" << std::dec << *it + << " at IP " << std::hex << ev.ip() + << ", skipping" << std::endl; + continue; + } + /* if not tracing flags, but flags register -> ignore it if not tracing gp, but ! flags -> ignore it*/ if (info.id == RID_FLAGS && !do_flags) @@ -168,6 +179,3 @@ bool RegisterImporter::handle_ip_event(fail::simtime_t curtime, instruction_coun return true; } - - -#endif // !__puma diff --git a/tools/import-trace/RegisterImporter.hpp b/tools/import-trace/RegisterImporter.hpp index 94c51ead..5cfacd49 100644 --- a/tools/import-trace/RegisterImporter.hpp +++ b/tools/import-trace/RegisterImporter.hpp @@ -5,13 +5,10 @@ #include "util/CommandLine.hpp" #include "Importer.hpp" -#ifndef __puma #include "util/llvmdisassembler/LLVMDisassembler.hpp" -#endif class RegisterImporter : public Importer { -#ifndef __puma llvm::OwningPtr binary; llvm::OwningPtr disas; @@ -19,8 +16,6 @@ class RegisterImporter : public Importer { const Trace_Event &ev, const fail::LLVMtoFailTranslator::reginfo_t &info, char access_type); -#endif - fail::CommandLine::option_handle NO_GP, FLAGS, IP; bool do_gp, do_flags, do_ip; diff --git a/tools/prune-trace/CMakeLists.txt b/tools/prune-trace/CMakeLists.txt index 32328f6d..a79e3451 100644 --- a/tools/prune-trace/CMakeLists.txt +++ b/tools/prune-trace/CMakeLists.txt @@ -3,7 +3,10 @@ set(SRCS BasicPruner.cc ) +find_package(MySQL REQUIRED) +include_directories(${MYSQL_INCLUDE_DIR}) + ## This is the example's campaign server distributing experiment parameters add_executable(prune-trace main.cc ${SRCS}) -target_link_libraries(prune-trace -lmysqlclient fail-util) +target_link_libraries(prune-trace ${MYSQL_LIBRARIES} fail-util) install(TARGETS prune-trace RUNTIME DESTINATION bin)