From: mlaurent Date: Tue, 7 Nov 2023 12:20:10 +0000 (+0100) Subject: Merge branch 'master' of https://framagit.org/simgrid/simgrid X-Git-Tag: v3.35~89 X-Git-Url: http://bilbo.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/fa33c62c831c17237ac38960b24596560ad3804d?hp=4f76cb02e1d37e95f8e9a14fd4fc84f4b27f7661 Merge branch 'master' of https://framagit.org/simgrid/simgrid --- diff --git a/.circleci/config.yml b/.circleci/config.yml index abd99f5377..b505615c32 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,5 +19,5 @@ jobs: name: Configure, build and test da stuff command: | mkdir _build && cd _build - cmake -Denable_documentation=OFF -Denable_coverage=OFF -Denable_model-checking=OFF -Denable_compile_optimizations=OFF -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=OFF -Denable_compile_warnings=ON .. + cmake -Denable_documentation=OFF -Denable_coverage=OFF -Denable_model-checking=OFF -Denable_compile_optimizations=OFF -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=OFF -Denable_compile_warnings=ON .. make -j4 tests && ctest -j4 --output-on-failure diff --git a/.github/workflows/git.yml b/.github/workflows/git.yml index 39d03c27d6..eb6bc035ab 100644 --- a/.github/workflows/git.yml +++ b/.github/workflows/git.yml @@ -39,8 +39,8 @@ jobs: mkdir build ; cd build cmake -GNinja -Denable_debug=ON -Denable_documentation=OFF -Denable_coverage=OFF \ -Denable_compile_optimizations=ON -Denable_compile_warnings=ON \ - -Denable_model-checking=OFF -Denable_smpi_MBI_testsuite=OFF \ - -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=ON \ + -Denable_model-checking=OFF -Denable_testsuite_smpi_MBI=OFF \ + -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=ON \ -DCMAKE_DISABLE_SOURCE_CHANGES=ON -DLTO_EXTRA_FLAG="auto" .. ninja tests ctest --output-on-failure -j$(nproc) @@ -72,13 +72,12 @@ jobs: - name: build run: | - sudo apt-get update && sudo apt-get install ninja-build libboost-dev libboost-context-dev pybind11-dev - sudo apt-get install libunwind-dev libdw-dev libelf-dev libevent-dev + sudo apt-get update && sudo apt-get install ninja-build libboost-dev libboost-context-dev pybind11-dev libevent-dev mkdir build ; cd build cmake -GNinja -Denable_debug=ON -Denable_documentation=OFF -Denable_coverage=OFF \ -Denable_compile_optimizations=ON -Denable_compile_warnings=ON \ - -Denable_model-checking=ON -Denable_smpi_MBI_testsuite=OFF \ - -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=OFF \ + -Denable_model-checking=ON -Denable_testsuite_smpi_MBI=OFF \ + -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=OFF \ -Denable_ns3=OFF \ -DCMAKE_DISABLE_SOURCE_CHANGES=ON -DLTO_EXTRA_FLAG="auto" .. ninja tests diff --git a/.gitignore b/.gitignore index c4b7ab787b..97d5571cbb 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,10 @@ tags callgrind.out.* ### Examples and traces *.exe +examples/c/activityset-testany/c-activityset-testany +examples/c/activityset-waitall/c-activityset-waitall +examples/c/activityset-waitallfor/c-activityset-waitallfor +examples/c/activityset-waitany/c-activityset-waitany examples/c/actor-create/c-actor-create examples/c/actor-daemon/c-actor-daemon examples/c/actor-exiting/c-actor-exiting @@ -143,6 +147,10 @@ examples/c/platform-failures/c-platform-failures examples/c/platform-properties/c-platform-properties examples/c/plugin-host-load/c-plugin-host-load examples/c/synchro-semaphore/c-synchro-semaphore +examples/cpp/activityset-testany/s4u-activityset-testany +examples/cpp/activityset-waitall/s4u-activityset-waitall +examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor +examples/cpp/activityset-waitany/s4u-activityset-waitany examples/cpp/actor-create/s4u-actor-create examples/cpp/actor-daemon/s4u-actor-daemon examples/cpp/actor-exiting/s4u-actor-exiting @@ -175,8 +183,11 @@ examples/cpp/comm-waitall/s4u-comm-waitall examples/cpp/comm-waitany/s4u-comm-waitany examples/cpp/comm-waituntil/s4u-comm-waituntil examples/cpp/dag-comm/s4u-dag-comm +examples/cpp/dag-tuto/s4u-dag-tuto examples/cpp/dag-failure/s4u-dag-failure examples/cpp/dag-from-dax/s4u-dag-from-dax +examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple +examples/cpp/dag-from-json-simple/s4u-dag-from-json-simple examples/cpp/dag-from-dot/s4u-dag-from-dot examples/cpp/dag-io/s4u-dag-io examples/cpp/dag-scheduling/s4u-dag-scheduling @@ -239,6 +250,13 @@ examples/cpp/synchro-condition-variable/s4u-synchro-condition-variable examples/cpp/synchro-condition-variable-waituntil/s4u-synchro-condition-variable-waituntil examples/cpp/synchro-mutex/s4u-synchro-mutex examples/cpp/synchro-semaphore/s4u-synchro-semaphore +examples/cpp/task-dispatch/s4u-task-dispatch +examples/cpp/task-io/s4u-task-io +examples/cpp/task-microservice/s4u-task-microservice +examples/cpp/task-parallelism/s4u-task-parallelism +examples/cpp/task-simple/s4u-task-simple +examples/cpp/task-storm/s4u-task-storm +examples/cpp/task-switch-host/s4u-task-switch-host examples/cpp/torus-multicpu/ examples/cpp/trace-categories/s4u-trace-categories examples/cpp/trace-host-user-variables/s4u-trace-host-user-variables diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 89000b0400..bbf969ba45 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,7 +11,7 @@ ctest-debug: script: - apt-get --allow-releaseinfo-change update - apt install -y binutils xsltproc - - cmake -Denable_model-checking=OFF -Denable_documentation=OFF -Denable_coverage=OFF -Denable_compile_optimizations=ON -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=ON -Denable_compile_warnings=ON -DLTO_EXTRA_FLAG="auto" . + - cmake -Denable_model-checking=OFF -Denable_documentation=OFF -Denable_coverage=OFF -Denable_compile_optimizations=ON -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=ON -Denable_testsuite_McMini=ON -Denable_compile_warnings=ON -DLTO_EXTRA_FLAG="auto" . - make -j$(nproc) VERBOSE=1 all tests - ctest -T Test -j$(nproc) --output-on-failure - xsltproc ./tools/jenkins/ctest2junit.xsl Testing/"$( head -n 1 < Testing/TAG )"/Test.xml > CTestResults.xml @@ -31,7 +31,7 @@ ctest-modelchecking: script: - apt-get --allow-releaseinfo-change update - apt install -y binutils xsltproc clang - - cmake -Denable_model-checking=ON -Denable_documentation=OFF -Denable_coverage=OFF -Denable_compile_optimizations=ON -Denable_smpi=ON -Denable_smpi_MPICH3_testsuite=OFF -Denable_compile_warnings=ON -DLTO_EXTRA_FLAG="auto" -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ . + - cmake -Denable_model-checking=ON -Denable_documentation=OFF -Denable_coverage=OFF -Denable_compile_optimizations=ON -Denable_smpi=ON -Denable_testsuite_smpi_MPICH3=OFF -Denable_testsuite_McMini=OFF -Denable_compile_warnings=ON -DLTO_EXTRA_FLAG="auto" -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ . - make -j$(nproc) VERBOSE=1 all tests - ctest -T Test -j$(nproc) --output-on-failure - xsltproc ./tools/jenkins/ctest2junit.xsl Testing/"$( head -n 1 < Testing/TAG )"/Test.xml > CTestResults.xml diff --git a/BuildSimGrid.sh b/BuildSimGrid.sh index 66b309eb8b..410d1ddb70 100755 --- a/BuildSimGrid.sh +++ b/BuildSimGrid.sh @@ -17,6 +17,7 @@ fi target=examples ncores=$(grep -c processor /proc/cpuinfo) +halfcores=$(expr $ncores / 2 + 1) install_path=$(sed -n 's/^CMAKE_INSTALL_PREFIX:PATH=//p' CMakeCache.txt) if [ -e ${install_path} ] && [ -d ${install_path} ] && [ -x ${install_path} ] && [ -w ${install_path} ] ; then @@ -32,7 +33,8 @@ fi ( echo "install_path: ${install_path}" echo "Target: ${target}" - echo "Cores: ${ncores}" - (nice ${builder} -j${ncores} ${target} tests || make ${target} tests) && nice ctest -j${ncores} --output-on-failure ; date + echo "Cores to build: ${ncores}" + echo "Cores to test: ${halfcores}" + (nice ${builder} -j${ncores} ${target} tests || ${builder} ${target} tests) && nice ctest -j${halfcores} --output-on-failure ; date ) 2>&1 | tee BuildSimGrid.sh.log diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a4a2459c5..47a5670865 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,12 +35,8 @@ include(GNUInstallDirs) #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Check for the compiler # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# -## -## Check the C/C++ standard that we need -## See also tools/cmake/Flags.cmake that sets our paranoid warning flags -INCLUDE(CheckCCompilerFlag) -CHECK_C_COMPILER_FLAG(-fstack-cleaner HAVE_C_STACK_CLEANER) +INCLUDE(CheckCCompilerFlag) ## Request full debugging flags set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3") @@ -217,21 +213,25 @@ if(enable_ns3) endif() ### Check for Eigen library -set(SIMGRID_HAVE_EIGEN3 OFF) -find_package (Eigen3 3.3 CONFIG - HINTS ${EIGEN3_HINT}) -if (Eigen3_FOUND) - set(SIMGRID_HAVE_EIGEN3 ON) - message(STATUS "Found Eigen3: ${EIGEN3_INCLUDE_DIR}") - include_directories(${EIGEN3_INCLUDE_DIR}) - if ("3.3.4" VERSION_EQUAL EIGEN3_VERSION_STRING AND CMAKE_COMPILER_IS_GNUCC) - message(STATUS "Avoid build error of Eigen3 v3.3.4 using -Wno-error=int-in-bool-context") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=int-in-bool-context") +if ((NOT DEFINED EIGEN3_HINT) OR (NOT EIGEN3_HINT STRLESS_EQUAL "OFF")) + set(SIMGRID_HAVE_EIGEN3 OFF) + find_package (Eigen3 3.3 CONFIG + HINTS ${EIGEN3_HINT}) + if (Eigen3_FOUND) + set(SIMGRID_HAVE_EIGEN3 ON) + message(STATUS "Found Eigen3: ${EIGEN3_INCLUDE_DIR}") + include_directories(${EIGEN3_INCLUDE_DIR}) + if ("3.3.4" VERSION_EQUAL EIGEN3_VERSION_STRING AND CMAKE_COMPILER_IS_GNUCC) + message(STATUS "Avoid build error of Eigen3 v3.3.4 using -Wno-error=int-in-bool-context") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=int-in-bool-context") + endif() + else() + message(STATUS "Disabling model BMF because Eigen3 was not found. If it's installed, use EIGEN3_HINT to hint cmake about the location of Eigen3Config.cmake") endif() + mark_as_advanced(Eigen3_DIR) else() - message(STATUS "Disabling model BMF because Eigen3 was not found. If it's installed, use EIGEN3_HINT to hint cmake about the location of Eigen3Config.cmake") + message(STATUS "Disabling Eigen3 as requested by the user (EIGEN3_HINT is set to 'OFF')") endif() -mark_as_advanced(Eigen3_DIR) # Check for our JSON dependency set(SIMGRID_HAVE_JSON 0) @@ -341,7 +341,6 @@ if(NOT HAVE_SYSCONF) message(FATAL_ERROR "Cannot build without sysconf.") endif() CHECK_FUNCTION_EXISTS(process_vm_readv HAVE_PROCESS_VM_READV) -CHECK_FUNCTION_EXISTS(mmap HAVE_MMAP) CHECK_FUNCTION_EXISTS(mremap HAVE_MREMAP) CHECK_SYMBOL_EXISTS(vasprintf stdio.h HAVE_VASPRINTF) @@ -354,14 +353,6 @@ else() set(SG_HAVE_SENDFILE 0) endif() -if(enable_model-checking AND NOT "${CMAKE_SYSTEM}" MATCHES "Linux|FreeBSD") - message(FATAL_ERROR "Support for model-checking has not been enabled on ${CMAKE_SYSTEM}. Please use a Linux docker to use the model checker.") -endif() - -if(enable_model-checking AND minimal-bindings) - message(FATAL_ERROR "Compile-time option 'minimal-bindings' cannot be enabled with 'model-checking'") -endif() - if(enable_mallocators) SET(SIMGRID_HAVE_MALLOCATOR 1) else() @@ -369,43 +360,19 @@ else() endif() SET(SIMGRID_HAVE_MC OFF) -SET(SIMGRID_HAVE_STATEFUL_MC OFF) -SET(HAVE_MMALLOC 0) - -find_package(Libevent) -if(Libevent_FOUND) - message(STATUS "Found libevent. The stateless model-checking can be enabled.") - include_directories(${LIBEVENT_INCLUDE_DIR}) - set(SIMGRID_DEP "${SIMGRID_DEP} ${LIBEVENT_LIBRARIES}") - SET(SIMGRID_HAVE_MC ON) -else() - message(STATUS "libevent not found. Please install libevent-dev to enable the SimGrid model checker.") -endif() -mark_as_advanced(LIBEVENT_LIBRARY) -mark_as_advanced(LIBEVENT_THREADS_LIBRARY) if(enable_model-checking) - include(FindLibunwind) - find_package(Libdw) - find_package(Libelf) - if(HAVE_MMAP AND HAVE_LIBUNWIND AND Libdw_FOUND AND Libelf_FOUND AND Libevent_FOUND) - message(STATUS "All dependencies found. The stateful model-checking can be enabled.") - SET(SIMGRID_HAVE_STATEFUL_MC ON) - SET(HAVE_MMALLOC 1) - SET(SIMGRID_DEP "${SIMGRID_DEP} ${LIBUNWIND_LIBRARIES} ${LIBELF_LIBRARIES} ${LIBDW_LIBRARIES}") - include_directories(${LIBDW_INCLUDE_DIR} ${LIBELF_INCLUDE_DIR}) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -gdwarf-4") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -gdwarf-4") + find_package(Libevent) + if(Libevent_FOUND) + message(STATUS "Found libevent. The stateless model-checking can be enabled.") + include_directories(${LIBEVENT_INCLUDE_DIR}) + set(SIMGRID_DEP "${SIMGRID_DEP} ${LIBEVENT_LIBRARIES}") + SET(SIMGRID_HAVE_MC ON) else() - message(STATUS "Please install libunwind-dev libdw-dev libelf-dev libevent-dev to enable the stateful model checker.") - set(HAVE_MMALLOC 0) + message(STATUS "libevent not found. Please install libevent-dev to enable the SimGrid model checker.") endif() -endif() -mark_as_advanced(PATH_LIBDW_H) -mark_as_advanced(PATH_LIBDW_LIB) - -if (SIMGRID_HAVE_STATEFUL_MC AND enable_ns3) - message(WARNING "Activating both model-checking and ns-3 bindings is considered experimental.") + mark_as_advanced(LIBEVENT_LIBRARY) + mark_as_advanced(LIBEVENT_THREADS_LIBRARY) endif() if(enable_smpi) @@ -798,11 +765,6 @@ endif() option(enable_python "Whether the Python bindings are activated." ${default_enable_python}) # ON by default if dependencies are met -if("${CMAKE_SYSTEM}" MATCHES "FreeBSD" AND enable_model-checking AND enable_python) - message(WARNING "FreeBSD + Model-Checking + Python = too much for now. Disabling the Python bindings.") - set(enable_python FALSE) -endif() - if(enable_python) if(NOT Python3_Development_FOUND) message(FATAL_ERROR "Please install the development components of Python (python3-dev on Debian) to build the Python bindings (or disable that option).") @@ -942,15 +904,15 @@ else() endif() message(" Compile Smpi ................: ${HAVE_SMPI}") message(" Smpi fortran ..............: ${SMPI_FORTRAN}") -message(" MPICH3 testsuite ..........: ${enable_smpi_MPICH3_testsuite}") -message(" MBI testsuite .............: ${enable_smpi_MBI_testsuite}") +message(" MPICH3 testsuite ..........: ${enable_testsuite_smpi_MPICH3}") +message(" MBI testsuite .............: ${enable_testsuite_smpi_MBI}") message(" Privatization .............: ${HAVE_PRIVATIZATION}") message(" PAPI support ..............: ${HAVE_PAPI}") message(" Compile Boost.Context support: ${HAVE_BOOST_CONTEXTS}") message("") message(" Model checking ..............: ${SIMGRID_HAVE_MC}") -message(" Stateful model checking ...: ${SIMGRID_HAVE_STATEFUL_MC}") -message(" MBI testsuite .............: ${enable_smpi_MBI_testsuite}") +message(" MBI testsuite .............: ${enable_testsuite_smpi_MBI}") +message(" McMini testsuite ..........: ${enable_testsuite_McMini}") message("") message(" Maintainer mode .............: ${enable_maintainer_mode}") message(" Documentation ...............: ${enable_documentation}") @@ -964,4 +926,3 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR} file(WRITE ${PROJECT_BINARY_DIR}/Testing/Notes/Build "GIT version : ${GIT_VERSION}\n") file(APPEND ${PROJECT_BINARY_DIR}/Testing/Notes/Build "Release : simgrid-${release_version}\n") -INCLUDE(Dart) diff --git a/COPYING b/COPYING index f4b1b6d7ef..c178bb31af 100644 --- a/COPYING +++ b/COPYING @@ -173,13 +173,6 @@ Copyright: 1997, Rolf Rabenseifner. Computing Center University of Stuttgart License: other-reduce-rab The usage of this software is free, but this header must not be removed. -Files: src/xbt/automaton/parserPromela.tab.cacc -Copyright: - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. - Copyright (C) 2003-2023. The SimGrid team. -License: GPL-3+ and LGPL-2.1-only -Comment: Generated with the Bison processor generator (which is GPL-3+) using SimGrid configuration files (that are LGPL-2.1-only) - Files: src/3rd-party/catch.hpp Copyright: Copyright (c) 2022 Two Blue Cubes Ltd. diff --git a/ChangeLog b/ChangeLog index 893664d9bc..c3dd61afbc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,15 +3,49 @@ SimGrid (3.34.1) not released (Target: fall 2023) S4U: - New class ActivitySet to ease wait_any()/test_any()/wait_all() - Deprecate {Comm,Io,Exec}::{wait_any,wait_all,test_any} and friends - - New function NetZone::add_route(host1, host2, links) when you don't need gateways - Also add a variant with s4u::Link, when you don't want to specify the directions - on symmetric routes. - - Introduce a Mailbox::get_async() with no payload parameter. You can use the new + - Simplify a bit the declaration of multi-zoned platforms from C++ + - New function NetZone::add_route(host1, host2, links) when you don't need gateways + - Also add a variant with s4u::Link, when you don't want to specify the directions + on symmetric routes. + - Zone's gateways can now be controlled directly. + - Add NetZone::add_route(zone1, zone2, links) specifying the route between zones + - Introduce a Mailbox::get_async() with no payload parameter. You can use the new Comm::get_payload() once the communication is over to retrieve the payload. + - Implement recursive mutexes. Simply pass true to the constructor to get one. + - Simplify the expression of horizontal scaling of Tasks. + - Each Task now consists of a dispatcher, a collector and one or more instances. + - The parallelism degree of each of these can be set. + - Several examples have been added or modified accordingly. + - Introduce a new MessageQueue abstraction and associated Mess simulated object. + The behavior of a MessageQueue is similar to that of a Mailbox, but intended for + control messages that do not incur any simulated cost. Information is automagically + transported over thin air between producer and consumer. See examples/cpp/mess-wait + +New S4U plugins: + - Add a JBOD (just a bunch of disks) concept. It's a sort of host with many disks. + - Revamp the battery plugin: rewrite completely the API, for a better usability. + The examples were updated accordingly. + The battery can now act as a simple connector (see battery-connector example). + - Revamp of the Photovoltaic plugin: now called SolarPanel and complete rewrite of the API + - Add chiller plugin: enable the management of chillers consuming electrical energy + to compensate heat generated by hosts. + - Add a battery-chiller-solar example combining several plugins to evaluate the amount + of brown energy (from the electrical grid) and green energy (from the solar panel) + during a given computation. SMPI: - New SMPI_app_instance_join(): wait for the completion of a started MPI instance - MPI_UNIVERSE_SIZE now initialized to the total amount of hosts in the platform + - Memory usage due to SMPI for non-MPI actors greatly reduced. + +sthread: + - Allow to use on valgrind-observed processes + - Install sthread on user's disk. + - Implement recursive pthreads. + - Add some McMini codes to test sthread further (controlled with enable_testsuite_McMini). + +Model checking: + - More informative backtraces on assertion failure. Python: - Make the host_load plugin available from Python. See examples/python/plugin-host-load @@ -19,17 +53,22 @@ Python: - Comm::waitall/waitany/testany() are gone. Please use ActivitySet() instead. - Comm::waitallfor() is gone too. Its semantic was unclear on timeout anyway. - Io::waitany() and waitanyfor() are gone. Please use ActivitySet() instead. + - Add the bindings of the host load plugin C API: - Introduce sg_activity_set_t and deprecate wait_all/wait_any/test_any for Exec, Io and Comm. -Plugins: - - Revamp the battery plugin: rewrite completely the API, for a better usability. - The examples were updated accordingly. - - Revamp of the Photovoltaic plugin: now called SolarPanel and complete rewrite of the API - - Add chiller plugin: enable the management of chillers consuming electrical energy - to compensate heat generated by hosts. +Kernel: + - optimize an internal data structure (replace boost::circular_buffer_space_optimized by + std::deque to store pending and unmatched Comms in Mailboxes). It is actually a revert + to what was used a few years back. The boost structure had a lower memory footprint than + deques, but it appeared that their "space_optimized" character was generating a huge lot + of refcount changes on the stored Comms. + +General: + - Fix errors with ns-3 v3.36+ + - Many other small bug fixes, in particular in MC and sthread. ---------------------------------------------------------------------------- diff --git a/MANIFEST.in b/MANIFEST.in index 1b8ad273d6..322f765f6f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -166,6 +166,10 @@ include examples/cpp/app-masterworkers/s4u-app-masterworkers.tesh include examples/cpp/app-masterworkers/s4u-app-masterworkers_d.xml include examples/cpp/app-token-ring/s4u-app-token-ring.cpp include examples/cpp/app-token-ring/s4u-app-token-ring.tesh +include examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp +include examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh +include examples/cpp/battery-connector/s4u-battery-connector.cpp +include examples/cpp/battery-connector/s4u-battery-connector.tesh include examples/cpp/battery-degradation/plot_battery_degradation.py include examples/cpp/battery-degradation/s4u-battery-degradation.cpp include examples/cpp/battery-degradation/s4u-battery-degradation.tesh @@ -310,16 +314,8 @@ include examples/cpp/io-priority/s4u-io-priority.cpp include examples/cpp/io-priority/s4u-io-priority.tesh include examples/cpp/maestro-set/s4u-maestro-set.cpp include examples/cpp/maestro-set/s4u-maestro-set.tesh -include examples/cpp/mc-bugged1-liveness/promela_bugged1_liveness -include examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner -include examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh -include examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp -include examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.tesh include examples/cpp/mc-bugged1/s4u-mc-bugged1.cpp include examples/cpp/mc-bugged1/s4u-mc-bugged1.tesh -include examples/cpp/mc-bugged2-liveness/promela_bugged2_liveness -include examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.cpp -include examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.tesh include examples/cpp/mc-bugged2/s4u-mc-bugged2.cpp include examples/cpp/mc-bugged2/s4u-mc-bugged2.tesh include examples/cpp/mc-centralized-mutex/s4u-mc-centralized-mutex.cpp @@ -327,9 +323,10 @@ include examples/cpp/mc-centralized-mutex/s4u-mc-centralized-mutex.tesh include examples/cpp/mc-electric-fence/s4u-mc-electric-fence.cpp include examples/cpp/mc-electric-fence/s4u-mc-electric-fence.tesh include examples/cpp/mc-failing-assert/s4u-mc-failing-assert-nodpor.tesh -include examples/cpp/mc-failing-assert/s4u-mc-failing-assert-statequality.tesh include examples/cpp/mc-failing-assert/s4u-mc-failing-assert.cpp include examples/cpp/mc-failing-assert/s4u-mc-failing-assert.tesh +include examples/cpp/mess-wait/s4u-mess-wait.cpp +include examples/cpp/mess-wait/s4u-mess-wait.tesh include examples/cpp/network-factors/s4u-network-factors.cpp include examples/cpp/network-factors/s4u-network-factors.tesh include examples/cpp/network-nonlinear/s4u-network-nonlinear.cpp @@ -348,8 +345,6 @@ include examples/cpp/network-ns3/s4u-network-ns3-timed.tesh include examples/cpp/network-ns3/s4u-network-ns3.cpp include examples/cpp/network-wifi/s4u-network-wifi.cpp include examples/cpp/network-wifi/s4u-network-wifi.tesh -include examples/cpp/solar-panel-simple/s4u-solar-panel-simple.cpp -include examples/cpp/solar-panel-simple/s4u-solar-panel-simple.tesh include examples/cpp/platform-comm-serialize/s4u-platform-comm-serialize.cpp include examples/cpp/platform-comm-serialize/s4u-platform-comm-serialize.tesh include examples/cpp/platform-failures/s4u-platform-failures.cpp @@ -380,6 +375,8 @@ include examples/cpp/replay-io/s4u-replay-io.txt include examples/cpp/replay-io/s4u-replay-io_d.xml include examples/cpp/routing-get-clusters/s4u-routing-get-clusters.cpp include examples/cpp/routing-get-clusters/s4u-routing-get-clusters.tesh +include examples/cpp/solar-panel-simple/s4u-solar-panel-simple.cpp +include examples/cpp/solar-panel-simple/s4u-solar-panel-simple.tesh include examples/cpp/synchro-barrier/s4u-mc-synchro-barrier.tesh include examples/cpp/synchro-barrier/s4u-synchro-barrier.cpp include examples/cpp/synchro-barrier/s4u-synchro-barrier.tesh @@ -387,7 +384,6 @@ include examples/cpp/synchro-condition-variable-waituntil/s4u-synchro-condition- include examples/cpp/synchro-condition-variable-waituntil/s4u-synchro-condition-variable-waituntil.tesh include examples/cpp/synchro-condition-variable/s4u-synchro-condition-variable.cpp include examples/cpp/synchro-condition-variable/s4u-synchro-condition-variable.tesh -include examples/cpp/synchro-mutex/s4u-mc-synchro-mutex-stateful.tesh include examples/cpp/synchro-mutex/s4u-mc-synchro-mutex.tesh include examples/cpp/synchro-mutex/s4u-synchro-mutex.cpp include examples/cpp/synchro-mutex/s4u-synchro-mutex.tesh @@ -526,22 +522,14 @@ include examples/smpi/gemm/gemm.c include examples/smpi/gemm/gemm.tesh include examples/smpi/hostfile include examples/smpi/mc/bugged1.c -include examples/smpi/mc/bugged1_liveness.c include examples/smpi/mc/bugged2.c include examples/smpi/mc/hostfile_bugged1 -include examples/smpi/mc/hostfile_bugged1_liveness include examples/smpi/mc/hostfile_bugged2 include examples/smpi/mc/hostfile_mutual_exclusion -include examples/smpi/mc/hostfile_non_termination include examples/smpi/mc/hostfile_only_send_deterministic include examples/smpi/mc/mutual_exclusion.c -include examples/smpi/mc/non_termination1.c -include examples/smpi/mc/non_termination2.c -include examples/smpi/mc/non_termination3.c -include examples/smpi/mc/non_termination4.c include examples/smpi/mc/only_send_deterministic.c include examples/smpi/mc/only_send_deterministic.tesh -include examples/smpi/mc/promela_bugged1_liveness include examples/smpi/mc/sendsend.c include examples/smpi/mc/sendsend.tesh include examples/smpi/replay/actions0.txt @@ -643,9 +631,12 @@ include examples/smpi/trace_call_location/trace_call_location.c include examples/smpi/trace_call_location/trace_call_location.tesh include examples/smpi/trace_simple/trace_simple.c include examples/smpi/trace_simple/trace_simple.tesh +include examples/sthread/pthread-mc-mutex-recursive.tesh include examples/sthread/pthread-mc-mutex-simple.tesh include examples/sthread/pthread-mc-mutex-simpledeadlock.tesh include examples/sthread/pthread-mc-producer-consumer.tesh +include examples/sthread/pthread-mutex-recursive.c +include examples/sthread/pthread-mutex-recursive.tesh include examples/sthread/pthread-mutex-simple.c include examples/sthread/pthread-mutex-simple.tesh include examples/sthread/pthread-mutex-simpledeadlock.c @@ -663,10 +654,22 @@ include teshsuite/kernel/context-defaults/factory_thread.tesh include teshsuite/kernel/context-defaults/factory_ucontext.tesh include teshsuite/kernel/stack-overflow/stack-overflow.cpp include teshsuite/kernel/stack-overflow/stack-overflow.tesh -include teshsuite/mc/dwarf-expression/dwarf-expression.cpp -include teshsuite/mc/dwarf-expression/dwarf-expression.tesh -include teshsuite/mc/dwarf/dwarf.cpp -include teshsuite/mc/dwarf/dwarf.tesh +include teshsuite/mc/mcmini/barber_shop_deadlock.c +include teshsuite/mc/mcmini/barber_shop_deadlock.tesh +include teshsuite/mc/mcmini/barber_shop_ok.c +include teshsuite/mc/mcmini/barber_shop_ok.tesh +include teshsuite/mc/mcmini/philosophers_mutex_deadlock.c +include teshsuite/mc/mcmini/philosophers_mutex_deadlock.tesh +include teshsuite/mc/mcmini/philosophers_mutex_ok.c +include teshsuite/mc/mcmini/philosophers_mutex_ok.tesh +include teshsuite/mc/mcmini/philosophers_semaphores_deadlock.c +include teshsuite/mc/mcmini/philosophers_semaphores_deadlock.tesh +include teshsuite/mc/mcmini/philosophers_semaphores_ok.c +include teshsuite/mc/mcmini/philosophers_semaphores_ok.tesh +include teshsuite/mc/mcmini/producer_consumer_deadlock.c +include teshsuite/mc/mcmini/producer_consumer_deadlock.tesh +include teshsuite/mc/mcmini/producer_consumer_ok.c +include teshsuite/mc/mcmini/producer_consumer_ok.tesh include teshsuite/mc/mutex-handling/mutex-handling.cpp include teshsuite/mc/mutex-handling/mutex-handling.tesh include teshsuite/mc/mutex-handling/without-mutex-handling.tesh @@ -1610,9 +1613,6 @@ include teshsuite/xbt/log_large/log_large.tesh include teshsuite/xbt/log_usage/log_usage.c include teshsuite/xbt/log_usage/log_usage.tesh include teshsuite/xbt/log_usage/log_usage_ndebug.tesh -include teshsuite/xbt/mmalloc/mmalloc_32.tesh -include teshsuite/xbt/mmalloc/mmalloc_64.tesh -include teshsuite/xbt/mmalloc/mmalloc_test.cpp include teshsuite/xbt/parallel_log_crashtest/parallel_log_crashtest.cpp include teshsuite/xbt/parallel_log_crashtest/parallel_log_crashtest.tesh include teshsuite/xbt/parmap_bench/parmap_bench.cpp @@ -1623,7 +1623,6 @@ include teshsuite/xbt/signals/signals.cpp include teshsuite/xbt/signals/signals.tesh include tools/address_sanitizer.supp include tools/fix-paje-trace.sh -include tools/generate-dwarf-functions include tools/graphicator/graphicator.cpp include tools/graphicator/graphicator.tesh include tools/normalize-pointers.py @@ -1966,6 +1965,8 @@ include include/simgrid/s4u/Host.hpp include include/simgrid/s4u/Io.hpp include include/simgrid/s4u/Link.hpp include include/simgrid/s4u/Mailbox.hpp +include include/simgrid/s4u/Mess.hpp +include include/simgrid/s4u/MessageQueue.hpp include include/simgrid/s4u/Mutex.hpp include include/simgrid/s4u/NetZone.hpp include include/simgrid/s4u/Semaphore.hpp @@ -1990,8 +1991,6 @@ include include/xbt/Extendable.hpp include include/xbt/PropertyHolder.hpp include include/xbt/asserts.h include include/xbt/asserts.hpp -include include/xbt/automaton.h -include include/xbt/automaton.hpp include include/xbt/backtrace.hpp include include/xbt/base.h include include/xbt/config.h @@ -2062,6 +2061,10 @@ include src/kernel/activity/IoImpl.cpp include src/kernel/activity/IoImpl.hpp include src/kernel/activity/MailboxImpl.cpp include src/kernel/activity/MailboxImpl.hpp +include src/kernel/activity/MessImpl.cpp +include src/kernel/activity/MessImpl.hpp +include src/kernel/activity/MessageQueueImpl.cpp +include src/kernel/activity/MessageQueueImpl.hpp include src/kernel/activity/MutexImpl.cpp include src/kernel/activity/MutexImpl.hpp include src/kernel/activity/SemaphoreImpl.cpp @@ -2187,9 +2190,6 @@ include src/kernel/xml/sg_platf.cpp include src/kernel/xml/simgrid.dtd include src/kernel/xml/simgrid_dtd.c include src/kernel/xml/simgrid_dtd.h -include src/mc/AddressSpace.hpp -include src/mc/VisitedState.cpp -include src/mc/VisitedState.hpp include src/mc/api/ActorState.hpp include src/mc/api/ClockVector.cpp include src/mc/api/ClockVector.hpp @@ -2202,15 +2202,12 @@ include src/mc/api/strategy/MaxMatchComm.hpp include src/mc/api/strategy/MinMatchComm.hpp include src/mc/api/strategy/Strategy.hpp include src/mc/api/strategy/UniformStrategy.hpp -include src/mc/compare.cpp include src/mc/datatypes.h include src/mc/explo/CommunicationDeterminismChecker.cpp include src/mc/explo/DFSExplorer.cpp include src/mc/explo/DFSExplorer.hpp include src/mc/explo/Exploration.cpp include src/mc/explo/Exploration.hpp -include src/mc/explo/LivenessChecker.cpp -include src/mc/explo/LivenessChecker.hpp include src/mc/explo/UdporChecker.cpp include src/mc/explo/UdporChecker.hpp include src/mc/explo/odpor/ClockVector_test.cpp @@ -2250,24 +2247,6 @@ include src/mc/explo/udpor/maximal_subsets_iterator.cpp include src/mc/explo/udpor/maximal_subsets_iterator.hpp include src/mc/explo/udpor/udpor_forward.hpp include src/mc/explo/udpor/udpor_tests_private.hpp -include src/mc/inspect/DwarfExpression.cpp -include src/mc/inspect/DwarfExpression.hpp -include src/mc/inspect/Frame.cpp -include src/mc/inspect/Frame.hpp -include src/mc/inspect/LocationList.cpp -include src/mc/inspect/LocationList.hpp -include src/mc/inspect/ObjectInformation.cpp -include src/mc/inspect/ObjectInformation.hpp -include src/mc/inspect/Type.hpp -include src/mc/inspect/Variable.hpp -include src/mc/inspect/mc_dwarf.cpp -include src/mc/inspect/mc_dwarf.hpp -include src/mc/inspect/mc_dwarf_attrnames.cpp -include src/mc/inspect/mc_dwarf_tagnames.cpp -include src/mc/inspect/mc_member.cpp -include src/mc/inspect/mc_unw.cpp -include src/mc/inspect/mc_unw.hpp -include src/mc/inspect/mc_unw_vmread.cpp include src/mc/mc.h include src/mc/mc_base.cpp include src/mc/mc_base.hpp @@ -2291,22 +2270,10 @@ include src/mc/remote/CheckerSide.cpp include src/mc/remote/CheckerSide.hpp include src/mc/remote/RemotePtr.hpp include src/mc/remote/mc_protocol.h -include src/mc/sosp/ChunkedData.cpp -include src/mc/sosp/ChunkedData.hpp -include src/mc/sosp/PageStore.cpp -include src/mc/sosp/PageStore.hpp -include src/mc/sosp/PageStore_test.cpp -include src/mc/sosp/Region.cpp -include src/mc/sosp/Region.hpp -include src/mc/sosp/RemoteProcessMemory.cpp -include src/mc/sosp/RemoteProcessMemory.hpp -include src/mc/sosp/Snapshot.cpp -include src/mc/sosp/Snapshot.hpp -include src/mc/sosp/Snapshot_test.cpp include src/mc/transition/Transition.cpp include src/mc/transition/Transition.hpp -include src/mc/transition/TransitionActorJoin.cpp -include src/mc/transition/TransitionActorJoin.hpp +include src/mc/transition/TransitionActor.cpp +include src/mc/transition/TransitionActor.hpp include src/mc/transition/TransitionAny.cpp include src/mc/transition/TransitionAny.hpp include src/mc/transition/TransitionComm.cpp @@ -2346,6 +2313,8 @@ include src/s4u/s4u_Host.cpp include src/s4u/s4u_Io.cpp include src/s4u/s4u_Link.cpp include src/s4u/s4u_Mailbox.cpp +include src/s4u/s4u_Mess.cpp +include src/s4u/s4u_MessageQueue.cpp include src/s4u/s4u_Mutex.cpp include src/s4u/s4u_Netzone.cpp include src/s4u/s4u_Semaphore.cpp @@ -2551,13 +2520,6 @@ include src/sthread/sthread.h include src/sthread/sthread_impl.cpp include src/xbt/OsSemaphore.hpp include src/xbt/PropertyHolder.cpp -include src/xbt/automaton/automaton.c -include src/xbt/automaton/automaton_lexer.yy.c -include src/xbt/automaton/automatonparse_promela.c -include src/xbt/automaton/parserPromela.lex -include src/xbt/automaton/parserPromela.tab.cacc -include src/xbt/automaton/parserPromela.tab.hacc -include src/xbt/automaton/parserPromela.yacc include src/xbt/backtrace.cpp include src/xbt/config.cpp include src/xbt/config_test.cpp @@ -2577,20 +2539,6 @@ include src/xbt/mallocator.c include src/xbt/mallocator_private.h include src/xbt/memory_map.cpp include src/xbt/memory_map.hpp -include src/xbt/mmalloc/mfree.c -include src/xbt/mmalloc/mm.c -include src/xbt/mmalloc/mm_interface.c -include src/xbt/mmalloc/mm_legacy.c -include src/xbt/mmalloc/mm_module.c -include src/xbt/mmalloc/mmalloc.c -include src/xbt/mmalloc/mmalloc.h -include src/xbt/mmalloc/mmalloc.info -include src/xbt/mmalloc/mmalloc.texi -include src/xbt/mmalloc/mmorecore.c -include src/xbt/mmalloc/mmprivate.h -include src/xbt/mmalloc/mrealloc.c -include src/xbt/mmalloc/swag.c -include src/xbt/mmalloc/swag.h include src/xbt/parmap.cpp include src/xbt/parmap.hpp include src/xbt/random.cpp @@ -2666,10 +2614,7 @@ include tools/cmake/Flags.cmake include tools/cmake/MaintainerMode.cmake include tools/cmake/MakeLib.cmake include tools/cmake/Modules/FindGraphviz.cmake -include tools/cmake/Modules/FindLibdw.cmake -include tools/cmake/Modules/FindLibelf.cmake include tools/cmake/Modules/FindLibevent.cmake -include tools/cmake/Modules/FindLibunwind.cmake include tools/cmake/Modules/FindNS3.cmake include tools/cmake/Modules/FindPAPI.cmake include tools/cmake/Modules/FindValgrind.cmake diff --git a/docs/source/Configuring_SimGrid.rst b/docs/source/Configuring_SimGrid.rst index 72d4c516a8..c0ecf2cd11 100644 --- a/docs/source/Configuring_SimGrid.rst +++ b/docs/source/Configuring_SimGrid.rst @@ -108,18 +108,14 @@ Existing Configuration Items - **maxmin/concurrency-limit:** :ref:`cfg=maxmin/concurrency-limit` - **model-check:** :ref:`options_modelchecking` -- **model-check/checkpoint:** :ref:`cfg=model-check/checkpoint` - **model-check/communications-determinism:** :ref:`cfg=model-check/communications-determinism` - **model-check/dot-output:** :ref:`cfg=model-check/dot-output` - **model-check/max-depth:** :ref:`cfg=model-check/max-depth` -- **model-check/property:** :ref:`cfg=model-check/property` - **model-check/reduction:** :ref:`cfg=model-check/reduction` - **model-check/replay:** :ref:`cfg=model-check/replay` - **model-check/send-determinism:** :ref:`cfg=model-check/send-determinism` - **model-check/setenv:** :ref:`cfg=model-check/setenv` -- **model-check/termination:** :ref:`cfg=model-check/termination` - **model-check/timeout:** :ref:`cfg=model-check/timeout` -- **model-check/visited:** :ref:`cfg=model-check/visited` - **network/bandwidth-factor:** :ref:`cfg=network/bandwidth-factor` - **network/crosstraffic:** :ref:`cfg=network/crosstraffic` @@ -527,8 +523,6 @@ Note that with the default host model this option is activated by default. Simulating Asynchronous Send ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -(this configuration item is experimental and may change or disappear) - It is possible to specify that messages below a certain size (in bytes) will be sent as soon as the call to MPI_Send is issued, without waiting for the correspondent receive. This threshold can be configured through @@ -647,38 +641,6 @@ The ``smpi/buffering`` (only valid with MC) option gives an easier interface to - **zero:** means that buffering should be disabled. All communications are actually blocking. - **infty:** means that buffering should be made infinite. All communications are non-blocking. -.. _cfg=model-check/property: - -Specifying a liveness property -.............................. - -**Option** ``model-check/property`` **Default:** unset - -If you want to specify liveness properties, you have to pass them on -the command line, specifying the name of the file containing the -property, as formatted by the `ltl2ba `_ program. -Note that ltl2ba is not part of SimGrid and must be installed separately. - -.. code-block:: console - - $ simgrid-mc ./my_program --cfg=model-check/property: - -.. _cfg=model-check/checkpoint: - -Going for Stateful Verification -............................... - -By default, the system is backtracked to its initial state to explore -another path, instead of backtracking to the exact step before the fork -that we want to explore (this is called stateless verification). This -is done this way because saving intermediate states can rapidly -exhaust the available memory. If you want, you can change the value of -the ``model-check/checkpoint`` item. For example, -``--cfg=model-check/checkpoint:1`` asks to take a checkpoint every -step. Beware, this will certainly explode your memory. Larger values -are probably better, make sure to experiment a bit to find the right -setting for your specific system. - .. _cfg=model-check/reduction: Specifying the kind of reduction @@ -691,7 +653,7 @@ explosion. You can activate some reduction technique with ``--cfg=model-check/reduction:``. For now, this configuration variable can take 2 values: - - **none:** Do not apply any kind of reduction (mandatory for liveness properties, as our current DPOR algorithm breaks cycles) + - **none:** Do not apply any kind of reduction - **dpor:** Apply Dynamic Partial Ordering Reduction. Only valid if you verify local safety properties (default value for safety checks). - **sdpor:** Source-set DPOR, as described in "Source Sets: A Foundation for Optimal Dynamic Partial Order Reduction" @@ -699,15 +661,9 @@ configuration variable can take 2 values: - **odpor:** Optimal DPOR, as described in "Source Sets: A Foundation for Optimal Dynamic Partial Order Reduction" by Abdulla et al. -Another way to mitigate the state space explosion is to search for -cycles in the exploration with the :ref:`cfg=model-check/visited` -configuration. Note that DPOR and state-equality reduction may not -play well together. You should choose between them. - Our current DPOR implementation could be improved in may ways. We are currently improving its efficiency (both in term of reduction ability -and computational speed), and future work could make it compatible -with liveness properties. +and computational speed). .. _cfg=model-check/strategy: @@ -730,45 +686,6 @@ DFS exploration. - **uniform**: this is a boring random strategy where choices are based on a uniform sampling of possible choices. Surprisingly, it gives really really good results. -.. _cfg=model-check/visited: - -Size of Cycle Detection Set (state equality reduction) -...................................................... - -Mc SimGrid can be asked to search for cycles during the exploration, -i.e. situations where a new explored state is in fact the same state -than a previous one.. This can prove useful to mitigate the state -space explosion with safety properties, and this is the crux when -searching for counter-examples to the liveness properties. - -Note that this feature may break the current implementation of the -DPOR reduction technique. - -The ``model-check/visited`` item is the maximum number of states, which -are stored in memory. If the maximum number of snapshotted state is -reached, some states will be removed from the memory and some cycles -might be missed. Small values can lead to incorrect verifications, but -large values can exhaust your memory and be CPU intensive as each new -state must be compared to that amount of older saved states. - -The default settings depend on the kind of exploration. With safety -checking, no state is snapshotted and cycles cannot be detected. With -liveness checking, all states are snapshotted because missing a cycle -could hinder the exploration soundness. - -.. _cfg=model-check/termination: - -Non-Termination Detection -......................... - -The ``model-check/termination`` configuration item can be used to -report if a non-termination execution path has been found. This is a -path with a cycle, which means that the program might never terminate. - -This only works in safety mode, not in liveness mode. - -This options is disabled by default. - .. _cfg=model-check/dot-output: Dot Output @@ -776,8 +693,7 @@ Dot Output If set, the ``model-check/dot-output`` configuration item is the name of a file in which to write a dot file of the path leading to the -property violation discovered (safety or liveness violation), as well -as the cycle for liveness properties. This dot file can then be fed to the +property violation discovered (safety violation). This dot file can then be fed to the graphviz dot tool to generate a corresponding graphical representation. .. _cfg=model-check/max-depth: @@ -852,7 +768,7 @@ this path reported by the model checker, enabling the usage of classical debugging tools. When the model checker finds an interesting path in the application -execution graph (where a safety or liveness property is violated), it +execution graph (where a safety property is violated), it generates an identifier for this path. Here is an example of the output: .. code-block:: console diff --git a/docs/source/Installing_SimGrid.rst b/docs/source/Installing_SimGrid.rst index 477b53ed9a..39cc872e8f 100644 --- a/docs/source/Installing_SimGrid.rst +++ b/docs/source/Installing_SimGrid.rst @@ -43,6 +43,17 @@ email. .. _simgrid AUR package: https://aur.archlinux.org/packages/simgrid/ .. _AUR official documentation: https://wiki.archlinux.org/title/Arch_User_Repository +Binaries from macOS +^^^^^^^^^^^^^^^^^^^ + +SimGrid can be found in the Homebrew package manager. Troubleshooting: + +warning: dylib (libsimgrid.dylib) was built for newer macOS version (14.0) than being linked (13.3) + This was reported with the SimGrid version from Homebrew on a Mac book air M1 (ARM). + The solution is simply to export this variable before the compilation of your binaries: + + ``export MACOSX_DEPLOYMENT_TARGET=14.0`` + .. _deprecation_policy: Version numbering and deprecation @@ -102,13 +113,11 @@ python bindings (optional): - On Debian / Ubuntu: ``apt install pybind11-dev python3-dev`` Model-checking mandatory dependencies - On Debian / Ubuntu: ``apt install libevent-dev`` -Model-checking optional dependencies - - On Debian / Ubuntu: ``apt install libunwind-dev libdw-dev libelf-dev`` Eigen3 (optional) - On Debian / Ubuntu: ``apt install libeigen3-dev`` - On CentOS / Fedora: ``dnf install eigen3-devel`` - On macOS with homebrew: ``brew install eigen`` - - Use EIGEN3_HINT to specify where it's installed if cmake doesn't find it automatically. + - Use EIGEN3_HINT to specify where it's installed if cmake doesn't find it automatically. Set EIGEN3_HINT=OFF to disable detection even if it could be found. JSON (optional, for the DAG wfcommons loader) - On Debian / Ubuntu: ``apt install nlohmann-json3-dev`` - Use nlohmann_json_HINT to specify where it's installed if cmake doesn't find it automatically. @@ -243,10 +252,9 @@ enable_mallocators (ON/off) Activates our internal memory caching mechanism. This produces faster code, but it may fool the debuggers. -enable_model-checking (on/OFF) - Activates the liveness verification mode. This will hinder simulation speed even when the model checker is not activated at run - time, because some optimizations such as LTO must be disabled at compile time. You need to have the :ref:`required - build-dependencies ` to activate this option. +enable_model-checking (ON/off) + Activates the verification mode. This should not impact the performance of your simulations if you build it but don't use it, + but you can still disable it to save some compilation time. enable_ns3 (on/OFF) Activates the ns-3 bindings. See section :ref:`models_ns3`. @@ -254,10 +262,13 @@ enable_ns3 (on/OFF) enable_smpi (ON/off) Allows one to run MPI code on top of SimGrid. -enable_smpi_MBI_testsuite (on/OFF) - Adds many extra tests for the model checker module. +enable_testsuite_McMini (on/OFF) + Adds several extra tests for the model checker module (targeting threaded applications). + +enable_testsuite_smpi_MBI (on/OFF) + Adds many extra tests for the model checker module (targeting MPI applications). -enable_smpi_MPICH3_testsuite (on/OFF) +enable_testsuite_smpi_MPICH3 (on/OFF) Adds many extra tests for the MPI module. minimal-bindings (on/OFF) @@ -269,6 +280,7 @@ NS3_HINT (empty by default) EIGEN3_HINT (empty by default) Alternative path into which Eigen3 should be searched for. + Providing the value OFF as an hint will disable the detection alltogether. SIMGRID_PYTHON_LIBDIR (auto-detected) Where to install the Python module library. By default, it is set to the cmake Python3_SITEARCH variable if installing to /usr, @@ -401,7 +413,7 @@ Windows-specific instructions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The best solution to get SimGrid working on windows is to install the -Ubuntu subsystem of Windows 10. All of SimGrid (but the liveness model checker) +Ubuntu subsystem of Windows 10. All of SimGrid works in this setting. Native builds never really worked, and they are disabled starting with SimGrid v3.33. diff --git a/docs/source/Plugins.rst b/docs/source/Plugins.rst index 659e67c1ce..c40e5e61b9 100644 --- a/docs/source/Plugins.rst +++ b/docs/source/Plugins.rst @@ -25,6 +25,7 @@ documents some of the plugins distributed with SimGrid: - :ref:`WiFi Energy `: models the energy dissipation of wifi links. - :ref:`Battery `: models batteries that get discharged by the energy consumption of a given host. - :ref:`Solar Panel `: models solar panels which energy production depends on the solar irradiance. + - :ref:`Chiller `: models chillers which dissipate heat by consuming energy. You can activate these plugins with the :ref:`--cfg=plugin ` command line option, for example with ``--cfg=plugin:host_energy``. You can get the full @@ -231,11 +232,11 @@ Solar Panel .. doxygengroup:: plugin_solar_panel +.. _plugin_chiller: + Chiller ======= .. doxygengroup:: plugin_chiller - .. doxygentypedef:: ChillerPtr - .. LocalWords: SimGrid diff --git a/docs/source/Release_Notes.rst b/docs/source/Release_Notes.rst index 55b0d5a2d8..346f563697 100644 --- a/docs/source/Release_Notes.rst +++ b/docs/source/Release_Notes.rst @@ -626,9 +626,10 @@ reacting to every signals of a class, and then filtering on the object you want. completion) are now specialized by activity class. That is, callbacks registered in Exec::on_suspend_cb will not be fired for Comms nor Ios -Two new useful plugins were added: The :ref:`battery plugin` can be used to create batteries that get discharged -by the energy consumption of a given host, while the :ref:`solar panel plugin ` can be used to create -solar panels which energy production depends on the solar irradiance. These plugins could probably be better integrated +Three new useful plugins were added: The :ref:`battery plugin` can be used to create batteries that get discharged +by the energy consumption of a given host, the :ref:`solar panel plugin ` can be used to create +solar panels which energy production depends on the solar irradiance and the :ref:`chiller plugin ` can be used to +create chillers and compensate the heat generated by hosts. These plugins could probably be better integrated in the framework, but our goal is to include in SimGrid the building blocks upon which everybody would agree, while the model elements that are more arguable are provided as plugins, in the hope that the users will carefully assess the plugins and adapt them to their specific needs before usage. Here for example, there is several models of batteries (the one provided does not @@ -667,7 +668,13 @@ This feature is not very usable yet, as you have to manually annotate your code, Version 3.35 (TBD) ------------------ - +**On the interface front**, we introduced a new MessageQueue abstraction and associated Mess simulated object. The behavior of a +MessageQueue is similar to that of a Mailbox, but intended for control messages that do not incur any simulated cost. +Information is automagically transported over thin air between producer and consumer. Internally, the implementation is very +similar to Mailboxes and Comms, only simpler. The motivation for this new abstraction came from a scalability issue observed in +the WRENCH framework, which is heavily based on control messages. When the simulated size of these messages is set to 0, it creates +very short lived network actions (i.e., lasting for only the route latency) that tend to overwhelm the LMM. Switching from Mailbox +to MessageQueue for such information exchange avoid this problem and greatly improves the scalability of WRENCH-based simulators. .. |br| raw:: html diff --git a/docs/source/Tutorial_Model-checking.rst b/docs/source/Tutorial_Model-checking.rst index 03bf0a0294..4e01642d53 100644 --- a/docs/source/Tutorial_Model-checking.rst +++ b/docs/source/Tutorial_Model-checking.rst @@ -4,7 +4,7 @@ Formal Verification and Model-checking ====================================== SimGrid can not only predict the performance of your application, but also assess its correctness through formal methods. Mc SimGrid is -a full-featured model-checker that is embedded in the SimGrid framework. It can be used to formally verify safety and liveness +a full-featured model-checker that is embedded in the SimGrid framework. It can be used to formally verify safety properties on codes running on top of SimGrid, be it :ref:`simple algorithms ` or :ref:`full MPI applications `. @@ -31,7 +31,7 @@ barrier, etc). Since it does not explicitly observe memory accesses, Mc SimGrid multithreaded programs. It can however be used to detect misuses of the synchronization functions, such as the ones resulting in deadlocks. -Mc SimGrid can be used to verify classical `safety and liveness properties `_, but +Mc SimGrid can be used to verify classical `safety properties `_, but also `communication determinism `_, a property that allows more efficient solutions toward fault-tolerance. It can alleviate the state space explosion problem through `Dynamic Partial Ordering Reduction (DPOR) `_ and `state equality `_. Note that @@ -308,11 +308,6 @@ If you want to run such analysis on your own code, out of the provided docker, t - SimGrid should naturally :ref:`be compiled ` with model-checking support. This requires a full set of dependencies (documented on the :ref:`relevant page `) and should not be activated by default as there is a small performance penalty for codes using a SimGrid with MC enabled (even if you don't activate the model-checking at run time). -- You should pass some specific flags to the linker when compiling your application: ``-Wl,-znorelro -Wl,-znoseparate-code`` In the - docker, the provided CMakeLists.txt provides them for you when compiling the provided code. ``smpicc`` and friends also add this - parameter automatically. -- If you get error messages complaining about the Dwarf version used, try adding ``-gdwarf-4`` to you CFLAGS and CXXFLAGS. - If you find a situation where this flag is needed in ``smpicc``, please report this issue. - Also install ``libboost-stacktrace-dev`` to display nice backtraces from the application side (the one from the model-checking side is available in any case, but it contains less details). - Mc SimGrid uses the ``ptrace`` system call to spy on the verified application. Some versions of Docker forbid the use of this call by @@ -324,11 +319,12 @@ Going further ------------- This tutorial is not complete yet, as there is nothing on reduction -techniques nor on liveness properties. For now, the best source of +techniques. For now, the best source of information on these topics is `this old tutorial `_ and `that old presentation -`_. +`_. But be warned that these source of +information are very old: the liveness verification was removed in v3.35, even if these docs still mention it. .. |br| raw:: html diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index b917540cf1..0361ccb114 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -34,67 +34,6 @@ else() endforeach() endif() -set(tesh_files ${tesh_files} ${CMAKE_CURRENT_SOURCE_DIR}/synchro-mutex/s4u-mc-synchro-mutex-stateful.tesh) -if(SIMGRID_HAVE_STATEFUL_MC) - if(HAVE_C_STACK_CLEANER) - add_executable (s4u-mc-bugged1-liveness-cleaner-on EXCLUDE_FROM_ALL s4u-mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp) - target_link_libraries(s4u-mc-bugged1-liveness-cleaner-on simgrid) - set_target_properties(s4u-mc-bugged1-liveness-cleaner-on PROPERTIES COMPILE_FLAGS "-DGARBAGE_STACK -fstack-cleaner") - add_dependencies(tests-mc s4u-mc-bugged1-liveness-cleaner-on) - - add_executable (s4u-mc-bugged1-liveness-cleaner-off EXCLUDE_FROM_ALL s4u-mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp) - target_link_libraries(s4u-mc-bugged1-liveness-cleaner-off simgrid) - set_target_properties(s4u-mc-bugged1-liveness-cleaner-off PROPERTIES COMPILE_FLAGS "-DGARBAGE_STACK -fno-stack-cleaner") - add_dependencies(tests-mc s4u-mc-bugged1-liveness-cleaner-off) - endif() - - ADD_TESH(s4u-mc-synchro-mutex-stateful - --setenv bindir=${CMAKE_CURRENT_BINARY_DIR}/synchro-mutex - --setenv libdir=${CMAKE_BINARY_DIR}/lib - --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms - --setenv srcdir=${CMAKE_CURRENT_SOURCE_DIR}/synchro-mutex - --cd ${CMAKE_CURRENT_SOURCE_DIR}/synchro-mutex - ${CMAKE_HOME_DIRECTORY}/examples/cpp/synchro-mutex/s4u-mc-synchro-mutex-stateful.tesh) - - # Model-checking liveness - if(HAVE_UCONTEXT_CONTEXTS AND SIMGRID_PROCESSOR_x86_64) - # liveness model-checking works only on 64bits (for now ...) - set(_mc-bugged1-liveness_factories "ucontext") - add_dependencies(tests-mc s4u-mc-bugged1-liveness) - set(_mc-bugged2-liveness_factories "ucontext") - - # This example never ends, disable it for now - set(_mc-bugged2-liveness_disable 1) - - if ("${CMAKE_SYSTEM}" MATCHES "Linux") - # timeout under FreeBSD (test never stops) - ADD_TESH(s4u-mc-bugged1-liveness-visited-ucontext --setenv bindir=${CMAKE_CURRENT_BINARY_DIR}/mc-bugged1-liveness - --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms - --cd ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness - ${CMAKE_HOME_DIRECTORY}/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh) - endif() - IF(HAVE_C_STACK_CLEANER) - add_dependencies(tests-mc s4u-mc-bugged1-liveness-stack-cleaner) - # This test checks if the stack cleaner is making a difference: - ADD_TEST(s4u-mc-bugged1-liveness-stack-cleaner ${CMAKE_HOME_DIRECTORY}/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner - ${CMAKE_HOME_DIRECTORY}/examples/cpp/mc-bugged1-liveness/ - ${CMAKE_CURRENT_BINARY_DIR}/mc-bugged1-liveness/) - ENDIF() - else() - set(_mc-bugged1-liveness_disable 1) - set(_mc-bugged2-liveness_disable 1) - endif() - - if(enable_coverage) - ADD_TEST(cover-mc-bugged1-liveness ${CMAKE_CURRENT_BINARY_DIR}/mc-bugged1-liveness/s4u-mc-bugged1-liveness ${CMAKE_HOME_DIRECTORY}/examples/platforms/small_platform.xml 1 1001) - endif() - -else() - foreach (example mc-bugged1-liveness mc-bugged2-liveness) - set(_${example}_disable 1) - endforeach() -endif() - # Hijack some regular tests to run them on top of the MC foreach (example synchro-barrier synchro-mutex synchro-semaphore) set(tesh_files ${tesh_files} ${CMAKE_CURRENT_SOURCE_DIR}/${example}/s4u-mc-${example}.tesh) @@ -157,7 +96,7 @@ foreach (example activityset-testany activityset-waitany activityset-waitall act actor-create actor-daemon actor-exiting actor-join actor-kill actor-lifetime actor-migrate actor-suspend actor-yield actor-stacksize app-bittorrent app-chainsend app-token-ring - battery-degradation battery-simple battery-energy + battery-chiller-solar battery-connector battery-degradation battery-simple battery-energy chiller-simple comm-pingpong comm-ready comm-suspend comm-wait comm-waituntil comm-dependent comm-host2host comm-failure comm-throttling @@ -169,7 +108,8 @@ foreach (example activityset-testany activityset-waitany activityset-waitall act exec-async exec-basic exec-dvfs exec-remote exec-waitfor exec-dependent exec-unassigned exec-ptask-multicore exec-ptask-multicore-latency exec-cpu-nonlinear exec-cpu-factors exec-failure exec-threads maestro-set - mc-bugged1 mc-bugged1-liveness mc-bugged2 mc-bugged2-liveness mc-centralized-mutex mc-electric-fence mc-failing-assert + mc-bugged1 mc-bugged2 mc-centralized-mutex mc-electric-fence mc-failing-assert + mess-wait network-ns3 network-ns3-wifi network-wifi io-async io-priority io-degradation io-file-system io-file-remote io-disk-raw io-dependent task-dispatch task-io task-microservice task-parallelism task-simple task-storm task-switch-host task-variable-load @@ -263,18 +203,6 @@ endforeach() # Test non-DPOR reductions on a given MC test foreach(example mc-failing-assert) -# State equality is not tested because it would take about 15 hours to run that test on my machine. -# We should first optimize mmalloc_heap_differ() which takes ~4sec for each pair to compare (maybe {175 x 174/ 2} pairs here) -# See the comment on mmalloc_heap_differ() in compare.cpp for more info on why it's hard to optimize. -# -# if(SIMGRID_HAVE_STATEFUL_MC) -# ADD_TESH(s4u-${example}-statequality --setenv bindir=${CMAKE_CURRENT_BINARY_DIR}/${example} -# --setenv libdir=${CMAKE_BINARY_DIR}/lib -# --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms -# --setenv srcdir=${CMAKE_CURRENT_SOURCE_DIR}/${example} -# --cd ${CMAKE_CURRENT_SOURCE_DIR}/${example} -# ${CMAKE_HOME_DIRECTORY}/examples/cpp/${example}/s4u-${example}-statequality.tesh) -# endif() if(SIMGRID_HAVE_MC) ADD_TESH(s4u-${example}-nodpor --setenv bindir=${CMAKE_CURRENT_BINARY_DIR}/${example} @@ -284,7 +212,6 @@ foreach(example mc-failing-assert) --cd ${CMAKE_CURRENT_SOURCE_DIR}/${example} ${CMAKE_HOME_DIRECTORY}/examples/cpp/${example}/s4u-${example}-nodpor.tesh) endif() - set(tesh_files ${tesh_files} ${CMAKE_HOME_DIRECTORY}/examples/cpp/${example}/s4u-${example}-statequality.tesh) set(tesh_files ${tesh_files} ${CMAKE_HOME_DIRECTORY}/examples/cpp/${example}/s4u-${example}-nodpor.tesh) endforeach() @@ -316,10 +243,8 @@ endif() # Add all extra files to the archive #################################### -set(examples_src ${examples_src} ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp PARENT_SCOPE) -set(tesh_files ${tesh_files} ${CMAKE_CURRENT_SOURCE_DIR}/comm-pingpong/debug-breakpoint.tesh - ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness/s4u-mc-bugged1-liveness.tesh - ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh PARENT_SCOPE) +set(examples_src ${examples_src} PARENT_SCOPE) +set(tesh_files ${tesh_files} ${CMAKE_CURRENT_SOURCE_DIR}/comm-pingpong/debug-breakpoint.tesh PARENT_SCOPE) set(xml_files ${xml_files} ${CMAKE_CURRENT_SOURCE_DIR}/actor-create/s4u-actor-create_d.xml ${CMAKE_CURRENT_SOURCE_DIR}/actor-lifetime/s4u-actor-lifetime_d.xml ${CMAKE_CURRENT_SOURCE_DIR}/app-bittorrent/s4u-app-bittorrent_d.xml @@ -340,10 +265,7 @@ set(xml_files ${xml_files} ${CMAKE_CURRENT_SOURCE_DIR}/actor-create/s4u-a ${CMAKE_CURRENT_SOURCE_DIR}/network-ns3/onelink_d.xml ${CMAKE_CURRENT_SOURCE_DIR}/network-ns3/one_cluster_d.xml PARENT_SCOPE) set(bin_files ${bin_files} ${CMAKE_CURRENT_SOURCE_DIR}/battery-degradation/plot_battery_degradation.py - ${CMAKE_CURRENT_SOURCE_DIR}/dht-kademlia/generate.py - ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner - ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged1-liveness/promela_bugged1_liveness - ${CMAKE_CURRENT_SOURCE_DIR}/mc-bugged2-liveness/promela_bugged2_liveness PARENT_SCOPE) + ${CMAKE_CURRENT_SOURCE_DIR}/dht-kademlia/generate.py PARENT_SCOPE) set(txt_files ${txt_files} ${CMAKE_CURRENT_SOURCE_DIR}/dag-from-dax/simple_dax_with_cycle.xml ${CMAKE_CURRENT_SOURCE_DIR}/dag-from-dax/smalldax.xml ${CMAKE_CURRENT_SOURCE_DIR}/dag-from-dax-simple/dag.xml diff --git a/examples/cpp/activityset-testany/s4u-activityset-testany.cpp b/examples/cpp/activityset-testany/s4u-activityset-testany.cpp index 8128c24755..d782094435 100644 --- a/examples/cpp/activityset-testany/s4u-activityset-testany.cpp +++ b/examples/cpp/activityset-testany/s4u-activityset-testany.cpp @@ -7,26 +7,26 @@ #include #include #include + namespace sg4 = simgrid::s4u; XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_testany, "Messages specific for this s4u example"); static void bob() { - sg4::Mailbox* mbox = sg4::Mailbox::by_name("mbox"); - const sg4::Disk* disk = sg4::Host::current()->get_disks().front(); + sg4::Mailbox* mbox = sg4::Mailbox::by_name("mbox"); + sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("mqueue"); + const sg4::Disk* disk = sg4::Host::current()->get_disks().front(); std::string* payload; + std::string* message; XBT_INFO("Create my asynchronous activities"); auto exec = sg4::this_actor::exec_async(5e9); auto comm = mbox->get_async(&payload); + auto mess = mqueue->get_async(&message); auto io = disk->read_async(3e8); - sg4::ActivitySet pending_activities; - pending_activities.push(exec); - pending_activities.push(comm); - pending_activities.push(io); - + sg4::ActivitySet pending_activities({exec, comm, mess, io}); XBT_INFO("Sleep_for a while"); sg4::this_actor::sleep_for(1); @@ -36,6 +36,8 @@ static void bob() if (completed_one != nullptr) { if (boost::dynamic_pointer_cast(completed_one)) XBT_INFO("Completed a Comm"); + if (boost::dynamic_pointer_cast(completed_one)) + XBT_INFO("Completed a Mess"); if (boost::dynamic_pointer_cast(completed_one)) XBT_INFO("Completed an Exec"); if (boost::dynamic_pointer_cast(completed_one)) @@ -47,6 +49,7 @@ static void bob() } XBT_INFO("Last activity is complete"); delete payload; + delete message; } static void alice() @@ -56,6 +59,14 @@ static void alice() sg4::Mailbox::by_name("mbox")->put(payload, 6e8); } +static void carl() +{ + sg4::this_actor::sleep_for(1.99); + auto* payload = new std::string("Control Message"); + XBT_INFO("Send '%s'", payload->c_str()); + sg4::MessageQueue::by_name("mqueue")->put(payload); +} + int main(int argc, char* argv[]) { sg4::Engine e(&argc, argv); @@ -64,6 +75,7 @@ int main(int argc, char* argv[]) sg4::Actor::create("bob", e.host_by_name("bob"), bob); sg4::Actor::create("alice", e.host_by_name("alice"), alice); + sg4::Actor::create("carl", e.host_by_name("carl"), carl); e.run(); diff --git a/examples/cpp/activityset-testany/s4u-activityset-testany.tesh b/examples/cpp/activityset-testany/s4u-activityset-testany.tesh index c590b36890..029e90b8cc 100644 --- a/examples/cpp/activityset-testany/s4u-activityset-testany.tesh +++ b/examples/cpp/activityset-testany/s4u-activityset-testany.tesh @@ -7,6 +7,8 @@ $ ${bindir:=.}/s4u-activityset-testany ${platfdir}/hosts_with_disks.xml "--log=r > [1.00] [ bob] Test for completed activities > [1.00] [ bob] Nothing matches, test again in 0.5s > [1.50] [ bob] Nothing matches, test again in 0.5s +> [1.99] [ carl] Send 'Control Message' +> [2.00] [ bob] Completed a Mess > [2.00] [ bob] Nothing matches, test again in 0.5s > [2.50] [ bob] Nothing matches, test again in 0.5s > [3.00] [ bob] Completed an I/O diff --git a/examples/cpp/activityset-waitall/s4u-activityset-waitall.cpp b/examples/cpp/activityset-waitall/s4u-activityset-waitall.cpp index efbc3a08ab..2c9cf1ad8b 100644 --- a/examples/cpp/activityset-waitall/s4u-activityset-waitall.cpp +++ b/examples/cpp/activityset-waitall/s4u-activityset-waitall.cpp @@ -9,28 +9,30 @@ #include namespace sg4 = simgrid::s4u; -XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waittany, "Messages specific for this s4u example"); +XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waitall, "Messages specific for this s4u example"); static void bob() { sg4::Mailbox* mbox = sg4::Mailbox::by_name("mbox"); + sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("mqueue"); const sg4::Disk* disk = sg4::Host::current()->get_disks().front(); std::string* payload; + std::string* message; XBT_INFO("Create my asynchronous activities"); auto exec = sg4::this_actor::exec_async(5e9); auto comm = mbox->get_async(&payload); auto io = disk->read_async(3e8); + auto mess = mqueue->get_async(&message); - sg4::ActivitySet pending_activities({boost::dynamic_pointer_cast(exec), - boost::dynamic_pointer_cast(comm), - boost::dynamic_pointer_cast(io)}); + sg4::ActivitySet pending_activities({exec, comm, io, mess}); XBT_INFO("Wait for asynchronous activities to complete, all in one shot."); pending_activities.wait_all(); XBT_INFO("All activities are completed."); delete payload; + delete message; } static void alice() @@ -40,6 +42,12 @@ static void alice() sg4::Mailbox::by_name("mbox")->put(payload, 6e8); } +static void carl() +{ + auto* payload = new std::string("Control Message"); + sg4::MessageQueue::by_name("mqueue")->put(payload); +} + int main(int argc, char* argv[]) { sg4::Engine e(&argc, argv); @@ -48,6 +56,7 @@ int main(int argc, char* argv[]) sg4::Actor::create("bob", e.host_by_name("bob"), bob); sg4::Actor::create("alice", e.host_by_name("alice"), alice); + sg4::Actor::create("carl", e.host_by_name("carl"), carl); e.run(); diff --git a/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.cpp b/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.cpp index 971d77441c..a322cc4f1b 100644 --- a/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.cpp +++ b/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.cpp @@ -9,20 +9,23 @@ #include namespace sg4 = simgrid::s4u; -XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waittany, "Messages specific for this s4u example"); +XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waitallfor, "Messages specific for this s4u example"); static void bob() { sg4::Mailbox* mbox = sg4::Mailbox::by_name("mbox"); + sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("mqueue"); const sg4::Disk* disk = sg4::Host::current()->get_disks().front(); std::string* payload; + std::string* message; XBT_INFO("Create my asynchronous activities"); auto exec = sg4::this_actor::exec_async(5e9); auto comm = mbox->get_async(&payload); auto io = disk->read_async(3e8); + auto mess = mqueue->get_async(&message); - sg4::ActivitySet pending_activities({exec, comm, io}); + sg4::ActivitySet pending_activities({exec, comm, io, mess}); XBT_INFO("Wait for asynchronous activities to complete"); while (not pending_activities.empty()) { @@ -34,6 +37,8 @@ static void bob() while (auto completed_one = pending_activities.test_any()) { if (boost::dynamic_pointer_cast(completed_one)) XBT_INFO("Completed a Comm"); + if (boost::dynamic_pointer_cast(completed_one)) + XBT_INFO("Completed a Mess"); if (boost::dynamic_pointer_cast(completed_one)) XBT_INFO("Completed an Exec"); if (boost::dynamic_pointer_cast(completed_one)) @@ -42,6 +47,7 @@ static void bob() } XBT_INFO("Last activity is complete"); delete payload; + delete message; } static void alice() @@ -51,6 +57,14 @@ static void alice() sg4::Mailbox::by_name("mbox")->put(payload, 6e8); } +static void carl() +{ + sg4::this_actor::sleep_for(1.99); + auto* payload = new std::string("Control Message"); + XBT_INFO("Send '%s'", payload->c_str()); + sg4::MessageQueue::by_name("mqueue")->put(payload); +} + int main(int argc, char* argv[]) { sg4::Engine e(&argc, argv); @@ -59,6 +73,7 @@ int main(int argc, char* argv[]) sg4::Actor::create("bob", e.host_by_name("bob"), bob); sg4::Actor::create("alice", e.host_by_name("alice"), alice); + sg4::Actor::create("carl", e.host_by_name("carl"), carl); e.run(); diff --git a/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.tesh b/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.tesh index 014c4f028e..ce8db4ac50 100644 --- a/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.tesh +++ b/examples/cpp/activityset-waitallfor/s4u-activityset-waitallfor.tesh @@ -5,7 +5,9 @@ $ ${bindir:=.}/s4u-activityset-waitallfor ${platfdir}/hosts_with_disks.xml "--lo > [0.000000] [ bob] Create my asynchronous activities > [0.000000] [ bob] Wait for asynchronous activities to complete > [1.000000] [ bob] Not all activities are terminated yet. +> [1.990000] [ carl] Send 'Control Message' > [2.000000] [ bob] Not all activities are terminated yet. +> [2.000000] [ bob] Completed a Mess > [3.000000] [ bob] Not all activities are terminated yet. > [3.000000] [ bob] Completed an I/O > [4.000000] [ bob] Not all activities are terminated yet. diff --git a/examples/cpp/activityset-waitany/s4u-activityset-waitany.cpp b/examples/cpp/activityset-waitany/s4u-activityset-waitany.cpp index 6f081b3ca6..6c8baef61e 100644 --- a/examples/cpp/activityset-waitany/s4u-activityset-waitany.cpp +++ b/examples/cpp/activityset-waitany/s4u-activityset-waitany.cpp @@ -9,22 +9,23 @@ #include namespace sg4 = simgrid::s4u; -XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waittany, "Messages specific for this s4u example"); +XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_activity_waitany, "Messages specific for this s4u example"); static void bob() { sg4::Mailbox* mbox = sg4::Mailbox::by_name("mbox"); + sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("mqueue"); const sg4::Disk* disk = sg4::Host::current()->get_disks().front(); std::string* payload; + std::string* message; XBT_INFO("Create my asynchronous activities"); auto exec = sg4::this_actor::exec_async(5e9); auto comm = mbox->get_async(&payload); auto io = disk->read_async(3e8); + auto mess = mqueue->get_async(&message); - sg4::ActivitySet pending_activities({boost::dynamic_pointer_cast(exec), - boost::dynamic_pointer_cast(comm), - boost::dynamic_pointer_cast(io)}); + sg4::ActivitySet pending_activities({exec, comm, io, mess}); XBT_INFO("Wait for asynchronous activities to complete"); while (not pending_activities.empty()) { @@ -32,6 +33,8 @@ static void bob() if (completed_one != nullptr) { if (boost::dynamic_pointer_cast(completed_one)) XBT_INFO("Completed a Comm"); + if (boost::dynamic_pointer_cast(completed_one)) + XBT_INFO("Completed a Mess"); if (boost::dynamic_pointer_cast(completed_one)) XBT_INFO("Completed an Exec"); if (boost::dynamic_pointer_cast(completed_one)) @@ -40,6 +43,7 @@ static void bob() } XBT_INFO("Last activity is complete"); delete payload; + delete message; } static void alice() @@ -49,6 +53,14 @@ static void alice() sg4::Mailbox::by_name("mbox")->put(payload, 6e8); } +static void carl() +{ + sg4::this_actor::sleep_for(2); + auto* payload = new std::string("Control Message"); + XBT_INFO("Send '%s'", payload->c_str()); + sg4::MessageQueue::by_name("mqueue")->put(payload); +} + int main(int argc, char* argv[]) { sg4::Engine e(&argc, argv); @@ -57,6 +69,7 @@ int main(int argc, char* argv[]) sg4::Actor::create("bob", e.host_by_name("bob"), bob); sg4::Actor::create("alice", e.host_by_name("alice"), alice); + sg4::Actor::create("carl", e.host_by_name("carl"), carl); e.run(); diff --git a/examples/cpp/activityset-waitany/s4u-activityset-waitany.tesh b/examples/cpp/activityset-waitany/s4u-activityset-waitany.tesh index b9ecf1eafa..e665de5b6c 100644 --- a/examples/cpp/activityset-waitany/s4u-activityset-waitany.tesh +++ b/examples/cpp/activityset-waitany/s4u-activityset-waitany.tesh @@ -4,6 +4,8 @@ $ ${bindir:=.}/s4u-activityset-waitany ${platfdir}/hosts_with_disks.xml "--log=r > [0.000000] [alice] Send 'Message' > [0.000000] [ bob] Create my asynchronous activities > [0.000000] [ bob] Wait for asynchronous activities to complete +> [2.000000] [ carl] Send 'Control Message' +> [2.000000] [ bob] Completed a Mess > [3.000000] [ bob] Completed an I/O > [5.000000] [ bob] Completed an Exec > [5.197828] [ bob] Completed a Comm diff --git a/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp new file mode 100644 index 0000000000..00fff065c0 --- /dev/null +++ b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.cpp @@ -0,0 +1,124 @@ +/* Copyright (c) 2017-2023. 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. */ + +/* This example combine the battery plugin, the chiller plugin and the solar + panel plugin. It illustrates how to use them together to evaluate the amount + of brown energy (from the electrical grid) and green energy (from the solar + panel) consumed by several machines. + + In this scenario we have two host placed in a room. + The room is maintained at 24°C by a chiller, powered by the electrical grid + and consumes brown energy. + The two hosts are powered by a battery when available, and the electrical + grid otherwise. The battery is charged by a solar panel. + + We simulate two days from 00h00 to 00h00. + The solar panel generates power from 8h to 20h with a peak at 14h. + During the simulation, when the charge of the battery goes: + - below 75% the solar panel is connected to the battery + - above 80% the solar panel is disconnected from the battery + - below 20% the hosts are disconnected from the battery + - above 25% the hosts are connected to the battery + + The two hosts are always idle, except from 12h to 16h on the first day. +*/ + +#include "simgrid/plugins/battery.hpp" +#include "simgrid/plugins/chiller.hpp" +#include "simgrid/plugins/energy.h" +#include "simgrid/plugins/solar_panel.hpp" +#include "simgrid/s4u.hpp" +#include + +XBT_LOG_NEW_DEFAULT_CATEGORY(battery_chiller_solar, "Messages specific for this s4u example"); +namespace sg4 = simgrid::s4u; +namespace sp = simgrid::plugins; + +static void irradiance_manager(sp::SolarPanelPtr solar_panel) +{ + int time = 0; + int time_step = 10; + double amplitude = 1000 / 2.0; + double period = 24 * 60 * 60; + double shift = 16 * 60 * 60; + double irradiance; + while (true) { + irradiance = amplitude * sin(2 * M_PI * (time + shift) / period); + irradiance = irradiance < 0 ? 0 : irradiance; + solar_panel->set_solar_irradiance(irradiance); + sg4::this_actor::sleep_for(time_step); + time += time_step; + } +} + +static void host_job_manager(double start, double duration) +{ + sg4::this_actor::sleep_until(start); + sg4::this_actor::get_host()->execute(duration * sg4::this_actor::get_host()->get_speed()); +} + +static void end_manager(sp::BatteryPtr b) +{ + sg4::this_actor::sleep_until(86400 * 2); + for (auto& handler : b->get_handlers()) + b->delete_handler(handler); +} + +int main(int argc, char* argv[]) +{ + sg4::Engine e(&argc, argv); + e.load_platform(argv[1]); + sg_host_energy_plugin_init(); + + auto myhost1 = e.host_by_name("MyHost1"); + auto myhost2 = e.host_by_name("MyHost2"); + + auto battery = sp::Battery::init("Battery", 0.2, -1e3, 1e3, 0.9, 0.9, 2000, 1000); + auto chiller = sp::Chiller::init("Chiller", 50, 1006, 0.2, 0.9, 24, 24, 1e3); + auto solar_panel = sp::SolarPanel::init("Solar Panel", 1.1, 0.9, 0, 0, 1e3); + chiller->add_host(myhost1); + chiller->add_host(myhost2); + solar_panel->on_this_power_change_cb( + [battery](sp::SolarPanel* s) { battery->set_load("Solar Panel", s->get_power() * -1); }); + + // These handlers connect/disconnect the solar panel and the hosts depending on the state of charge of the battery + battery->schedule_handler(0.8, sp::Battery::CHARGE, sp::Battery::Handler::PERSISTANT, + [battery]() { battery->set_load("Solar Panel", false); }); + battery->schedule_handler(0.75, sp::Battery::DISCHARGE, sp::Battery::Handler::PERSISTANT, + [battery]() { battery->set_load("Solar Panel", true); }); + battery->schedule_handler(0.2, sp::Battery::DISCHARGE, sp::Battery::Handler::PERSISTANT, + [battery, &myhost1, &myhost2]() { + battery->connect_host(myhost1, false); + battery->connect_host(myhost2, false); + }); + battery->schedule_handler(0.25, sp::Battery::CHARGE, sp::Battery::Handler::PERSISTANT, + [battery, &myhost1, &myhost2]() { + battery->connect_host(myhost1); + battery->connect_host(myhost2); + }); + + /* Handlers create simulation events preventing the simulation from finishing + To avoid this behaviour this actor sleeps for 2 days and then delete all handlers + */ + sg4::Actor::create("end_manager", myhost1, end_manager, battery); + + // This actor updates the solar irradiance of the solar panel + sg4::Actor::create("irradiance_manager", myhost1, irradiance_manager, solar_panel)->daemonize(); + + // These actors start a job on a host for a specific duration + sg4::Actor::create("host_job_manager", myhost1, host_job_manager, 12 * 60 * 60, 4 * 60 * 60); + sg4::Actor::create("host_job_manager", myhost2, host_job_manager, 12 * 60 * 60, 4 * 60 * 60); + + e.run(); + XBT_INFO("State of charge of the battery: %0.1f%%", battery->get_state_of_charge() * 100); + XBT_INFO( + "Energy consumed by the hosts (green / brown): %.2fMJ " + "/ %.2fMJ", + battery->get_energy_provided() / 1e6, + (sg_host_get_consumed_energy(myhost1) + sg_host_get_consumed_energy(myhost2) - battery->get_energy_provided()) / + 1e6); + XBT_INFO("Energy consumed by the chiller (brown): %.2fMJ", chiller->get_energy_consumed() / 1e6); + return 0; +} diff --git a/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh new file mode 100644 index 0000000000..f2cddf46e3 --- /dev/null +++ b/examples/cpp/battery-chiller-solar/s4u-battery-chiller-solar.tesh @@ -0,0 +1,10 @@ +#!/usr/bin/env tesh + +$ ${bindir:=.}/s4u-battery-chiller-solar ${platfdir}/energy_platform.xml +> [172800.000000] [host_energy/INFO] Total energy consumption: 53568000.000000 Joules (used hosts: 36288000.000000 Joules; unused/idle hosts: 17280000.000000) +> [172800.000000] [battery_chiller_solar/INFO] State of charge of the battery: 20.4% +> [172800.000000] [battery_chiller_solar/INFO] Energy consumed by the hosts (green / brown): 21.60MJ / 14.69MJ +> [172800.000000] [battery_chiller_solar/INFO] Energy consumed by the chiller (brown): 48.38MJ +> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost1: 17568000.000000 Joules +> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost2: 18720000.000000 Joules +> [172800.000000] [host_energy/INFO] Energy consumption of host MyHost3: 17280000.000000 Joules \ No newline at end of file diff --git a/examples/cpp/battery-connector/s4u-battery-connector.cpp b/examples/cpp/battery-connector/s4u-battery-connector.cpp new file mode 100644 index 0000000000..b3a8588b28 --- /dev/null +++ b/examples/cpp/battery-connector/s4u-battery-connector.cpp @@ -0,0 +1,65 @@ +/* Copyright (c) 2017-2023. 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. */ + +/* This example shows how to use the battery as a connector. + A connector has no capacity and only delivers as much power as it receives + with a transfer efficiency of 100%. + A solar panel is connected to the connector and power a host. +*/ + +#include "simgrid/plugins/battery.hpp" +#include "simgrid/plugins/chiller.hpp" +#include "simgrid/plugins/energy.h" +#include "simgrid/plugins/solar_panel.hpp" +#include "simgrid/s4u.hpp" +#include +#include +#include + +XBT_LOG_NEW_DEFAULT_CATEGORY(battery_chiller_solar, "Messages specific for this s4u example"); +namespace sg4 = simgrid::s4u; +namespace sp = simgrid::plugins; + +int main(int argc, char* argv[]) +{ + sg4::Engine e(&argc, argv); + e.load_platform(argv[1]); + sg_host_energy_plugin_init(); + + auto myhost1 = e.host_by_name("MyHost1"); + + auto connector = sp::Battery::init(); + auto solar_panel = sp::SolarPanel::init("Solar Panel", 1, 1, 200, 0, 1e3); + + connector->set_load("Solar Panel", solar_panel->get_power() * -1); + connector->connect_host(myhost1); + + solar_panel->on_this_power_change_cb([connector](sp::SolarPanel *s) { + connector->set_load("Solar Panel", s->get_power() * -1); + }); + + sg4::Actor::create("manager", myhost1, [&myhost1, & solar_panel, &connector]{ + XBT_INFO("Solar Panel power = %.2fW, MyHost1 power = %.2fW. The Solar Panel provides more than needed.", solar_panel->get_power(), sg_host_get_current_consumption(myhost1)); + simgrid::s4u::this_actor::sleep_for(100); + XBT_INFO("Energy consumption MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", sg_host_get_consumed_energy(myhost1) / 1e3, connector->get_energy_provided() / 1e3); + + solar_panel->set_solar_irradiance(100); + XBT_INFO("Solar Panel power = %.2fW, MyHost1 power = %.2fW. The Solar Panel provides exactly what is needed.", solar_panel->get_power(), sg_host_get_current_consumption(myhost1)); + double last_measure_host_energy = sg_host_get_consumed_energy(myhost1); + double last_measure_connector_energy = connector->get_energy_provided(); + + simgrid::s4u::this_actor::sleep_for(100); + XBT_INFO("Energy consumption MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", (sg_host_get_consumed_energy(myhost1) - last_measure_host_energy) / 1e3, (connector->get_energy_provided() - last_measure_connector_energy) / 1e3); + + XBT_INFO("MyHost1 executes something for 100s. The Solar Panel does not provide enough energy."); + last_measure_host_energy = sg_host_get_consumed_energy(myhost1); + last_measure_connector_energy = connector->get_energy_provided(); + myhost1->execute(100 * myhost1->get_speed()); + XBT_INFO("Energy MyHost1: %.2fkJ, Energy from the Solar Panel %.2fkJ", (sg_host_get_consumed_energy(myhost1) - last_measure_host_energy) / 1e3, (connector->get_energy_provided() - last_measure_connector_energy) / 1e3); + }); + + e.run(); + return 0; +} diff --git a/examples/cpp/battery-connector/s4u-battery-connector.tesh b/examples/cpp/battery-connector/s4u-battery-connector.tesh new file mode 100644 index 0000000000..2dd264da3f --- /dev/null +++ b/examples/cpp/battery-connector/s4u-battery-connector.tesh @@ -0,0 +1,13 @@ +#!/usr/bin/env tesh + +$ ${bindir:=.}/s4u-battery-connector ${platfdir}/energy_platform.xml +> [MyHost1:manager:(1) 0.000000] [battery_chiller_solar/INFO] Solar Panel power = 200.00W, MyHost1 power = 100.00W. The Solar Panel provides more than needed. +> [MyHost1:manager:(1) 100.000000] [battery_chiller_solar/INFO] Energy consumption MyHost1: 10.00kJ, Energy from the Solar Panel 10.00kJ +> [MyHost1:manager:(1) 100.000000] [battery_chiller_solar/INFO] Solar Panel power = 100.00W, MyHost1 power = 100.00W. The Solar Panel provides exactly what is needed. +> [MyHost1:manager:(1) 200.000000] [battery_chiller_solar/INFO] Energy consumption MyHost1: 10.00kJ, Energy from the Solar Panel 10.00kJ +> [MyHost1:manager:(1) 200.000000] [battery_chiller_solar/INFO] MyHost1 executes something for 100s. The Solar Panel does not provide enough energy. +> [MyHost1:manager:(1) 300.000000] [battery_chiller_solar/INFO] Energy MyHost1: 12.00kJ, Energy from the Solar Panel 10.00kJ +> [300.000000] [host_energy/INFO] Total energy consumption: 92000.000000 Joules (used hosts: 32000.000000 Joules; unused/idle hosts: 60000.000000) +> [300.000000] [host_energy/INFO] Energy consumption of host MyHost1: 32000.000000 Joules +> [300.000000] [host_energy/INFO] Energy consumption of host MyHost2: 30000.000000 Joules +> [300.000000] [host_energy/INFO] Energy consumption of host MyHost3: 30000.000000 Joules \ No newline at end of file diff --git a/examples/cpp/battery-degradation/s4u-battery-degradation.cpp b/examples/cpp/battery-degradation/s4u-battery-degradation.cpp index 9510404fa0..4973587089 100644 --- a/examples/cpp/battery-degradation/s4u-battery-degradation.cpp +++ b/examples/cpp/battery-degradation/s4u-battery-degradation.cpp @@ -10,39 +10,34 @@ XBT_LOG_NEW_DEFAULT_CATEGORY(battery_degradation, "Messages specific for this s4u example"); -static void manager() +int main(int argc, char* argv[]) { + simgrid::s4u::Engine e(&argc, argv); + e.load_platform(argv[1]); + auto battery = simgrid::plugins::Battery::init("Battery", 0.8, -200, 200, 0.9, 0.9, 10, 100); - battery->set_load("load", 100); + battery->set_load("load", 100.0); auto handler1 = battery->schedule_handler( - 0.2, simgrid::plugins::Battery::DISCHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, [battery]() { + 0.2, simgrid::plugins::Battery::DISCHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, [&battery]() { XBT_INFO("%f,%f,SoC", simgrid::s4u::Engine::get_clock(), battery->get_state_of_charge()); XBT_INFO("%f,%f,SoH", simgrid::s4u::Engine::get_clock(), battery->get_state_of_health()); - battery->set_load("load", -100); + battery->set_load("load", -100.0); }); std::shared_ptr handler2; handler2 = battery->schedule_handler( 0.8, simgrid::plugins::Battery::CHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, - [battery, handler1, handler2]() { + [&battery, &handler1, &handler2]() { XBT_INFO("%f,%f,SoC", simgrid::s4u::Engine::get_clock(), battery->get_state_of_charge()); XBT_INFO("%f,%f,SoH", simgrid::s4u::Engine::get_clock(), battery->get_state_of_health()); if (battery->get_state_of_health() < 0.1) { battery->delete_handler(handler1); battery->delete_handler(handler2); } - battery->set_load("load", 100); + battery->set_load("load", 100.0); }); -} - -int main(int argc, char* argv[]) -{ - simgrid::s4u::Engine e(&argc, argv); - e.load_platform(argv[1]); - - simgrid::s4u::Actor::create("manager", e.host_by_name("MyHost1"), manager); e.run(); return 0; diff --git a/examples/cpp/battery-energy/s4u-battery-energy.cpp b/examples/cpp/battery-energy/s4u-battery-energy.cpp index c50ef02cae..6db88125a4 100644 --- a/examples/cpp/battery-energy/s4u-battery-energy.cpp +++ b/examples/cpp/battery-energy/s4u-battery-energy.cpp @@ -21,7 +21,7 @@ static void manager() battery->schedule_handler( 0.2, simgrid::plugins::Battery::DISCHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, - [battery, &host1, &host2, &host3]() { + [&battery, &host1, &host2, &host3]() { XBT_INFO("Handler -> Battery low: SoC: %f SoH: %f Energy stored: %fJ Energy provided: %fJ Energy consumed %fJ", battery->get_state_of_charge(), battery->get_state_of_health(), battery->get_energy_stored(), battery->get_energy_provided(), battery->get_energy_consumed()); diff --git a/examples/cpp/battery-simple/s4u-battery-simple.cpp b/examples/cpp/battery-simple/s4u-battery-simple.cpp index 04eb4f6d13..61a4186239 100644 --- a/examples/cpp/battery-simple/s4u-battery-simple.cpp +++ b/examples/cpp/battery-simple/s4u-battery-simple.cpp @@ -28,7 +28,7 @@ int main(int argc, char* argv[]) XBT_INFO("Set load to %fW", load_w); battery->schedule_handler( - 0.2, simgrid::plugins::Battery::DISCHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, [battery, &load_w]() { + 0.2, simgrid::plugins::Battery::DISCHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, [&battery, &load_w]() { XBT_INFO("Discharged state: SoC: %f SoH: %f Energy stored: %fJ Energy provided: %fJ Energy consumed %fJ", battery->get_state_of_charge(), battery->get_state_of_health(), battery->get_energy_stored(), battery->get_energy_provided(), battery->get_energy_consumed()); @@ -37,7 +37,7 @@ int main(int argc, char* argv[]) }); battery->schedule_handler( - 0.8, simgrid::plugins::Battery::CHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, [battery]() { + 0.8, simgrid::plugins::Battery::CHARGE, simgrid::plugins::Battery::Handler::PERSISTANT, [&battery]() { XBT_INFO("Charged state: SoC: %f SoH: %f Energy stored: %fJ Energy provided: %fJ Energy consumed %fJ", battery->get_state_of_charge(), battery->get_state_of_health(), battery->get_energy_stored(), battery->get_energy_provided(), battery->get_energy_consumed()); @@ -45,5 +45,6 @@ int main(int argc, char* argv[]) }); e.run(); + return 0; } \ No newline at end of file diff --git a/examples/cpp/chiller-simple/s4u-chiller-simple.cpp b/examples/cpp/chiller-simple/s4u-chiller-simple.cpp index c5a45b3d16..db48b653e7 100644 --- a/examples/cpp/chiller-simple/s4u-chiller-simple.cpp +++ b/examples/cpp/chiller-simple/s4u-chiller-simple.cpp @@ -6,59 +6,44 @@ #include "simgrid/plugins/chiller.hpp" #include "simgrid/plugins/energy.h" #include "simgrid/s4u.hpp" -#include XBT_LOG_NEW_DEFAULT_CATEGORY(chiller_simple, "Messages specific for this s4u example"); namespace sg4 = simgrid::s4u; -static void manager(simgrid::plugins::ChillerPtr c) +static void display_chiller(simgrid::plugins::ChillerPtr c) { - XBT_INFO("Initial state: "); - XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(), - c->get_energy_consumed()); - - XBT_INFO("The machines slowly heat up the room."); - simgrid::s4u::this_actor::sleep_until(400); - XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(), - c->get_energy_consumed()); - simgrid::s4u::this_actor::sleep_until(800); - XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(), - c->get_energy_consumed()); - simgrid::s4u::this_actor::sleep_until(1000); - XBT_INFO("The Chiller now compensates the heat generated by the machines."); - XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(), - c->get_energy_consumed()); - simgrid::s4u::this_actor::sleep_until(1200); - XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(), + XBT_INFO("%s: Power: %.2fW T_in: %.2f°C Energy consumed: %.2fJ", c->get_cname(), c->get_power(), c->get_temp_in(), c->get_energy_consumed()); +} - XBT_INFO("Let's compute something."); - sg4::this_actor::exec_async(1e10); - simgrid::s4u::this_actor::sleep_until(1250); - XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(), - c->get_energy_consumed()); +static void manager(simgrid::plugins::ChillerPtr c) +{ + display_chiller(c); - simgrid::s4u::this_actor::sleep_until(1300); - XBT_INFO("Computation done."); + simgrid::s4u::this_actor::sleep_for(c->get_time_to_goal_temp()); + XBT_INFO("The input temperature is now equal to the goal temperature. After this point the Chiller will compensate " + "heat with electrical power."); + display_chiller(c); - simgrid::s4u::this_actor::sleep_until(1400); - XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(), - c->get_energy_consumed()); + simgrid::s4u::this_actor::sleep_for(1); + display_chiller(c); + XBT_INFO("Let's compute something."); + sg4::this_actor::execute(1e10); + XBT_INFO("Computation done."); + display_chiller(c); XBT_INFO("Now let's stress the chiller by decreasing the goal temperature to 23°C."); c->set_goal_temp(23); - simgrid::s4u::this_actor::sleep_until(1600); - XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(), - c->get_energy_consumed()); - simgrid::s4u::this_actor::sleep_until(1800); - XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(), - c->get_energy_consumed()); - simgrid::s4u::this_actor::sleep_until(2000); - XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(), - c->get_energy_consumed()); - simgrid::s4u::this_actor::sleep_until(2200); - XBT_INFO("%s: Power: %fW T_in: %f°C Energy consumed: %fJ", c->get_cname(), c->get_power(), c->get_temp_in(), - c->get_energy_consumed()); + + simgrid::s4u::this_actor::sleep_for(1); + display_chiller(c); + + simgrid::s4u::this_actor::sleep_for(c->get_time_to_goal_temp()); + XBT_INFO("The input temperature is back to the goal temperature."); + display_chiller(c); + + simgrid::s4u::this_actor::sleep_for(1); + display_chiller(c); } int main(int argc, char* argv[]) @@ -71,7 +56,7 @@ int main(int argc, char* argv[]) chiller->add_host(e.host_by_name("MyHost1")); chiller->add_host(e.host_by_name("MyHost2")); chiller->add_host(e.host_by_name("MyHost3")); - sg4::Actor::create("sender", e.host_by_name("MyHost1"), manager, chiller); + sg4::Actor::create("manager", e.host_by_name("MyHost1"), manager, chiller); e.run(); return 0; diff --git a/examples/cpp/chiller-simple/s4u-chiller-simple.tesh b/examples/cpp/chiller-simple/s4u-chiller-simple.tesh index c1d4c27f46..33e196f9b1 100644 --- a/examples/cpp/chiller-simple/s4u-chiller-simple.tesh +++ b/examples/cpp/chiller-simple/s4u-chiller-simple.tesh @@ -1,24 +1,19 @@ #!/usr/bin/env tesh $ ${bindir:=.}/s4u-chiller-simple ${platfdir}/energy_platform.xml -> [MyHost1:sender:(1) 0.000000] [chiller_simple/INFO] Initial state: -> [MyHost1:sender:(1) 0.000000] [chiller_simple/INFO] Chiller: Power: 0.000000W T_in: 23.000000°C Energy consumed: 0.000000J -> [MyHost1:sender:(1) 0.000000] [chiller_simple/INFO] The machines slowly heat up the room. -> [MyHost1:sender:(1) 400.000000] [chiller_simple/INFO] Chiller: Power: 0.000000W T_in: 23.486875°C Energy consumed: 0.000000J -> [MyHost1:sender:(1) 800.000000] [chiller_simple/INFO] Chiller: Power: 0.000000W T_in: 23.973749°C Energy consumed: 0.000000J -> [MyHost1:sender:(1) 1000.000000] [chiller_simple/INFO] The Chiller now compensates the heat generated by the machines. -> [MyHost1:sender:(1) 1000.000000] [chiller_simple/INFO] Chiller: Power: 356.866667W T_in: 24.000000°C Energy consumed: 71373.333333J -> [MyHost1:sender:(1) 1200.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 151373.333333J -> [MyHost1:sender:(1) 1200.000000] [chiller_simple/INFO] Let's compute something. -> [MyHost1:sender:(1) 1250.000000] [chiller_simple/INFO] Chiller: Power: 426.666667W T_in: 24.000000°C Energy consumed: 172706.666667J -> [MyHost1:sender:(1) 1300.000000] [chiller_simple/INFO] Computation done. -> [MyHost1:sender:(1) 1400.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 24.000000°C Energy consumed: 234040.000000J -> [MyHost1:sender:(1) 1400.000000] [chiller_simple/INFO] Now let's stress the chiller by decreasing the goal temperature to 23°C. -> [MyHost1:sender:(1) 1600.000000] [chiller_simple/INFO] Chiller: Power: 1000.000000W T_in: 23.634844°C Energy consumed: 434040.000000J -> [MyHost1:sender:(1) 1800.000000] [chiller_simple/INFO] Chiller: Power: 1000.000000W T_in: 23.269688°C Energy consumed: 634040.000000J -> [MyHost1:sender:(1) 2000.000000] [chiller_simple/INFO] Chiller: Power: 843.133333W T_in: 23.000000°C Energy consumed: 802666.666667J -> [MyHost1:sender:(1) 2200.000000] [chiller_simple/INFO] Chiller: Power: 400.000000W T_in: 23.000000°C Energy consumed: 882666.666667J -> [2200.000000] [host_energy/INFO] Total energy consumption: 662000.000000 Joules (used hosts: 222000.000000 Joules; unused/idle hosts: 440000.000000) -> [2200.000000] [host_energy/INFO] Energy consumption of host MyHost1: 222000.000000 Joules -> [2200.000000] [host_energy/INFO] Energy consumption of host MyHost2: 220000.000000 Joules -> [2200.000000] [host_energy/INFO] Energy consumption of host MyHost3: 220000.000000 Joules +> [MyHost1:manager:(1) 0.000000] [chiller_simple/INFO] Chiller: Power: 0.00W T_in: 23.00°C Energy consumed: 0.00J +> [MyHost1:manager:(1) 821.566667] [chiller_simple/INFO] The input temperature is now equal to the goal temperature. After this point the Chiller will compensate heat with electrical power. +> [MyHost1:manager:(1) 821.566667] [chiller_simple/INFO] Chiller: Power: 0.00W T_in: 24.00°C Energy consumed: 0.00J +> [MyHost1:manager:(1) 822.566667] [chiller_simple/INFO] Chiller: Power: 400.00W T_in: 24.00°C Energy consumed: 400.00J +> [MyHost1:manager:(1) 822.566667] [chiller_simple/INFO] Let's compute something. +> [MyHost1:manager:(1) 922.566667] [chiller_simple/INFO] Computation done. +> [MyHost1:manager:(1) 922.566667] [chiller_simple/INFO] Chiller: Power: 426.67W T_in: 24.00°C Energy consumed: 43066.67J +> [MyHost1:manager:(1) 922.566667] [chiller_simple/INFO] Now let's stress the chiller by decreasing the goal temperature to 23°C. +> [MyHost1:manager:(1) 923.566667] [chiller_simple/INFO] Chiller: Power: 1000.00W T_in: 24.00°C Energy consumed: 44066.67J +> [MyHost1:manager:(1) 1470.277778] [chiller_simple/INFO] The input temperature is back to the goal temperature. +> [MyHost1:manager:(1) 1470.277778] [chiller_simple/INFO] Chiller: Power: 1000.00W T_in: 23.00°C Energy consumed: 590777.78J +> [MyHost1:manager:(1) 1471.277778] [chiller_simple/INFO] Chiller: Power: 400.00W T_in: 23.00°C Energy consumed: 591177.78J +> [1471.277778] [host_energy/INFO] Total energy consumption: 443383.333333 Joules (used hosts: 149127.777778 Joules; unused/idle hosts: 294255.555556) +> [1471.277778] [host_energy/INFO] Energy consumption of host MyHost1: 149127.777778 Joules +> [1471.277778] [host_energy/INFO] Energy consumption of host MyHost2: 147127.777778 Joules +> [1471.277778] [host_energy/INFO] Energy consumption of host MyHost3: 147127.777778 Joules \ No newline at end of file diff --git a/examples/cpp/io-dependent/s4u-io-dependent.cpp b/examples/cpp/io-dependent/s4u-io-dependent.cpp index 4772376fa3..f64c4c2e46 100644 --- a/examples/cpp/io-dependent/s4u-io-dependent.cpp +++ b/examples/cpp/io-dependent/s4u-io-dependent.cpp @@ -17,10 +17,7 @@ static void test() sg4::IoPtr carl_read = sg4::Host::by_name("carl")->get_disks().front()->io_init(4000000, sg4::Io::OpType::READ); sg4::ExecPtr carl_compute = sg4::Host::by_name("carl")->exec_init(1e9); - sg4::ActivitySet pending_activities ({boost::dynamic_pointer_cast(bob_compute), - boost::dynamic_pointer_cast(bob_write), - boost::dynamic_pointer_cast(carl_read), - boost::dynamic_pointer_cast(carl_compute)}); + sg4::ActivitySet pending_activities ({bob_compute, bob_write, carl_read, carl_compute}); // Name the activities (for logging purposes only) bob_compute->set_name("bob compute"); diff --git a/examples/cpp/mc-bugged1-liveness/promela_bugged1_liveness b/examples/cpp/mc-bugged1-liveness/promela_bugged1_liveness deleted file mode 100644 index 96b491d6af..0000000000 --- a/examples/cpp/mc-bugged1-liveness/promela_bugged1_liveness +++ /dev/null @@ -1,11 +0,0 @@ -never { /* !G(r->Fcs) */ -T0_init : /* init */ - if - :: (1) -> goto T0_init - :: (!cs && r) -> goto accept_S2 - fi; -accept_S2 : /* 1 */ - if - :: (!cs) -> goto accept_S2 - fi; -} diff --git a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner b/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner deleted file mode 100755 index 0552ca2898..0000000000 --- a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-stack-cleaner +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env sh -# Run the same test compiled with -fstack-cleaner / f-no-stack-cleaner -# and compare the output. - -srcdir="$1" -bindir="$2" - -cd "$srcdir" - -die() { - echo "$@" >&2 - exit 1 -} - -assert() { - if ! eval "$1"; then - die "Assertion failed: $*" - fi -} - -# If we don't have timeout, fake it: -if ! which timeout > /dev/null; then - timeout() { - shift - "$@" - } -fi - -run() { - state=$1 - shift - timeout 30s ${bindir:=.}/bugged1_liveness_cleaner_$state \ - ${srcdir:=.}/../../platforms/platform.xml \ - ${srcdir:=.}/deploy_bugged1_liveness.xml \ - "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" \ - --cfg=contexts/factory:ucontext \ - --cfg=contexts/stack-size:256 - assert 'test $? = 134' -} - -get_states() { - echo "$1" | grep "Expanded pairs = " | sed "s/^.*Expanded pairs = //" | head -n1 -} - -RES_ON="$(run on 2>&1 1>/dev/null)" -RES_OFF="$(run off 2>&1 1>/dev/null)" - -STATES_ON=$(get_states "$RES_ON") -STATES_OFF=$(get_states "$RES_OFF") - -# Both runs finished: -assert 'test -n "$STATES_ON"' -assert 'test -n "$STATES_OFF"' - -# We expect 21 visited pairs with the stack cleaner: -assert 'test "$STATES_ON" = 21' - -# We expect more states without the stack cleaner: -assert 'test "$STATES_ON" -lt "$STATES_OFF"' diff --git a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh b/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh deleted file mode 100644 index e956f9cd91..0000000000 --- a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness-visited.tesh +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env tesh - -! expect return 2 -! timeout 30 -! output display -$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/s4u-mc-bugged1-liveness ${platfdir:=.}/small_platform.xml 1 --log=xbt_cfg.thresh:warning "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=model-check/visited:100 --cfg=contexts/stack-size:256 --cfg=model-check/property:promela_bugged1_liveness -> [ 0.000000] (0:maestro@) Check the liveness property promela_bugged1_liveness -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (3:client@Fafard) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. resource now idle -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. resource now idle -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. resource now idle -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. resource now idle -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (1:coordinator@Tremblay) CS already used. Queue the request. -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. Grant to queued requests (queue size: 1) -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. resource now idle -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (1:coordinator@Tremblay) CS already used. Queue the request. -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. Grant to queued requests (queue size: 1) -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. resource now idle -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (1:coordinator@Tremblay) CS already used. Queue the request. -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. Grant to queued requests (queue size: 1) -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. resource now idle -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (1:coordinator@Tremblay) CS already used. Queue the request. -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. Grant to queued requests (queue size: 1) -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (3:client@Fafard) Propositions changed : r=1, cs=0 -> [ 0.000000] (1:coordinator@Tremblay) CS release. Grant to queued requests (queue size: 1) -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (2:client@Boivin) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (0:maestro@) Pair 58 already reached (equal to pair 46) ! -> [ 0.000000] (0:maestro@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* -> [ 0.000000] (0:maestro@) | ACCEPTANCE CYCLE | -> [ 0.000000] (0:maestro@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* -> [ 0.000000] (0:maestro@) Counter-example that violates formula : -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iRecv(dst=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iRecv(dst=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(3)Fafard (client)] iSend(src=(3)Fafard (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iRecv(dst=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(3)Fafard (client)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iRecv(dst=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (2)Boivin (client)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) Expanded pairs = 58 -> [ 0.000000] (0:maestro@) Visited pairs = 202 -> [ 0.000000] (0:maestro@) Executed transitions = 208 -> [ 0.000000] (0:maestro@) Counter-example depth : 51 diff --git a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp b/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp deleted file mode 100644 index ad4d30a52f..0000000000 --- a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* Copyright (c) 2012-2023. 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. */ - -/***************** Centralized Mutual Exclusion Algorithm *******************/ -/* This example implements a centralized mutual exclusion algorithm. */ -/* Bug : CS requests of client 1 not satisfied */ -/* LTL property checked : G(r->F(cs)); (r=request of CS, cs=CS ok) */ -/****************************************************************************/ - -#ifdef GARBAGE_STACK -#include -#include -#include -#endif - -#include -#include -#include - -XBT_LOG_NEW_DEFAULT_CATEGORY(bugged1_liveness, "my log messages"); -namespace sg4 = simgrid::s4u; - -class Message { -public: - enum class Kind { GRANT, REQUEST, RELEASE }; - Kind kind = Kind::GRANT; - sg4::Mailbox* return_mailbox = nullptr; - explicit Message(Message::Kind kind, sg4::Mailbox* mbox) : kind(kind), return_mailbox(mbox) {} -}; - -int r = 0; -int cs = 0; - -#ifdef GARBAGE_STACK -/** Do not use a clean stack */ -static void garbage_stack(void) -{ - const size_t size = 256; - int fd = open("/dev/urandom", O_RDONLY); - char foo[size]; - read(fd, foo, size); - close(fd); -} -#endif - -static void coordinator() -{ - bool CS_used = false; - std::queue requests; - - sg4::Mailbox* mbox = sg4::Mailbox::by_name("coordinator"); - - while (true) { - auto m = mbox->get_unique(); - if (m->kind == Message::Kind::REQUEST) { - if (CS_used) { - XBT_INFO("CS already used. Queue the request."); - requests.push(m->return_mailbox); - } else { - if (m->return_mailbox->get_name() != "1") { - XBT_INFO("CS idle. Grant immediately"); - m->return_mailbox->put(new Message(Message::Kind::GRANT, mbox), 1000); - CS_used = true; - } - } - } else { - if (not requests.empty()) { - XBT_INFO("CS release. Grant to queued requests (queue size: %zu)", requests.size()); - sg4::Mailbox* req = requests.front(); - requests.pop(); - if (req->get_name() != "1") { - req->put(new Message(Message::Kind::GRANT, mbox), 1000); - } else { - requests.push(req); - CS_used = false; - } - } else { - XBT_INFO("CS release. resource now idle"); - CS_used = false; - } - } - } -} - -static void client(int id) -{ - aid_t my_pid = sg4::this_actor::get_pid(); - - sg4::Mailbox* my_mailbox = sg4::Mailbox::by_name(std::to_string(id)); - - while (true) { - XBT_INFO("Ask the request"); - sg4::Mailbox::by_name("coordinator")->put(new Message(Message::Kind::REQUEST, my_mailbox), 1000); - - if (id == 1) { - r = 1; - cs = 0; - XBT_INFO("Propositions changed : r=1, cs=0"); - } - - auto grant = my_mailbox->get_unique(); - xbt_assert(grant->kind == Message::Kind::GRANT); - - if (id == 1) { - cs = 1; - r = 0; - XBT_INFO("Propositions changed : r=0, cs=1"); - } - - XBT_INFO("%d got the answer. Sleep a bit and release it", id); - - sg4::this_actor::sleep_for(1); - - sg4::Mailbox::by_name("coordinator")->put(new Message(Message::Kind::RELEASE, my_mailbox), 1000); - - sg4::this_actor::sleep_for(static_cast(my_pid)); - - if (id == 1) { - cs = 0; - r = 0; - XBT_INFO("Propositions changed : r=0, cs=0"); - } - } -} - -static void raw_client(int id) -{ -#ifdef GARBAGE_STACK - // At this point the stack of the callee (client) is probably filled with - // zeros and uninitialized variables will contain 0. This call will place - // random byes in the stack of the callee: - garbage_stack(); -#endif - client(id); -} - -int main(int argc, char* argv[]) -{ - sg4::Engine e(&argc, argv); - - MC_automaton_new_propositional_symbol_pointer("r", &r); - MC_automaton_new_propositional_symbol_pointer("cs", &cs); - - e.load_platform(argv[1]); - - sg4::Actor::create("coordinator", e.host_by_name("Tremblay"), coordinator) - ->set_kill_time(argc > 3 ? std::stod(argv[3]) : -1.0); - if (std::stod(argv[2]) == 0) { - sg4::Actor::create("client", e.host_by_name("Boivin"), raw_client, 1); - sg4::Actor::create("client", e.host_by_name("Fafard"), raw_client, 2); - } else { // "Visited" case - sg4::Actor::create("client", e.host_by_name("Boivin"), raw_client, 2); - sg4::Actor::create("client", e.host_by_name("Fafard"), raw_client, 1); - } - e.run(); - - return 0; -} diff --git a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.tesh b/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.tesh deleted file mode 100644 index 5f0999cec4..0000000000 --- a/examples/cpp/mc-bugged1-liveness/s4u-mc-bugged1-liveness.tesh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env tesh - -! expect return 2 -! timeout 20 -! output display -$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/s4u-mc-bugged1-liveness ${platfdir:=.}/small_platform.xml 0 --log=xbt_cfg.thresh:warning "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=contexts/stack-size:256 --cfg=model-check/property:promela_bugged1_liveness -> [ 0.000000] (0:maestro@) Check the liveness property promela_bugged1_liveness -> [ 0.000000] (2:client@Boivin) Ask the request -> [ 0.000000] (3:client@Fafard) Ask the request -> [ 0.000000] (2:client@Boivin) Propositions changed : r=1, cs=0 -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (3:client@Fafard) 2 got the answer. Sleep a bit and release it -> [ 0.000000] (1:coordinator@Tremblay) CS release. resource now idle -> [ 0.000000] (3:client@Fafard) Ask the request -> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediately -> [ 0.000000] (0:maestro@) Pair 22 already reached (equal to pair 10) ! -> [ 0.000000] (0:maestro@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* -> [ 0.000000] (0:maestro@) | ACCEPTANCE CYCLE | -> [ 0.000000] (0:maestro@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* -> [ 0.000000] (0:maestro@) Counter-example that violates formula : -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iSend(src=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] Wait(comm=(verbose only) [(2)Boivin (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(2)Boivin (client)] iRecv(dst=(2)Boivin (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(3)Fafard (client)] iSend(src=(3)Fafard (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(3)Fafard (client)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(3)Fafard (client)] iRecv(dst=(3)Fafard (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (3)Fafard (client)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(3)Fafard (client)] Wait(comm=(verbose only) [(1)Tremblay (coordinator)-> (3)Fafard (client)]) -> [ 0.000000] (0:maestro@) [(3)Fafard (client)] iSend(src=(3)Fafard (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] iRecv(dst=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(3)Fafard (client)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) [(3)Fafard (client)] iSend(src=(3)Fafard (client), buff=(verbose only), size=(verbose only)) -> [ 0.000000] (0:maestro@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)]) -> [ 0.000000] (0:maestro@) Expanded pairs = 22 -> [ 0.000000] (0:maestro@) Visited pairs = 20 -> [ 0.000000] (0:maestro@) Executed transitions = 20 -> [ 0.000000] (0:maestro@) Counter-example depth : 21 diff --git a/examples/cpp/mc-bugged2-liveness/promela_bugged2_liveness b/examples/cpp/mc-bugged2-liveness/promela_bugged2_liveness deleted file mode 100644 index 5361f88099..0000000000 --- a/examples/cpp/mc-bugged2-liveness/promela_bugged2_liveness +++ /dev/null @@ -1,12 +0,0 @@ -never { /* !(!(GFcs)) */ -T0_init : /* init */ - if - :: (cs) -> goto accept_S1 - :: (1) -> goto T0_init - fi; -accept_S1 : /* 1 */ - if - :: (cs) -> goto accept_S1 - :: (1) -> goto T0_init - fi; -} diff --git a/examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.cpp b/examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.cpp deleted file mode 100644 index fcc6878548..0000000000 --- a/examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (c) 2012-2023. 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. */ - -/***************************** Bugged2 ****************************************/ -/* This example implements a centralized mutual exclusion algorithm. */ -/* One client stay always in critical section */ -/* LTL property checked : !(GFcs) */ -/******************************************************************************/ - -#include -#include - -XBT_LOG_NEW_DEFAULT_CATEGORY(bugged2_liveness, "my log messages"); -namespace sg4 = simgrid::s4u; - -class Message { -public: - enum class Kind { GRANT, NOT_GRANT, REQUEST }; - Kind kind = Kind::GRANT; - sg4::Mailbox* return_mailbox = nullptr; - explicit Message(Message::Kind kind, sg4::Mailbox* mbox) : kind(kind), return_mailbox(mbox) {} -}; - -int cs = 0; - -static void coordinator() -{ - bool CS_used = false; // initially the CS is idle - std::queue requests; - - sg4::Mailbox* mbox = sg4::Mailbox::by_name("coordinator"); - - while (true) { - auto m = mbox->get_unique(); - if (m->kind == Message::Kind::REQUEST) { - if (CS_used) { - XBT_INFO("CS already used."); - m->return_mailbox->put(new Message(Message::Kind::NOT_GRANT, mbox), 1000); - } else { // can serve it immediately - XBT_INFO("CS idle. Grant immediately"); - m->return_mailbox->put(new Message(Message::Kind::GRANT, mbox), 1000); - CS_used = true; - } - } else { // that's a release. Check if someone was waiting for the lock - XBT_INFO("CS release. resource now idle"); - CS_used = false; - } - } -} - -static void client(int id) -{ - aid_t my_pid = sg4::this_actor::get_pid(); - - sg4::Mailbox* my_mailbox = sg4::Mailbox::by_name(std::to_string(id)); - - while (true) { - XBT_INFO("Client (%d) asks the request", id); - sg4::Mailbox::by_name("coordinator")->put(new Message(Message::Kind::REQUEST, my_mailbox), 1000); - - auto grant = my_mailbox->get_unique(); - - if (grant->kind == Message::Kind::GRANT) { - XBT_INFO("Client (%d) got the answer (grant). Sleep a bit and release it", id); - if (id == 1) - cs = 1; - } else { - XBT_INFO("Client (%d) got the answer (not grant). Try again", id); - } - - sg4::this_actor::sleep_for(my_pid); - } -} - -int main(int argc, char* argv[]) -{ - sg4::Engine e(&argc, argv); - - MC_automaton_new_propositional_symbol_pointer("cs", &cs); - - e.load_platform(argv[1]); - - sg4::Actor::create("coordinator", e.host_by_name("Tremblay"), coordinator); - sg4::Actor::create("client", e.host_by_name("Fafard"), client, 1); - sg4::Actor::create("client", e.host_by_name("Boivin"), client, 2); - - e.run(); - - return 0; -} diff --git a/examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.tesh b/examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.tesh deleted file mode 100644 index 28329f62da..0000000000 --- a/examples/cpp/mc-bugged2-liveness/s4u-mc-bugged2-liveness.tesh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env tesh - -! expect return 2 -! timeout 20 -! output ignore -$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/s4u-mc-bugged2-liveness ${platfdir:=.}/small_platform.xml --log=xbt_cfg.thresh:warning "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=contexts/stack-size:256 --cfg=model-check/property:promela_bugged2_liveness diff --git a/examples/cpp/mc-failing-assert/s4u-mc-failing-assert-statequality.tesh b/examples/cpp/mc-failing-assert/s4u-mc-failing-assert-statequality.tesh deleted file mode 100644 index cb545840d9..0000000000 --- a/examples/cpp/mc-failing-assert/s4u-mc-failing-assert-statequality.tesh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env tesh - -! expect return 1 -! timeout 300 -$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/visited:10000 -- ${bindir:=.}/s4u-mc-failing-assert ${platfdir}/small_platform.xml --log=root.thresh:critical -> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/visited' to '20' -> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor. -> [0.000000] [mc_ModelChecker/INFO] ************************** -> [0.000000] [mc_ModelChecker/INFO] *** PROPERTY NOT VALID *** -> [0.000000] [mc_ModelChecker/INFO] ************************** -> [0.000000] [mc_ModelChecker/INFO] Counter-example execution trace: -> [0.000000] [mc_ModelChecker/INFO] 1: iRecv(mbox=0) -> [0.000000] [mc_ModelChecker/INFO] 3: iSend(mbox=0) -> [0.000000] [mc_ModelChecker/INFO] 1: WaitComm(from 3 to 1, mbox=0, no timeout) -> [0.000000] [mc_ModelChecker/INFO] 1: iRecv(mbox=0) -> [0.000000] [mc_ModelChecker/INFO] 2: iSend(mbox=0) -> [0.000000] [mc_ModelChecker/INFO] 1: WaitComm(from 2 to 1, mbox=0, no timeout) -> [0.000000] [mc_ModelChecker/INFO] Path = 1;3;1;1;2;1 -> [0.000000] [mc_dfs/INFO] DFS exploration ended. 18 unique states visited; 4 backtracks (22 transition replays, 0 states visited overall) diff --git a/examples/cpp/mess-wait/s4u-mess-wait.cpp b/examples/cpp/mess-wait/s4u-mess-wait.cpp new file mode 100644 index 0000000000..086dc474c2 --- /dev/null +++ b/examples/cpp/mess-wait/s4u-mess-wait.cpp @@ -0,0 +1,79 @@ +/* Copyright (c) 2023. 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. */ + +/* This example shows how to use simgrid::s4u::this_actor::wait() to wait for a given communication. + * + * As for the other asynchronous examples, the sender initiate all the messages it wants to send and + * pack the resulting simgrid::s4u::CommPtr objects in a vector. All messages thus occurs concurrently. + * + * The sender then loops until there is no ongoing communication. + */ + +#include "simgrid/s4u.hpp" +#include +#include +#include +namespace sg4 = simgrid::s4u; + +XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_mess_wait, "Messages specific for this s4u example"); + +static void sender(int messages_count) +{ + sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("control"); + + sg4::this_actor::sleep_for(0.5); + + for (int i = 0; i < messages_count; i++) { + std::string msg_content = "Message " + std::to_string(i); + // Copy the data we send: the 'msg_content' variable is not a stable storage location. + // It will be destroyed when this actor leaves the loop, ie before the receiver gets the data + auto* payload = new std::string(msg_content); + + /* Create a control message and put it in the message queue */ + sg4::MessPtr mess = mqueue->put_async(payload); + XBT_INFO("Send '%s' to '%s'", msg_content.c_str(), mqueue->get_cname()); + mess->wait(); + } + + /* Send message to let the receiver know that it should stop */ + XBT_INFO("Send 'finalize' to 'receiver'"); + mqueue->put(new std::string("finalize")); +} + +/* Receiver actor expects 1 argument: its ID */ +static void receiver() +{ + sg4::MessageQueue* mqueue = sg4::MessageQueue::by_name("control"); + + sg4::this_actor::sleep_for(1); + + XBT_INFO("Wait for my first message"); + for (bool cont = true; cont;) { + std::string* received; + sg4::MessPtr mess = mqueue->get_async(&received); + + sg4::this_actor::sleep_for(0.1); + mess->wait(); + + XBT_INFO("I got a '%s'.", received->c_str()); + if (*received == "finalize") + cont = false; // If it's a finalize message, we're done. + delete received; + } +} + +int main(int argc, char* argv[]) +{ + sg4::Engine e(&argc, argv); + + e.load_platform(argv[1]); + + sg4::Actor::create("sender", e.host_by_name("Tremblay"), sender, 3); + sg4::Actor::create("receiver", e.host_by_name("Fafard"), receiver); + + e.run(); + + return 0; +} diff --git a/examples/cpp/mess-wait/s4u-mess-wait.tesh b/examples/cpp/mess-wait/s4u-mess-wait.tesh new file mode 100644 index 0000000000..fe7bcee8f9 --- /dev/null +++ b/examples/cpp/mess-wait/s4u-mess-wait.tesh @@ -0,0 +1,12 @@ +#!/usr/bin/env tesh + +$ ${bindir:=.}/s4u-mess-wait ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" +> [ 0.500000] (1:sender@Tremblay) Send 'Message 0' to 'control' +> [ 1.000000] (2:receiver@Fafard) Wait for my first message +> [ 1.000000] (1:sender@Tremblay) Send 'Message 1' to 'control' +> [ 1.100000] (2:receiver@Fafard) I got a 'Message 0'. +> [ 1.100000] (1:sender@Tremblay) Send 'Message 2' to 'control' +> [ 1.200000] (2:receiver@Fafard) I got a 'Message 1'. +> [ 1.200000] (1:sender@Tremblay) Send 'finalize' to 'receiver' +> [ 1.300000] (2:receiver@Fafard) I got a 'Message 2'. +> [ 1.400000] (2:receiver@Fafard) I got a 'finalize'. \ No newline at end of file diff --git a/examples/cpp/synchro-barrier/s4u-mc-synchro-barrier.tesh b/examples/cpp/synchro-barrier/s4u-mc-synchro-barrier.tesh index b17f900737..9ed6eb7f45 100644 --- a/examples/cpp/synchro-barrier/s4u-mc-synchro-barrier.tesh +++ b/examples/cpp/synchro-barrier/s4u-mc-synchro-barrier.tesh @@ -18,21 +18,21 @@ $ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs. > [Checker] Sleep set actually containing: > [Checker] Execute 2: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 2, state: 2, 0 interleaves) > [Checker] INDEPENDENT Transitions: -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=1) -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=2) +> [Checker] #1 BARRIER_ASYNC_LOCK(barrier: 0) (state=1) +> [Checker] #2 BARRIER_ASYNC_LOCK(barrier: 0) (state=2) > [Checker] Sleep set actually containing: > [Checker] Execute 1: BARRIER_WAIT(barrier: 0) (stack depth: 3, state: 3, 0 interleaves) > [Checker] Dependent Transitions: -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=2) -> [Checker] BARRIER_WAIT(barrier: 0) (state=3) +> [Checker] #2 BARRIER_ASYNC_LOCK(barrier: 0) (state=2) +> [Checker] #1 BARRIER_WAIT(barrier: 0) (state=3) > [Checker] Sleep set actually containing: > [Checker] Execute 2: BARRIER_WAIT(barrier: 0) (stack depth: 4, state: 4, 0 interleaves) > [Checker] INDEPENDENT Transitions: -> [Checker] BARRIER_WAIT(barrier: 0) (state=3) -> [Checker] BARRIER_WAIT(barrier: 0) (state=4) +> [Checker] #1 BARRIER_WAIT(barrier: 0) (state=3) +> [Checker] #2 BARRIER_WAIT(barrier: 0) (state=4) > [Checker] Dependent Transitions: -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=1) -> [Checker] BARRIER_WAIT(barrier: 0) (state=4) +> [Checker] #1 BARRIER_ASYNC_LOCK(barrier: 0) (state=1) +> [Checker] #2 BARRIER_WAIT(barrier: 0) (state=4) > [Checker] 0 actors remain, but none of them need to be interleaved (depth 6). > [Checker] Execution came to an end at 1;2;1;2 (state: 5, depth: 5) > [Checker] Backtracking from 1;2;1;2 @@ -50,40 +50,40 @@ $ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs. > [Checker] Sleep set actually containing: > [Checker] Execute 2: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 2, state: 2, 0 interleaves) > [Checker] INDEPENDENT Transitions: -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=1) -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=2) +> [Checker] #1 BARRIER_ASYNC_LOCK(barrier: 0) (state=1) +> [Checker] #2 BARRIER_ASYNC_LOCK(barrier: 0) (state=2) > [Checker] Sleep set actually containing: > [Checker] Execute 3: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 3, state: 3, 0 interleaves) > [Checker] INDEPENDENT Transitions: -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=2) -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=3) +> [Checker] #2 BARRIER_ASYNC_LOCK(barrier: 0) (state=2) +> [Checker] #3 BARRIER_ASYNC_LOCK(barrier: 0) (state=3) > [Checker] INDEPENDENT Transitions: -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=1) -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=3) +> [Checker] #1 BARRIER_ASYNC_LOCK(barrier: 0) (state=1) +> [Checker] #3 BARRIER_ASYNC_LOCK(barrier: 0) (state=3) > [Checker] Sleep set actually containing: > [Checker] Execute 1: BARRIER_WAIT(barrier: 0) (stack depth: 4, state: 4, 0 interleaves) > [Checker] Dependent Transitions: -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=3) -> [Checker] BARRIER_WAIT(barrier: 0) (state=4) +> [Checker] #3 BARRIER_ASYNC_LOCK(barrier: 0) (state=3) +> [Checker] #1 BARRIER_WAIT(barrier: 0) (state=4) > [Checker] Sleep set actually containing: > [Checker] Execute 2: BARRIER_WAIT(barrier: 0) (stack depth: 5, state: 5, 0 interleaves) > [Checker] INDEPENDENT Transitions: -> [Checker] BARRIER_WAIT(barrier: 0) (state=4) -> [Checker] BARRIER_WAIT(barrier: 0) (state=5) +> [Checker] #1 BARRIER_WAIT(barrier: 0) (state=4) +> [Checker] #2 BARRIER_WAIT(barrier: 0) (state=5) > [Checker] Dependent Transitions: -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=3) -> [Checker] BARRIER_WAIT(barrier: 0) (state=5) +> [Checker] #3 BARRIER_ASYNC_LOCK(barrier: 0) (state=3) +> [Checker] #2 BARRIER_WAIT(barrier: 0) (state=5) > [Checker] Sleep set actually containing: > [Checker] Execute 3: BARRIER_WAIT(barrier: 0) (stack depth: 6, state: 6, 0 interleaves) > [Checker] INDEPENDENT Transitions: -> [Checker] BARRIER_WAIT(barrier: 0) (state=5) -> [Checker] BARRIER_WAIT(barrier: 0) (state=6) +> [Checker] #2 BARRIER_WAIT(barrier: 0) (state=5) +> [Checker] #3 BARRIER_WAIT(barrier: 0) (state=6) > [Checker] INDEPENDENT Transitions: -> [Checker] BARRIER_WAIT(barrier: 0) (state=4) -> [Checker] BARRIER_WAIT(barrier: 0) (state=6) +> [Checker] #1 BARRIER_WAIT(barrier: 0) (state=4) +> [Checker] #3 BARRIER_WAIT(barrier: 0) (state=6) > [Checker] Dependent Transitions: -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=2) -> [Checker] BARRIER_WAIT(barrier: 0) (state=6) +> [Checker] #2 BARRIER_ASYNC_LOCK(barrier: 0) (state=2) +> [Checker] #3 BARRIER_WAIT(barrier: 0) (state=6) > [Checker] 0 actors remain, but none of them need to be interleaved (depth 8). > [Checker] Execution came to an end at 1;2;3;1;2;3 (state: 7, depth: 7) > [Checker] Backtracking from 1;2;3;1;2;3 @@ -91,8 +91,8 @@ $ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs. > [Checker] <2,BARRIER_ASYNC_LOCK(barrier: 0)> > [Checker] Execute 3: BARRIER_ASYNC_LOCK(barrier: 0) (stack depth: 2, state: 2, 0 interleaves) > [Checker] INDEPENDENT Transitions: -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=1) -> [Checker] BARRIER_ASYNC_LOCK(barrier: 0) (state=2) +> [Checker] #1 BARRIER_ASYNC_LOCK(barrier: 0) (state=1) +> [Checker] #3 BARRIER_ASYNC_LOCK(barrier: 0) (state=2) > [Checker] 3 actors remain, but none of them need to be interleaved (depth 4). > [Checker] Backtracking from 1;3 > [Checker] DFS exploration ended. 8 unique states visited; 1 backtracks (1 transition replays, 10 states visited overall) \ No newline at end of file diff --git a/examples/cpp/synchro-mutex/s4u-mc-synchro-mutex-stateful.tesh b/examples/cpp/synchro-mutex/s4u-mc-synchro-mutex-stateful.tesh deleted file mode 100644 index d2a7187d84..0000000000 --- a/examples/cpp/synchro-mutex/s4u-mc-synchro-mutex-stateful.tesh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env tesh - -p This file tests the cfg=model-check/checkpoint option for DFS explorer - -$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/checkpoint:5 -- ${bindir:=.}/s4u-synchro-mutex --cfg=actors:2 --log=s4u_test.thres:critical -> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/checkpoint' to '5' -> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'actors' to '2' -> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor. -> [0.000000] [mc_dfs/INFO] DFS exploration ended. 66 unique states visited; 11 backtracks (22 transition replays, 99 states visited overall) - -p The stats without checkpoints is: 130 unique states visited; 27 backtracks (308 transition replays, 151 states visited overall) -p But it runs much faster (0.6 sec vs. 1.6 sec), damn slow checkpointing code. diff --git a/examples/cpp/synchro-mutex/s4u-mc-synchro-mutex.tesh b/examples/cpp/synchro-mutex/s4u-mc-synchro-mutex.tesh index f7f1a551d8..5f726fec70 100644 --- a/examples/cpp/synchro-mutex/s4u-mc-synchro-mutex.tesh +++ b/examples/cpp/synchro-mutex/s4u-mc-synchro-mutex.tesh @@ -14,24 +14,24 @@ $ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs. > [Checker] Sleep set actually containing: > [Checker] Execute 2: MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (stack depth: 4, state: 4, 0 interleaves) > [Checker] INDEPENDENT Transitions: -> [Checker] MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3) -> [Checker] MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4) +> [Checker] #1 MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3) +> [Checker] #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4) > [Checker] INDEPENDENT Transitions: -> [Checker] MUTEX_WAIT(mutex: 0, owner: 1) (state=2) -> [Checker] MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4) +> [Checker] #1 MUTEX_WAIT(mutex: 0, owner: 1) (state=2) +> [Checker] #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4) > [Checker] Dependent Transitions: -> [Checker] MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=1) -> [Checker] MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4) +> [Checker] #1 MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=1) +> [Checker] #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=4) > [Checker] Sleep set actually containing: > [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner: 2) (stack depth: 5, state: 5, 0 interleaves) > [Checker] Dependent Transitions: -> [Checker] MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3) -> [Checker] MUTEX_WAIT(mutex: 0, owner: 2) (state=5) +> [Checker] #1 MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3) +> [Checker] #2 MUTEX_WAIT(mutex: 0, owner: 2) (state=5) > [Checker] Sleep set actually containing: > [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner: -1) (stack depth: 6, state: 6, 0 interleaves) > [Checker] Dependent Transitions: -> [Checker] MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3) -> [Checker] MUTEX_UNLOCK(mutex: 0, owner: -1) (state=6) +> [Checker] #1 MUTEX_UNLOCK(mutex: 0, owner: -1) (state=3) +> [Checker] #2 MUTEX_UNLOCK(mutex: 0, owner: -1) (state=6) > [Checker] 0 actors remain, but none of them need to be interleaved (depth 8). > [Checker] Execution came to an end at 1;1;1;2;2;2 (state: 7, depth: 7) > [Checker] Backtracking from 1;1;1;2;2;2 @@ -39,11 +39,11 @@ $ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs. > [Checker] <1,MUTEX_UNLOCK(mutex: 0, owner: -1)> > [Checker] Execute 2: MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (stack depth: 3, state: 3, 0 interleaves) > [Checker] INDEPENDENT Transitions: -> [Checker] MUTEX_WAIT(mutex: 0, owner: 1) (state=2) -> [Checker] MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=3) +> [Checker] #1 MUTEX_WAIT(mutex: 0, owner: 1) (state=2) +> [Checker] #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=3) > [Checker] Dependent Transitions: -> [Checker] MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=1) -> [Checker] MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=3) +> [Checker] #1 MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=1) +> [Checker] #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 1) (state=3) > [Checker] 2 actors remain, but none of them need to be interleaved (depth 5). > [Checker] Backtracking from 1;1;2 > [Checker] Sleep set actually containing: @@ -52,28 +52,28 @@ $ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs. > [Checker] Sleep set actually containing: > [Checker] Execute 1: MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (stack depth: 2, state: 9, 0 interleaves) > [Checker] Dependent Transitions: -> [Checker] MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=1) -> [Checker] MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=9) +> [Checker] #2 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=1) +> [Checker] #1 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=9) > [Checker] Sleep set actually containing: > [Checker] Execute 2: MUTEX_WAIT(mutex: 0, owner: 2) (stack depth: 3, state: 10, 0 interleaves) > [Checker] INDEPENDENT Transitions: -> [Checker] MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=9) -> [Checker] MUTEX_WAIT(mutex: 0, owner: 2) (state=10) +> [Checker] #1 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=9) +> [Checker] #2 MUTEX_WAIT(mutex: 0, owner: 2) (state=10) > [Checker] Sleep set actually containing: > [Checker] Execute 2: MUTEX_UNLOCK(mutex: 0, owner: 1) (stack depth: 4, state: 11, 0 interleaves) > [Checker] INDEPENDENT Transitions: -> [Checker] MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=9) -> [Checker] MUTEX_UNLOCK(mutex: 0, owner: 1) (state=11) +> [Checker] #1 MUTEX_ASYNC_LOCK(mutex: 0, owner: 2) (state=9) +> [Checker] #2 MUTEX_UNLOCK(mutex: 0, owner: 1) (state=11) > [Checker] Sleep set actually containing: > [Checker] Execute 1: MUTEX_WAIT(mutex: 0, owner: 1) (stack depth: 5, state: 12, 0 interleaves) > [Checker] Dependent Transitions: -> [Checker] MUTEX_UNLOCK(mutex: 0, owner: 1) (state=11) -> [Checker] MUTEX_WAIT(mutex: 0, owner: 1) (state=12) +> [Checker] #2 MUTEX_UNLOCK(mutex: 0, owner: 1) (state=11) +> [Checker] #1 MUTEX_WAIT(mutex: 0, owner: 1) (state=12) > [Checker] Sleep set actually containing: > [Checker] Execute 1: MUTEX_UNLOCK(mutex: 0, owner: -1) (stack depth: 6, state: 13, 0 interleaves) > [Checker] Dependent Transitions: -> [Checker] MUTEX_UNLOCK(mutex: 0, owner: 1) (state=11) -> [Checker] MUTEX_UNLOCK(mutex: 0, owner: -1) (state=13) +> [Checker] #2 MUTEX_UNLOCK(mutex: 0, owner: 1) (state=11) +> [Checker] #1 MUTEX_UNLOCK(mutex: 0, owner: -1) (state=13) > [Checker] 0 actors remain, but none of them need to be interleaved (depth 8). > [Checker] Execution came to an end at 2;1;2;2;1;1 (state: 14, depth: 7) > [Checker] Backtracking from 2;1;2;2;1;1 diff --git a/examples/cpp/task-storm/s4u-task-storm.cpp b/examples/cpp/task-storm/s4u-task-storm.cpp index 0a0ab7143b..ca0f61ea5c 100644 --- a/examples/cpp/task-storm/s4u-task-storm.cpp +++ b/examples/cpp/task-storm/s4u-task-storm.cpp @@ -111,11 +111,13 @@ int main(int argc, char* argv[]) auto data = t->get_token_from(SA_to_B1)->get_data(); t->deque_token_from(SA_to_B1); t->set_amount(*data * 10); + delete data; }); B2->on_this_start_cb([&SA_to_B2](sg4::Task* t) { auto data = t->get_token_from(SA_to_B2)->get_data(); t->deque_token_from(SA_to_B2); t->set_amount(*data * 10); + delete data; }); // Enqueue firings for tasks without predecessors diff --git a/examples/smpi/CMakeLists.txt b/examples/smpi/CMakeLists.txt index c2b3186017..e5901089c3 100644 --- a/examples/smpi/CMakeLists.txt +++ b/examples/smpi/CMakeLists.txt @@ -3,10 +3,9 @@ set(_replay_sources ${CMAKE_CURRENT_SOURCE_DIR}/replay/replay.cpp) set(_ampi_test_sources ${CMAKE_CURRENT_SOURCE_DIR}/ampi_test/ampi_test.cpp) # These tests are only used when MC is actived -set(MC_tests bugged1 bugged2 bugged1_liveness only_send_deterministic mutual_exclusion non_termination1 - non_termination2 non_termination3 non_termination4 sendsend) +set(MC_tests bugged1 bugged2 only_send_deterministic mutual_exclusion sendsend) foreach(x ${MC_tests}) - if(NOT SIMGRID_HAVE_STATEFUL_MC) + if(NOT SIMGRID_HAVE_MC) set(_${x}_disable 1) endif() set(_${x}_sources ${CMAKE_CURRENT_SOURCE_DIR}/mc/${x}.c) @@ -65,13 +64,10 @@ set(tesh_files ${tesh_files} ${CMAKE_CURRENT_SOURCE_DIR}/energy/energy.tes ${CMAKE_CURRENT_SOURCE_DIR}/replay/replay.tesh PARENT_SCOPE) set(bin_files ${bin_files} ${CMAKE_CURRENT_SOURCE_DIR}/hostfile ${CMAKE_CURRENT_SOURCE_DIR}/energy/hostfile - ${CMAKE_CURRENT_SOURCE_DIR}/mc/promela_bugged1_liveness - ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_bugged1_liveness ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_bugged1 ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_bugged2 ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_only_send_deterministic ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_mutual_exclusion - ${CMAKE_CURRENT_SOURCE_DIR}/mc/hostfile_non_termination ${CMAKE_CURRENT_SOURCE_DIR}/simple-execute/hostfile_griffon PARENT_SCOPE) set(txt_files ${txt_files} ${CMAKE_CURRENT_SOURCE_DIR}/replay/actions0.txt ${CMAKE_CURRENT_SOURCE_DIR}/replay/actions1.txt @@ -91,7 +87,7 @@ set(txt_files ${txt_files} ${CMAKE_CURRENT_SOURCE_DIR}/replay/actions0.t if(enable_smpi) # MC is currently broken with threads (deadlock => timeout) - if(SIMGRID_HAVE_STATEFUL_MC) + if(SIMGRID_HAVE_MC) add_dependencies(tests-mc smpimain) add_dependencies(tests-mc smpi_only_send_deterministic) ADD_TESH(smpi-mc-only-send-determinism --setenv srcdir=${CMAKE_HOME_DIRECTORY}/examples/smpi/mc --setenv platfdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --cd ${CMAKE_BINARY_DIR}/examples/smpi/mc ${CMAKE_HOME_DIRECTORY}/examples/smpi/mc/only_send_deterministic.tesh) diff --git a/examples/smpi/mc/bugged1_liveness.c b/examples/smpi/mc/bugged1_liveness.c deleted file mode 100644 index 0b215f9324..0000000000 --- a/examples/smpi/mc/bugged1_liveness.c +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (c) 2013-2023. 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. */ - -/***************** Centralized Mutual Exclusion Algorithm *********************/ -/* This example implements a centralized mutual exclusion algorithm. */ -/* Bug : CS requests of process 1 not satisfied */ -/* LTL property checked : G(r->F(cs)); (r=request of CS, cs=CS ok) */ -/******************************************************************************/ - -/* Run : - /usr/bin/time -f "clock:%e user:%U sys:%S swapped:%W exitval:%x max:%Mk" "$@" \ - ../../../smpi_script/bin/smpirun -hostfile hostfile_bugged1_liveness -platform ../../platforms/cluster_backbone.xml \ - --cfg=contexts/factory:ucontext --cfg=model-check/reduction:none \ - --cfg=model-check/property:promela_bugged1_liveness --cfg=smpi/send-is-detached-thresh:0 \ - --cfg=contexts/stack-size:128 --cfg=model-check/visited:100000 --cfg=model-check/max-depth:100000 ./bugged1_liveness -*/ - -#include -#include -#include -#include - -#define GRANT_TAG 0 -#define REQUEST_TAG 1 -#define RELEASE_TAG 2 - -int r; -int cs; - -int main(int argc, char **argv){ - int size; - int rank; - int recv_buff; - MPI_Status status; - xbt_dynar_t requests = xbt_dynar_new(sizeof(int), NULL); - - /* Initialize MPI */ - int err = MPI_Init(&argc, &argv); - if(err != MPI_SUCCESS){ - printf("MPI initialization failed !\n"); - exit(1); - } - - MC_automaton_new_propositional_symbol_pointer("r", &r); - MC_automaton_new_propositional_symbol_pointer("cs", &cs); - - MC_ignore(&status.count, sizeof status.count); - - /* Get number of processes */ - MPI_Comm_size(MPI_COMM_WORLD, &size); - /* Get id of this process */ - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - if(rank == 0){ /* Coordinator */ - int CS_used = 0; - while(1){ - MPI_Recv(&recv_buff, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); - if(status.MPI_TAG == REQUEST_TAG){ - if(CS_used){ - printf("CS already used.\n"); - xbt_dynar_push(requests, &recv_buff); - }else{ - if(recv_buff != size - 1){ - printf("CS idle. Grant immediately.\n"); - MPI_Send(&rank, 1, MPI_INT, recv_buff, GRANT_TAG, MPI_COMM_WORLD); - CS_used = 1; - } - } - }else{ - if(!xbt_dynar_is_empty(requests)){ - printf("CS release. Grant to queued requests (queue size: %lu)", xbt_dynar_length(requests)); - xbt_dynar_shift(requests, &recv_buff); - if(recv_buff != size - 1){ - MPI_Send(&rank, 1, MPI_INT, recv_buff, GRANT_TAG, MPI_COMM_WORLD); - CS_used = 1; - }else{ - xbt_dynar_push(requests, &recv_buff); - CS_used = 0; - } - }else{ - printf("CS release. Resource now idle.\n"); - CS_used = 0; - } - } - } - }else{ /* Client */ - while(1){ - printf("%d asks the request.\n", rank); - MPI_Send(&rank, 1, MPI_INT, 0, REQUEST_TAG, MPI_COMM_WORLD); - if(rank == size - 1){ - r = 1; - cs = 0; - } - MPI_Recv(&recv_buff, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &status); - if(status.MPI_TAG == GRANT_TAG && rank == size - 1){ - cs = 1; - r = 0; - } - printf("%d got the answer. Release it.\n", rank); - MPI_Send(&rank, 1, MPI_INT, 0, RELEASE_TAG, MPI_COMM_WORLD); - if(rank == size - 1){ - r = 0; - cs = 0; - } - } - } - - MPI_Finalize(); - - return 0; -} diff --git a/examples/smpi/mc/hostfile_bugged1_liveness b/examples/smpi/mc/hostfile_bugged1_liveness deleted file mode 100644 index edbbeb8312..0000000000 --- a/examples/smpi/mc/hostfile_bugged1_liveness +++ /dev/null @@ -1,3 +0,0 @@ -node-1.simgrid.org -node-2.simgrid.org -node-3.simgrid.org diff --git a/examples/smpi/mc/hostfile_non_termination b/examples/smpi/mc/hostfile_non_termination deleted file mode 100644 index c1627f2e47..0000000000 --- a/examples/smpi/mc/hostfile_non_termination +++ /dev/null @@ -1,2 +0,0 @@ -node-1.simgrid.org -node-2.simgrid.org \ No newline at end of file diff --git a/examples/smpi/mc/mutual_exclusion.c b/examples/smpi/mc/mutual_exclusion.c index 0fb0a756fb..235860c24d 100644 --- a/examples/smpi/mc/mutual_exclusion.c +++ b/examples/smpi/mc/mutual_exclusion.c @@ -27,8 +27,6 @@ int main(int argc, char **argv){ exit(1); } - MC_ignore(&status.count, sizeof status.count); - /* Get number of processes */ MPI_Comm_size(MPI_COMM_WORLD, &size); /* Get id of this process */ diff --git a/examples/smpi/mc/non_termination1.c b/examples/smpi/mc/non_termination1.c deleted file mode 100644 index a0ce7ddca6..0000000000 --- a/examples/smpi/mc/non_termination1.c +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (c) 2015-2023. 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 - -int x = 5; -int y = 8; - -int main(int argc, char **argv) { - int recv_buff; - int size; - int rank; - MPI_Status status; - - MPI_Init(&argc, &argv); - - MPI_Comm_size(MPI_COMM_WORLD, &size); /* Get nr of tasks */ - MPI_Comm_rank(MPI_COMM_WORLD, &rank); /* Get id of this process */ - - MC_ignore(&status.count, sizeof status.count); - - if (rank == 0) { - while (1) { - MPI_Recv(&recv_buff, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); - } - } else { - while (1) { - int old_x = x; - x = -y; - y = old_x; - printf("x = %d, y = %d\n", x, y); - MPI_Send(&rank, 1, MPI_INT, 0, 42, MPI_COMM_WORLD); - } - } - - MPI_Finalize(); - - return 0; -} diff --git a/examples/smpi/mc/non_termination2.c b/examples/smpi/mc/non_termination2.c deleted file mode 100644 index 5ccafb6932..0000000000 --- a/examples/smpi/mc/non_termination2.c +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (c) 2015-2023. 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 - -int x; - -int main(int argc, char **argv) { - int recv_buff; - int size; - int rank; - MPI_Status status; - - MPI_Init(&argc, &argv); - - MPI_Comm_size(MPI_COMM_WORLD, &size); /* Get nr of tasks */ - MPI_Comm_rank(MPI_COMM_WORLD, &rank); /* Get id of this process */ - - MC_ignore(&status.count, sizeof status.count); - - if (rank == 0) { - while (1) { - MPI_Recv(&recv_buff, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); - } - } else { - while (1) { - x = 2; - MPI_Send(&rank, 1, MPI_INT, 0, 42, MPI_COMM_WORLD); - } - } - - MPI_Finalize(); - - return 0; -} diff --git a/examples/smpi/mc/non_termination3.c b/examples/smpi/mc/non_termination3.c deleted file mode 100644 index 309f4d45b3..0000000000 --- a/examples/smpi/mc/non_termination3.c +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright (c) 2015-2023. 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 - -int x = 0; -int y = 0; - -int main(int argc, char **argv) { - int recv_x; - int recv_y; - int size; - int rank; - MPI_Status status; - - MPI_Init(&argc, &argv); - - MPI_Comm_size(MPI_COMM_WORLD, &size); /* Get nr of tasks */ - MPI_Comm_rank(MPI_COMM_WORLD, &rank); /* Get id of this process */ - - MC_ignore(&status.count, sizeof status.count); - - if (rank == 0) { - while (x<5) { - MPI_Recv(&recv_x, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); - MPI_Recv(&recv_y, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); - } - } else { - while (x<5) { - int old_x = x; - x = old_x - y; - MPI_Send(&x, 1, MPI_INT, 0, 42, MPI_COMM_WORLD); - y = old_x + y; - MPI_Send(&y, 1, MPI_INT, 0, 42, MPI_COMM_WORLD); - } - } - - MPI_Finalize(); - - return 0; -} diff --git a/examples/smpi/mc/non_termination4.c b/examples/smpi/mc/non_termination4.c deleted file mode 100644 index 7facb28c0d..0000000000 --- a/examples/smpi/mc/non_termination4.c +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (c) 2015-2023. 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 - -int x = 20; - -int main(int argc, char **argv) { - int recv_x = 1; - int size; - int rank; - MPI_Status status; - - MPI_Init(&argc, &argv); - - MPI_Comm_size(MPI_COMM_WORLD, &size); /* Get nr of tasks */ - MPI_Comm_rank(MPI_COMM_WORLD, &rank); /* Get id of this process */ - - MC_ignore(&status.count, sizeof status.count); - - if(rank==0){ - while (recv_x>=0) { - MPI_Recv(&recv_x, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); - } - }else{ - while (x >= 0) { - if (MC_random(0,1) == 0) { - x -= 1; - } else { - x += 1; - } - printf("x=%d\n", x); - MPI_Send(&x, 1, MPI_INT, 0, 42, MPI_COMM_WORLD); - } - } - - MPI_Finalize(); - - return 0; -} diff --git a/examples/smpi/mc/promela_bugged1_liveness b/examples/smpi/mc/promela_bugged1_liveness deleted file mode 100644 index 96b491d6af..0000000000 --- a/examples/smpi/mc/promela_bugged1_liveness +++ /dev/null @@ -1,11 +0,0 @@ -never { /* !G(r->Fcs) */ -T0_init : /* init */ - if - :: (1) -> goto T0_init - :: (!cs && r) -> goto accept_S2 - fi; -accept_S2 : /* 1 */ - if - :: (!cs) -> goto accept_S2 - fi; -} diff --git a/examples/sthread/CMakeLists.txt b/examples/sthread/CMakeLists.txt index 98811c23ad..a3d86817e9 100644 --- a/examples/sthread/CMakeLists.txt +++ b/examples/sthread/CMakeLists.txt @@ -5,16 +5,13 @@ find_package(Threads REQUIRED) ######################################################################### foreach(x - mutex-simple + mutex-simple mutex-recursive producer-consumer) if("${CMAKE_SYSTEM}" MATCHES "Linux") add_executable (pthread-${x} EXCLUDE_FROM_ALL pthread-${x}.c) set_target_properties(pthread-${x} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(pthread-${x} PRIVATE Threads::Threads) - if(SIMGRID_HAVE_STATEFUL_MC) # Only needed to introspect the binary - target_link_libraries(pthread-${x} PUBLIC "-Wl,-znorelro -Wl,-znoseparate-code") # TODO: convert to target_link_option once CMAKE_VERSION is >3.13 - endif() add_dependencies(tests pthread-${x}) ADD_TESH_FACTORIES(pthread-${x} "^thread" --setenv libdir=${CMAKE_BINARY_DIR}/lib --cd ${CMAKE_BINARY_DIR}/examples/sthread ${CMAKE_CURRENT_SOURCE_DIR}/pthread-${x}.tesh) @@ -42,9 +39,6 @@ foreach(x add_executable (pthread-${x} EXCLUDE_FROM_ALL pthread-${x}.c) set_target_properties(pthread-${x} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(pthread-${x} PRIVATE Threads::Threads) - if(SIMGRID_HAVE_STATEFUL_MC) # Only needed to introspect the binary - target_link_libraries(pthread-${x} PUBLIC "-Wl,-znorelro -Wl,-znoseparate-code") # TODO: convert to target_link_option once CMAKE_VERSION is >3.13 - endif() if(SIMGRID_HAVE_MC) add_dependencies(tests-mc pthread-${x}) @@ -67,9 +61,6 @@ foreach(example add_executable (${example} EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/${example}/${example}.cpp) set_target_properties(${example} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(${example} PRIVATE Threads::Threads) - if(SIMGRID_HAVE_STATEFUL_MC) # Only needed to introspect the binary - target_link_libraries(${example} PUBLIC "-fPIC -Wl,-znorelro -Wl,-znoseparate-code") # TODO: convert to target_link_option once CMAKE_VERSION is >3.13 - endif() set_target_properties(${example} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${example}) if(SIMGRID_HAVE_MC) diff --git a/examples/sthread/pthread-mc-mutex-recursive.tesh b/examples/sthread/pthread-mc-mutex-recursive.tesh new file mode 100644 index 0000000000..485712903a --- /dev/null +++ b/examples/sthread/pthread-mc-mutex-recursive.tesh @@ -0,0 +1,14 @@ +# We ignore the LD_PRELOAD lines from the expected output because they contain the build path +! ignore .*LD_PRELOAD.* + +$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-mutex-recursive +> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor. +> Got the lock on the default mutex. +> Failed to relock the default mutex. +> Got the lock on the recursive mutex. +> Got the lock again on the recursive mutex. +> Got the lock on the default mutex. +> Failed to relock the default mutex. +> Got the lock on the recursive mutex. +> Got the lock again on the recursive mutex. +> [0.000000] [mc_dfs/INFO] DFS exploration ended. 17 unique states visited; 1 backtracks (3 transition replays, 21 states visited overall) diff --git a/examples/sthread/pthread-mc-mutex-simple.tesh b/examples/sthread/pthread-mc-mutex-simple.tesh index 55ecc955dc..b352717928 100644 --- a/examples/sthread/pthread-mc-mutex-simple.tesh +++ b/examples/sthread/pthread-mc-mutex-simple.tesh @@ -2,8 +2,7 @@ # We ignore the LD_PRELOAD lines from the expected output because they contain the build path ! ignore .*LD_PRELOAD.* -$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/pthread-mutex-simple -> [0.000000] [sthread/INFO] Starting the simulation. +$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-mutex-simple > All threads are started. > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor. > The thread 0 is terminating. @@ -12,4 +11,4 @@ $ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-chec > The thread 1 is terminating. > The thread 0 is terminating. > User's main is terminating. -> [0.000000] [mc_dfs/INFO] DFS exploration ended. 18 unique states visited; 2 backtracks (2 transition replays, 22 states visited overall) \ No newline at end of file +> [0.000000] [mc_dfs/INFO] DFS exploration ended. 18 unique states visited; 2 backtracks (2 transition replays, 22 states visited overall) diff --git a/examples/sthread/pthread-mc-mutex-simpledeadlock.tesh b/examples/sthread/pthread-mc-mutex-simpledeadlock.tesh index 2de4e42603..8a23f34965 100644 --- a/examples/sthread/pthread-mc-mutex-simpledeadlock.tesh +++ b/examples/sthread/pthread-mc-mutex-simpledeadlock.tesh @@ -5,8 +5,7 @@ # We ignore the LD_PRELOAD lines from the expected output because they contain the build path ! ignore .*LD_PRELOAD.* -$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/pthread-mutex-simpledeadlock -> [0.000000] [sthread/INFO] Starting the simulation. +$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-mutex-simpledeadlock > All threads are started. > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor. > The thread 0 is terminating. diff --git a/examples/sthread/pthread-mc-producer-consumer.tesh b/examples/sthread/pthread-mc-producer-consumer.tesh index a9f5a723d7..508d8dac98 100644 --- a/examples/sthread/pthread-mc-producer-consumer.tesh +++ b/examples/sthread/pthread-mc-producer-consumer.tesh @@ -1,19 +1,16 @@ # We ignore the LD_PRELOAD lines from the expected output because they contain the build path ! ignore .*LD_PRELOAD.* -$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/pthread-producer-consumer -q -C 1 -P 1 -> [0.000000] [sthread/INFO] Starting the simulation. +$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-producer-consumer -q -C 1 -P 1 > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor. > [0.000000] [mc_dfs/INFO] DFS exploration ended. 786 unique states visited; 97 backtracks (2049 transition replays, 2932 states visited overall) -$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:sdpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/pthread-producer-consumer -q -C 1 -P 1 +$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:sdpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-producer-consumer -q -C 1 -P 1 > [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'sdpor' -> [0.000000] [sthread/INFO] Starting the simulation. > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: sdpor. > [0.000000] [mc_dfs/INFO] DFS exploration ended. 1186 unique states visited; 157 backtracks (3403 transition replays, 4746 states visited overall) -$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsgmalloc.so:${libdir:=.}/libsthread.so ${bindir:=.}/pthread-producer-consumer -q -C 1 -P 1 +$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/pthread-producer-consumer -q -C 1 -P 1 > [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor' -> [0.000000] [sthread/INFO] Starting the simulation. > [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor. > [0.000000] [mc_dfs/INFO] DFS exploration ended. 39 unique states visited; 0 backtracks (0 transition replays, 39 states visited overall) diff --git a/examples/sthread/pthread-mutex-recursive.c b/examples/sthread/pthread-mutex-recursive.c new file mode 100644 index 0000000000..482cf3ee7f --- /dev/null +++ b/examples/sthread/pthread-mutex-recursive.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2002-2023. 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. */ + +/* Code with both recursive and non-recursive mutexes */ + +#include +#include +#include + +// Structure to hold the mutex's name and pointer to the actual mutex +typedef struct { + const char* name; + pthread_mutex_t* mutex; +} ThreadData; + +static void* thread_function(void* arg) +{ + ThreadData* data = (ThreadData*)arg; + pthread_mutex_t* mutex = data->mutex; + const char* name = data->name; + + pthread_mutex_lock(mutex); + fprintf(stderr, "Got the lock on the %s mutex.\n", name); + + // Attempt to relock the mutex - This behavior depends on the mutex type + if (pthread_mutex_trylock(mutex) == 0) { + fprintf(stderr, "Got the lock again on the %s mutex.\n", name); + pthread_mutex_unlock(mutex); + } else { + fprintf(stderr, "Failed to relock the %s mutex.\n", name); + } + + pthread_mutex_unlock(mutex); + + // pthread_exit(NULL); TODO: segfaulting + return NULL; +} + +int main() +{ + pthread_t thread1, thread2; + pthread_mutex_t mutex_dflt = PTHREAD_MUTEX_INITIALIZER; // Non-recursive mutex + + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_t mutex_rec; + pthread_mutex_init(&mutex_rec, &attr); + + ThreadData data1 = {"default", &mutex_dflt}; + ThreadData data2 = {"recursive", &mutex_rec}; + + pthread_create(&thread1, NULL, thread_function, &data1); + pthread_create(&thread2, NULL, thread_function, &data2); + + pthread_join(thread1, NULL); + pthread_join(thread2, NULL); + + pthread_mutex_destroy(&mutex_dflt); + pthread_mutex_destroy(&mutex_rec); + + return 0; +} diff --git a/examples/sthread/pthread-mutex-recursive.tesh b/examples/sthread/pthread-mutex-recursive.tesh new file mode 100644 index 0000000000..0879b2c14e --- /dev/null +++ b/examples/sthread/pthread-mutex-recursive.tesh @@ -0,0 +1,6 @@ +$ env ASAN_OPTIONS=verify_asan_link_order=0:$ASAN_OPTIONS LD_PRELOAD=${libdir:=.}/libsthread.so ./pthread-mutex-recursive +> Got the lock on the default mutex. +> Failed to relock the default mutex. +> Got the lock on the recursive mutex. +> Got the lock again on the recursive mutex. +> [0.000000] [sthread/INFO] All threads exited. Terminating the simulation. diff --git a/examples/sthread/pthread-mutex-simple.c b/examples/sthread/pthread-mutex-simple.c index 1d391418ba..a7dea6bd6b 100644 --- a/examples/sthread/pthread-mutex-simple.c +++ b/examples/sthread/pthread-mutex-simple.c @@ -1,3 +1,8 @@ +/* Copyright (c) 2002-2023. 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. */ + /* Simple test code with no bug */ #include diff --git a/examples/sthread/pthread-mutex-simple.tesh b/examples/sthread/pthread-mutex-simple.tesh index 29d66a92df..f4b3f3cd6b 100644 --- a/examples/sthread/pthread-mutex-simple.tesh +++ b/examples/sthread/pthread-mutex-simple.tesh @@ -1,5 +1,4 @@ $ env ASAN_OPTIONS=verify_asan_link_order=0:$ASAN_OPTIONS LD_PRELOAD=${libdir:=.}/libsthread.so ./pthread-mutex-simple -> [0.000000] [sthread/INFO] Starting the simulation. > All threads are started. > The thread 0 is terminating. > The thread 1 is terminating. diff --git a/examples/sthread/pthread-mutex-simpledeadlock.c b/examples/sthread/pthread-mutex-simpledeadlock.c index 09be6c11ea..92a04a1ace 100644 --- a/examples/sthread/pthread-mutex-simpledeadlock.c +++ b/examples/sthread/pthread-mutex-simpledeadlock.c @@ -1,3 +1,8 @@ +/* Copyright (c) 2002-2023. 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. */ + /* Simple test code that may deadlock: Thread 1 locks mutex1 then mutex2 while thread 2 locks in reverse order. diff --git a/examples/sthread/pthread-producer-consumer.tesh b/examples/sthread/pthread-producer-consumer.tesh index a54bed01af..471fbe8102 100644 --- a/examples/sthread/pthread-producer-consumer.tesh +++ b/examples/sthread/pthread-producer-consumer.tesh @@ -1,5 +1,4 @@ $ env ASAN_OPTIONS=verify_asan_link_order=0:$ASAN_OPTIONS LD_PRELOAD=${libdir:=.}/libsthread.so ./pthread-producer-consumer -> [0.000000] [sthread/INFO] Starting the simulation. > Producer 1: Insert Item 0 at 0 > Producer 2: Insert Item 0 at 1 > Consumer 1: Remove Item 0 from 0 @@ -15,7 +14,6 @@ $ env ASAN_OPTIONS=verify_asan_link_order=0:$ASAN_OPTIONS LD_PRELOAD=${libdir:=. > [0.000000] [sthread/INFO] All threads exited. Terminating the simulation. $ env ASAN_OPTIONS=verify_asan_link_order=0:$ASAN_OPTIONS LD_PRELOAD=${libdir:=.}/libsthread.so ./pthread-producer-consumer -c 2 -C 1 -p 2 -P 1 -> [0.000000] [sthread/INFO] Starting the simulation. > Producer 1: Insert Item 0 at 0 > Consumer 1: Remove Item 0 from 0 > Producer 1: Insert Item 1 at 1 diff --git a/examples/sthread/stdobject/stdobject.cpp b/examples/sthread/stdobject/stdobject.cpp index 06e49c86a5..246095eaef 100644 --- a/examples/sthread/stdobject/stdobject.cpp +++ b/examples/sthread/stdobject/stdobject.cpp @@ -6,13 +6,15 @@ std::vector v = {1, 2, 3, 5, 8, 13}; extern "C" { -extern int sthread_access_begin(void* addr, const char* objname, const char* file, int line) __attribute__((weak)); -extern void sthread_access_end(void* addr, const char* objname, const char* file, int line) __attribute__((weak)); +extern int sthread_access_begin(void* addr, const char* objname, const char* file, int line, const char* func) + __attribute__((weak)); +extern void sthread_access_end(void* addr, const char* objname, const char* file, int line, const char* func) + __attribute__((weak)); } #define STHREAD_ACCESS(obj) \ - for (bool first = sthread_access_begin(static_cast(obj), #obj, __FILE__, __LINE__) || true; first; \ - sthread_access_end(static_cast(obj), #obj, __FILE__, __LINE__), first = false) + for (bool first = sthread_access_begin(static_cast(obj), #obj, __FILE__, __LINE__, __FUNCTION__) || true; \ + first; sthread_access_end(static_cast(obj), #obj, __FILE__, __LINE__, __FUNCTION__), first = false) static void thread_code() { diff --git a/examples/sthread/stdobject/stdobject.tesh b/examples/sthread/stdobject/stdobject.tesh index 457238ced8..602c3f4589 100644 --- a/examples/sthread/stdobject/stdobject.tesh +++ b/examples/sthread/stdobject/stdobject.tesh @@ -5,7 +5,6 @@ ! ignore .*LD_PRELOAD.* $ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/stdobject "--log=root.fmt:[%11.6r]%e(%a@%h)%e%m%n" --log=no_loc -> [ 0.000000] (maestro@) Starting the simulation. > starting two helpers... > waiting for helpers to finish... > [ 0.000000] (maestro@) Start a DFS exploration. Reduction is: dpor. @@ -16,7 +15,7 @@ $ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-c > v = { 1, 2, 3, 5, 8, 13, 21, 21, }; > [ 0.000000] (maestro@) thread 1 takes &v > [ 0.000000] (maestro@) thread 2 takes &v -> [ 0.000000] (maestro@) Unprotected concurent access to &v: thread 1 vs thread 2 (locations hidden because of --log=no_loc). +> [ 0.000000] (maestro@) Unprotected concurent access to &v: thread 1 from 1 location vs thread 2 (locations hidden because of --log=no_loc). > [ 0.000000] (maestro@) ************************** > [ 0.000000] (maestro@) *** PROPERTY NOT VALID *** > [ 0.000000] (maestro@) ************************** diff --git a/examples/sthread/sthread-mutex-simple.tesh b/examples/sthread/sthread-mutex-simple.tesh index ffa04c1dc4..67afd1a12b 100644 --- a/examples/sthread/sthread-mutex-simple.tesh +++ b/examples/sthread/sthread-mutex-simple.tesh @@ -1,5 +1,4 @@ $ ./sthread-mutex-simple -> [0.000000] [sthread/INFO] Starting the simulation. > All threads are started. > The thread 0 is terminating. > The thread 1 is terminating. diff --git a/include/simgrid/config.h.in b/include/simgrid/config.h.in index bb4f27e346..6ef3fd76b1 100644 --- a/include/simgrid/config.h.in +++ b/include/simgrid/config.h.in @@ -13,8 +13,6 @@ #cmakedefine01 SIMGRID_HAVE_MALLOCATOR /* Was the model-checking compiled in? */ #cmakedefine01 SIMGRID_HAVE_MC -/* Was the stateful model-checking compiled in? */ -#cmakedefine01 SIMGRID_HAVE_STATEFUL_MC /* Was the ns-3 support compiled in? */ #cmakedefine01 SIMGRID_HAVE_NS3 #cmakedefine NS3_MINOR_VERSION @NS3_MINOR_VERSION@ diff --git a/include/simgrid/forward.h b/include/simgrid/forward.h index 2c1da4f7f1..ec54ec4158 100644 --- a/include/simgrid/forward.h +++ b/include/simgrid/forward.h @@ -76,6 +76,14 @@ class SplitDuplexLink; class Mailbox; +class Mess; +/** Smart pointer to a simgrid::s4u::Mess */ +using MessPtr = boost::intrusive_ptr; +XBT_PUBLIC void intrusive_ptr_release(Mess* c); +XBT_PUBLIC void intrusive_ptr_add_ref(Mess* c); + +class MessageQueue; + class Mutex; XBT_PUBLIC void intrusive_ptr_release(const Mutex* m); XBT_PUBLIC void intrusive_ptr_add_ref(const Mutex* m); @@ -123,6 +131,7 @@ using ActorCodeFactory = std::function args)> class Simcall; class SimcallObserver; +class MutexObserver; class ObjectAccessSimcallObserver; class ObjectAccessSimcallItem; } // namespace actor @@ -152,6 +161,8 @@ namespace activity { using ExecImplPtr = boost::intrusive_ptr; class IoImpl; using IoImplPtr = boost::intrusive_ptr; + class MessImpl; + using MessImplPtr = boost::intrusive_ptr; class MutexImpl; using MutexImplPtr = boost::intrusive_ptr; class MutexAcquisitionImpl; @@ -170,6 +181,7 @@ namespace activity { using SleepImplPtr = boost::intrusive_ptr; class MailboxImpl; + class MessageQueueImpl; } namespace context { class Context; @@ -232,6 +244,7 @@ using s4u_Link = simgrid::s4u::Link; using s4u_File = simgrid::s4u::File; using s4u_ConditionVariable = simgrid::s4u::ConditionVariable; using s4u_Mailbox = simgrid::s4u::Mailbox; +using s4u_MessageQueue = simgrid::s4u::MessageQueue; using s4u_Mutex = simgrid::s4u::Mutex; using s4u_Semaphore = simgrid::s4u::Semaphore; using s4u_Disk = simgrid::s4u::Disk; @@ -252,6 +265,7 @@ typedef struct s4u_Link s4u_Link; typedef struct s4u_File s4u_File; typedef struct s4u_ConditionVariable s4u_ConditionVariable; typedef struct s4u_Mailbox s4u_Mailbox; +typedef struct s4u_MessageQueue s4u_MessageQueue; typedef struct s4u_Mutex s4u_Mutex; typedef struct s4u_Semaphore s4u_Semaphore; typedef struct s4u_Disk s4u_Disk; @@ -271,6 +285,8 @@ typedef s4u_ConditionVariable* sg_cond_t; typedef const s4u_ConditionVariable* const_sg_cond_t; typedef s4u_Mailbox* sg_mailbox_t; typedef const s4u_Mailbox* const_sg_mailbox_t; +typedef s4u_MessageQueue* sg_messagequeue_t; +typedef const s4u_MessageQueue* const_sg_messagequeue_t; typedef s4u_Mutex* sg_mutex_t; typedef const s4u_Mutex* const_sg_mutex_t; typedef s4u_Semaphore* sg_sem_t; diff --git a/include/simgrid/modelchecker.h b/include/simgrid/modelchecker.h index 2c308ddd02..09566a3b82 100644 --- a/include/simgrid/modelchecker.h +++ b/include/simgrid/modelchecker.h @@ -23,13 +23,6 @@ XBT_PUBLIC void MC_assert(int); * It is off in simulation or when replaying MC traces (see MC_record_replay_is_active()) */ XBT_PUBLIC int MC_is_active(); -XBT_PUBLIC void MC_automaton_new_propositional_symbol_pointer(const char* id, int* value); - -XBT_PUBLIC void MC_ignore(void* addr, size_t size); -XBT_PUBLIC void MC_unignore(void* addr, size_t size); -XBT_PUBLIC void MC_ignore_heap(void* address, size_t size); -XBT_PUBLIC void MC_unignore_heap(void* address, size_t size); - SG_END_DECL #endif /* SIMGRID_MODELCHECKER_H */ diff --git a/include/simgrid/plugins/battery.hpp b/include/simgrid/plugins/battery.hpp index 7f0c3618ef..058428beb4 100644 --- a/include/simgrid/plugins/battery.hpp +++ b/include/simgrid/plugins/battery.hpp @@ -6,6 +6,7 @@ #ifndef SIMGRID_PLUGINS_BATTERY_HPP_ #define SIMGRID_PLUGINS_BATTERY_HPP_ +#include #include #include #include @@ -87,23 +88,24 @@ private: static std::shared_ptr battery_model_; std::string name_; - double nominal_charge_power_w_; - double nominal_discharge_power_w_; - double charge_efficiency_; - double discharge_efficiency_; - double initial_capacity_wh_; - double energy_budget_j_; - - std::map host_loads_ = {}; - std::map named_loads_ = {}; + double nominal_charge_power_w_ = -INFINITY; + double nominal_discharge_power_w_ = INFINITY; + double charge_efficiency_ = 1; + double discharge_efficiency_ = 1; + double initial_capacity_wh_ = 0; + double energy_budget_j_ = 0; + + std::map host_loads_ = {}; + std::map> named_loads_ = {}; std::vector> handlers_; - double capacity_wh_; - double energy_stored_j_; + double capacity_wh_ = 0; + double energy_stored_j_ = 0; double energy_provided_j_ = 0; double energy_consumed_j_ = 0; double last_updated_ = 0; + explicit Battery(); explicit Battery(const std::string& name, double state_of_charge, double nominal_charge_power_w, double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency, double initial_capacity_wh, int cycles); @@ -124,10 +126,12 @@ private: #endif public: + static BatteryPtr init(); static BatteryPtr init(const std::string& name, double state_of_charge, double nominal_charge_power_w, double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency, double initial_capacity_wh, int cycles); void set_load(const std::string& name, double power_w); + void set_load(const std::string& name, bool active); void connect_host(s4u::Host* host, bool active = true); double get_state_of_charge(); double get_state_of_health(); diff --git a/include/simgrid/plugins/chiller.hpp b/include/simgrid/plugins/chiller.hpp index b60e03dc82..8f9611bda6 100644 --- a/include/simgrid/plugins/chiller.hpp +++ b/include/simgrid/plugins/chiller.hpp @@ -68,6 +68,9 @@ private: friend void intrusive_ptr_add_ref(Chiller* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); } #endif + inline static xbt::signal on_power_change; + xbt::signal on_this_power_change; + public: static ChillerPtr init(const std::string& name, double air_mass_kg, double specific_heat_j_per_kg_per_c, double alpha, double cooling_efficiency, double initial_temp_c, double goal_temp_c, double max_power_w); @@ -93,9 +96,9 @@ public: double get_max_power() { return max_power_w_; } bool is_active() { return active_; } double get_temp_in() { return temp_in_c_; } - double get_temp_out() { return temp_out_c_; } double get_power() { return power_w_; } double get_energy_consumed() { return energy_consumed_j_; } + double get_time_to_goal_temp(); }; } // namespace simgrid::plugins diff --git a/include/simgrid/plugins/solar_panel.hpp b/include/simgrid/plugins/solar_panel.hpp index b9097b416f..0ba319c059 100644 --- a/include/simgrid/plugins/solar_panel.hpp +++ b/include/simgrid/plugins/solar_panel.hpp @@ -16,37 +16,18 @@ using SolarPanelPtr = boost::intrusive_ptr; XBT_PUBLIC void intrusive_ptr_release(SolarPanel* o); XBT_PUBLIC void intrusive_ptr_add_ref(SolarPanel* o); -class SolarPanelModel : public kernel::resource::Model { - std::vector solar_panels_; - -public: - explicit SolarPanelModel(); - - void add_solar_panel(SolarPanelPtr b); - void update_actions_state(double now, double delta) override; - double next_occurring_event(double now) override; -}; - class SolarPanel { - friend SolarPanelModel; - -private: - static std::shared_ptr solar_panel_model_; - std::string name_; double area_m2_; double conversion_efficiency_; double solar_irradiance_w_per_m2_; double min_power_w_; double max_power_w_; - - double power_w_ = 0; - double last_updated_ = 0; + double power_w_ = -1; explicit SolarPanel(std::string name, double area_m2, double conversion_efficiency, double solar_irradiance_w_per_m2, double min_power_w, double max_power_w); - static void init_plugin(); void update(); std::atomic_int_fast32_t refcount_{0}; @@ -61,6 +42,9 @@ private: friend void intrusive_ptr_add_ref(SolarPanel* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); } #endif + static xbt::signal on_power_change; + xbt::signal on_this_power_change; + public: static SolarPanelPtr init(const std::string& name, double area_m2, double conversion_efficiency, double solar_irradiance_w_per_m2, double min_power_w, double max_power_w); @@ -72,14 +56,20 @@ public: SolarPanelPtr set_min_power(double power_w); SolarPanelPtr set_max_power(double power_w); - std::string get_name() { return name_; } - const char* get_cname() { return name_.c_str(); } - double get_area() { return area_m2_; } - double get_conversion_efficiency() { return conversion_efficiency_; } - double get_solar_irradiance() { return solar_irradiance_w_per_m2_; } - double get_min_power() { return min_power_w_; } - double get_max_power() { return max_power_w_; } - double get_power() { return power_w_; } + std::string get_name() const { return name_; } + const char* get_cname() const { return name_.c_str(); } + double get_area() const { return area_m2_; } + double get_conversion_efficiency() const { return conversion_efficiency_; } + double get_solar_irradiance() const { return solar_irradiance_w_per_m2_; } + double get_min_power() const { return min_power_w_; } + double get_max_power() const { return max_power_w_; } + double get_power() const { return power_w_; } + + /** Add a callback fired after this solar panel power changed. */ + void on_this_power_change_cb(const std::function& func) { on_this_power_change.connect(func); }; + /** Add a callback fired after a solar panel power changed. + * Triggered after the on_this_power_change function.**/ + static void on_power_change_cb(const std::function& cb) { on_power_change.connect(cb); } }; } // namespace simgrid::plugins #endif diff --git a/include/simgrid/s4u.hpp b/include/simgrid/s4u.hpp index b2853229c2..8ddbf1aac3 100644 --- a/include/simgrid/s4u.hpp +++ b/include/simgrid/s4u.hpp @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/include/simgrid/s4u/Activity.hpp b/include/simgrid/s4u/Activity.hpp index ef51321b4b..8b9f48508d 100644 --- a/include/simgrid/s4u/Activity.hpp +++ b/include/simgrid/s4u/Activity.hpp @@ -38,6 +38,7 @@ class XBT_PUBLIC Activity : public xbt::Extendable { friend Comm; friend Exec; friend Io; + friend Mess; friend kernel::activity::ActivityImpl; friend std::vector create_DAG_from_dot(const std::string& filename); friend std::vector create_DAG_from_DAX(const std::string& filename); diff --git a/include/simgrid/s4u/Engine.hpp b/include/simgrid/s4u/Engine.hpp index d92987dfa5..fbef8cccc9 100644 --- a/include/simgrid/s4u/Engine.hpp +++ b/include/simgrid/s4u/Engine.hpp @@ -155,6 +155,7 @@ public: Link* link_by_name_or_null(const std::string& name) const; Mailbox* mailbox_by_name_or_create(const std::string& name) const; + MessageQueue* message_queue_by_name_or_create(const std::string& name) const; size_t get_actor_count() const; std::vector get_all_actors() const; diff --git a/include/simgrid/s4u/Mess.hpp b/include/simgrid/s4u/Mess.hpp new file mode 100644 index 0000000000..81dcee98ff --- /dev/null +++ b/include/simgrid/s4u/Mess.hpp @@ -0,0 +1,65 @@ +/* Copyright (c) 2023. 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 SIMGRID_S4U_MESS_HPP +#define SIMGRID_S4U_MESS_HPP + +#include +#include + +#include +#include + +namespace simgrid::s4u { + +class XBT_PUBLIC Mess : public Activity_T { +#ifndef DOXYGEN + friend MessageQueue; // Factory of messages + friend kernel::activity::MessImpl; +#endif + MessageQueue* queue_ = nullptr; + void* payload_ = nullptr; + size_t dst_buff_size_ = 0; + void* dst_buff_ = nullptr; + + Mess() = default; + Mess* do_start() override; + + static xbt::signal on_send; + xbt::signal on_this_send; + static xbt::signal on_recv; + xbt::signal on_this_recv; + + /* These ensure that the on_completion signals are really thrown */ + void fire_on_completion_for_real() const { Activity_T::fire_on_completion(); } + void fire_on_this_completion_for_real() const { Activity_T::fire_on_this_completion(); } + +public: +#ifndef DOXYGEN + Mess(Mess const&) = delete; + Mess& operator=(Mess const&) = delete; +#endif + + MessPtr set_queue(MessageQueue* queue); + MessageQueue* get_queue() const { return queue_; } + + /** Retrieve the payload associated to the communication. You can only do that once the comm is (gracefully) + * terminated */ + void* get_payload() const { return payload_; } + MessPtr set_payload(void* data); + MessPtr set_dst_data(void** buff, size_t size); + Actor* get_sender() const; + Actor* get_receiver() const; + + bool is_assigned() const override { return true; }; + + Mess* wait_for(double timeout) override; + + kernel::actor::ActorImpl* sender_ = nullptr; + kernel::actor::ActorImpl* receiver_ = nullptr; +}; +} // namespace simgrid::s4u + +#endif /* SIMGRID_S4U_MESS_HPP */ diff --git a/include/simgrid/s4u/MessageQueue.hpp b/include/simgrid/s4u/MessageQueue.hpp new file mode 100644 index 0000000000..dc00941216 --- /dev/null +++ b/include/simgrid/s4u/MessageQueue.hpp @@ -0,0 +1,112 @@ +/* Copyright (c) 2023. 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 SIMGRID_S4U_MESSAGEQUEUE_HPP +#define SIMGRID_S4U_MESSAGEQUEUE_HPP + +#include +#include +#include + +#include + +namespace simgrid::s4u { + +class XBT_PUBLIC MessageQueue { +#ifndef DOXYGEN + friend Mess; + friend kernel::activity::MessageQueueImpl; +#endif + + kernel::activity::MessageQueueImpl* const pimpl_; + + explicit MessageQueue(kernel::activity::MessageQueueImpl * mqueue) : pimpl_(mqueue) {} + ~MessageQueue() = default; + +protected: + kernel::activity::MessageQueueImpl* get_impl() const { return pimpl_; } + +public: + /** @brief Retrieves the name of that message queue as a C++ string */ + const std::string& get_name() const; + /** @brief Retrieves the name of that message queue as a C string */ + const char* get_cname() const; + + /** \static Retrieve the message queye associated to the given name. Message queues are created on demand. */ + static MessageQueue* by_name(const std::string& name); + + /** Returns whether the message queue contains queued messages */ + bool empty() const; + + /* Returns the number of queued messages */ + size_t size() const; + + /** Gets the first element in the queue (without dequeuing it), or nullptr if none is there */ + kernel::activity::MessImplPtr front() const; + + /** Creates (but don't start) a data transmission to that message queue */ + MessPtr put_init(); + /** Creates (but don't start) a data transmission to that message queue. + * + * Please note that if you send a pointer to some data, you must ensure that your data remains live until + * consumption, or the receiver will get a pointer to a garbled memory area. + */ + MessPtr put_init(void* payload); + /** Creates and start a data transmission to that mailbox. + * + * Please note that if you send a pointer to some data, you must ensure that your data remains live until + * consumption, or the receiver will get a pointer to a garbled memory area. + */ + MessPtr put_async(void* payload); + + /** Blocking data transmission. + * + * Please note that if you send a pointer to some data, you must ensure that your data remains live until + * consumption, or the receiver will get a pointer to a garbled memory area. + */ + void put(void* payload); + /** Blocking data transmission with timeout */ + void put(void* payload, double timeout); + + /** Creates (but don't start) a data reception onto that message queue. */ + MessPtr get_init(); + /** Creates and start an async data reception to that message queue */ + template MessPtr get_async(T** data); + /** Creates and start an async data reception to that mailbox. Since the data location is not provided, you'll have to + * use Mess::get_payload once the messaging operation terminates */ + MessPtr get_async(); + + /** Blocking data reception */ + template T* get(); + template std::unique_ptr get_unique() { return std::unique_ptr(get()); } + + /** Blocking data reception with timeout */ + template T* get(double timeout); + template std::unique_ptr get_unique(double timeout) { return std::unique_ptr(get(timeout)); } +}; + +template MessPtr MessageQueue::get_async(T** data) +{ + MessPtr res = get_init()->set_dst_data(reinterpret_cast(data), sizeof(void*)); + res->start(); + return res; +} + +template T* MessageQueue::get() +{ + T* res = nullptr; + get_async(&res)->wait(); + return res; +} + +template T* MessageQueue::get(double timeout) +{ + T* res = nullptr; + get_async(&res)->wait_for(timeout); + return res; +} +} // namespace simgrid::s4u + +#endif /* SIMGRID_S4U_MESSAGEQUEUE_HPP */ diff --git a/include/simgrid/s4u/Mutex.hpp b/include/simgrid/s4u/Mutex.hpp index 7791cd7e23..06f04c2aa5 100644 --- a/include/simgrid/s4u/Mutex.hpp +++ b/include/simgrid/s4u/Mutex.hpp @@ -12,6 +12,8 @@ namespace simgrid::s4u { /** @brief A classical mutex, but blocking in the simulation world. + * + * S4U mutexes are not recursive. If an actor tries to lock the same object twice, it deadlocks with itself. * * @beginrst * It is strictly impossible to use a real mutex, such as @@ -48,7 +50,8 @@ class XBT_PUBLIC Mutex { public: /** \static Constructs a new mutex */ - static MutexPtr create(); + static MutexPtr create(bool recursive = false); + void lock(); void unlock(); bool try_lock(); diff --git a/include/smpi/smpi.h b/include/smpi/smpi.h index 453a6ef0e8..84cd4ceb11 100644 --- a/include/smpi/smpi.h +++ b/include/smpi/smpi.h @@ -1123,7 +1123,16 @@ MPI_CALL(XBT_PUBLIC int, MPI_Ineighbor_alltoallw, const MPI_Aint* recvdisps, const MPI_Datatype* recvtypes, MPI_Comm comm, MPI_Request *request)); MPI_CALL(XBT_PUBLIC int, MPI_Status_f2c, (MPI_Fint *f_status, MPI_Status *c_status)); MPI_CALL(XBT_PUBLIC int, MPI_Status_c2f, (MPI_Status *c_status, MPI_Fint *f_status)); - +MPI_CALL(XBT_PUBLIC int, MPI_Parrived, (MPI_Request request, int partition, int *flag)); +MPI_CALL(XBT_PUBLIC int, MPI_Pready, (int partitions, MPI_Request request)); +MPI_CALL(XBT_PUBLIC int, MPI_Pready_range, (int partition_low, int partition_high, MPI_Request request)); +MPI_CALL(XBT_PUBLIC int, MPI_Pready_list, (int length, int partition_list[], MPI_Request request)); +MPI_CALL(XBT_PUBLIC int, MPI_Precv_init, (void* buf, int partitions, MPI_Count count, + MPI_Datatype datatype, int source, int tag, MPI_Comm comm, + MPI_Info info, MPI_Request *request)); +MPI_CALL(XBT_PUBLIC int, MPI_Psend_init, (const void* buf, int partitions, MPI_Count count, + MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, + MPI_Info info, MPI_Request *request)); //FIXME: End of all the not yet implemented stuff diff --git a/include/smpi/smpi_extended_traces.h b/include/smpi/smpi_extended_traces.h index aa3d055671..1e1fefb901 100644 --- a/include/smpi/smpi_extended_traces.h +++ b/include/smpi/smpi_extended_traces.h @@ -394,3 +394,13 @@ #define MPI_Ineighbor_alltoallw(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Ineighbor_alltoallw"), MPI_Ineighbor_alltoallw(__VA_ARGS__)) #define MPI_Status_f2c(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Status_f2c"), MPI_Status_f2c(__VA_ARGS__)) #define MPI_Status_c2f(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Status_c2f"), MPI_Status_c2f(__VA_ARGS__)) +#define MPI_Parrived(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Parrived"), MPI_Parrived(__VA_ARGS__)) +#define MPI_Pready(...) (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Pready"), MPI_Pready(__VA_ARGS__)) +#define MPI_Pready_range(...) \ + (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Pready_range"), MPI_Pready_range(__VA_ARGS__)) +#define MPI_Pready_list(...) \ + (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Pready_list"), MPI_Pready_list(__VA_ARGS__)) +#define MPI_Precv_init(...) \ + (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Precv_init"), MPI_Precv_init(__VA_ARGS__)) +#define MPI_Psend_init(...) \ + (smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_Psend_init"), MPI_Psend_init(__VA_ARGS__)) diff --git a/include/smpi/smpi_extended_traces_fortran.h b/include/smpi/smpi_extended_traces_fortran.h index be47ad104e..4684b6b61f 100644 --- a/include/smpi/smpi_extended_traces_fortran.h +++ b/include/smpi/smpi_extended_traces_fortran.h @@ -781,3 +781,39 @@ #define MPI_STATUS_F2C smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_STATUS_F2C"); call MPI_Status_f2c #define mpi_status_c2f smpi_trace_set_call_location(__FILE__,__LINE__,"mpi_status_c2f"); call MPI_Status_c2f #define MPI_STATUS_C2F smpi_trace_set_call_location(__FILE__,__LINE__,"MPI_STATUS_C2F"); call MPI_Status_c2f +#define mpi_parrived \ + smpi_trace_set_call_location(__FILE__, __LINE__, "mpi_parrived"); \ + call MPI_Parrived +#define MPI_PARRIVED \ + smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_PARRIVED"); \ + call MPI_Parrived +#define mpi_pready \ + smpi_trace_set_call_location(__FILE__, __LINE__, "mpi_pready"); \ + call MPI_Pready +#define MPI_PREADY \ + smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_PREADY"); \ + call MPI_Pready +#define mpi_pready_range \ + smpi_trace_set_call_location(__FILE__, __LINE__, "mpi_pready_range"); \ + call MPI_Pready_range +#define MPI_PREADY_RANGE \ + smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_PREADY_RANGE"); \ + call MPI_Pready_range +#define mpi_pready_list \ + smpi_trace_set_call_location(__FILE__, __LINE__, "mpi_pready_list"); \ + call MPI_Pready_list +#define MPI_PREADY_LIST \ + smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_PREADY_LIST"); \ + call MPI_Pready_list +#define mpi_precv_init \ + smpi_trace_set_call_location(__FILE__, __LINE__, "mpi_precv_init"); \ + call MPI_Precv_init +#define MPI_PRECV_INIT \ + smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_PRECV_INIT"); \ + call MPI_Precv_init +#define mpi_psend_init \ + smpi_trace_set_call_location(__FILE__, __LINE__, "mpi_psend_init"); \ + call MPI_Psend_init +#define MPI_PSEND_INIT \ + smpi_trace_set_call_location(__FILE__, __LINE__, "MPI_PSEND_INIT"); \ + call MPI_Psend_init diff --git a/include/xbt/automaton.h b/include/xbt/automaton.h deleted file mode 100644 index 582b2fdee3..0000000000 --- a/include/xbt/automaton.h +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright (c) 2011-2023. 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 XBT_AUTOMATON_H -#define XBT_AUTOMATON_H - -#include - -SG_BEGIN_DECL - -typedef struct xbt_automaton_state { - char* id; - int type; /* -1 = init, 0 = inter, 1 = final */ - xbt_dynar_t in; - xbt_dynar_t out; -} s_xbt_automaton_state; - -typedef struct xbt_automaton_state* xbt_automaton_state_t; -typedef const struct xbt_automaton_state* const_xbt_automaton_state_t; - -typedef struct xbt_automaton { - xbt_dynar_t propositional_symbols; - xbt_dynar_t transitions; - xbt_dynar_t states; - xbt_automaton_state_t current_state; -} s_xbt_automaton; - -typedef struct xbt_automaton* xbt_automaton_t; -typedef const struct xbt_automaton* const_xbt_automaton_t; - -typedef struct xbt_automaton_exp_label{ - enum{AUT_OR=0, AUT_AND=1, AUT_NOT=2, AUT_PREDICAT=3, AUT_ONE=4} type; - union{ - struct{ - struct xbt_automaton_exp_label* left_exp; - struct xbt_automaton_exp_label* right_exp; - }or_and; - struct xbt_automaton_exp_label* exp_not; - char* predicat; - }u; -} s_xbt_automaton_exp_label; - -typedef struct xbt_automaton_exp_label* xbt_automaton_exp_label_t; -typedef const struct xbt_automaton_exp_label* const_xbt_automaton_exp_label_t; - -typedef struct xbt_automaton_transition { - xbt_automaton_state_t src; - xbt_automaton_state_t dst; - xbt_automaton_exp_label_t label; -} s_xbt_automaton_transition; - -typedef struct xbt_automaton_transition* xbt_automaton_transition_t; -typedef const struct xbt_automaton_transition* const_xbt_automaton_transition_t; - -typedef struct xbt_automaton_propositional_symbol* xbt_automaton_propositional_symbol_t; -typedef const struct xbt_automaton_propositional_symbol* const_xbt_automaton_propositional_symbol_t; - -typedef int (*xbt_automaton_propositional_symbol_callback_type)(void*); -typedef void (*xbt_automaton_propositional_symbol_free_function_type)(void*); - -XBT_PUBLIC xbt_automaton_t xbt_automaton_new(void); -XBT_PUBLIC void xbt_automaton_load(xbt_automaton_t automaton, const char* file); -XBT_PUBLIC xbt_automaton_state_t xbt_automaton_state_new(const_xbt_automaton_t a, int type, const char* id); -XBT_PUBLIC xbt_automaton_transition_t xbt_automaton_transition_new(const_xbt_automaton_t a, xbt_automaton_state_t src, - xbt_automaton_state_t dst, - xbt_automaton_exp_label_t label); -XBT_PUBLIC xbt_automaton_exp_label_t xbt_automaton_exp_label_new_or(xbt_automaton_exp_label_t left, - xbt_automaton_exp_label_t right); -XBT_PUBLIC xbt_automaton_exp_label_t xbt_automaton_exp_label_new_and(xbt_automaton_exp_label_t left, - xbt_automaton_exp_label_t right); -XBT_PUBLIC xbt_automaton_exp_label_t xbt_automaton_exp_label_new_not(xbt_automaton_exp_label_t exp_not); -XBT_PUBLIC xbt_automaton_exp_label_t xbt_automaton_exp_label_new_predicat(const char* p); -XBT_PUBLIC xbt_automaton_exp_label_t xbt_automaton_exp_label_new_one(void); -XBT_PUBLIC xbt_dynar_t xbt_automaton_get_states(const_xbt_automaton_t a); -XBT_PUBLIC xbt_dynar_t xbt_automaton_get_transitions(const_xbt_automaton_t a); -XBT_PUBLIC xbt_automaton_transition_t xbt_automaton_get_transition(const_xbt_automaton_t a, - const_xbt_automaton_state_t src, - const_xbt_automaton_state_t dst); -XBT_PUBLIC xbt_automaton_state_t xbt_automaton_transition_get_source(const_xbt_automaton_transition_t t); -XBT_PUBLIC xbt_automaton_state_t xbt_automaton_transition_get_destination(const_xbt_automaton_transition_t t); -XBT_PUBLIC void xbt_automaton_transition_set_source(xbt_automaton_transition_t t, xbt_automaton_state_t src); -XBT_PUBLIC void xbt_automaton_transition_set_destination(xbt_automaton_transition_t t, xbt_automaton_state_t dst); -XBT_PUBLIC xbt_dynar_t xbt_automaton_state_get_out_transitions(const_xbt_automaton_state_t s); -XBT_PUBLIC xbt_dynar_t xbt_automaton_state_get_in_transitions(const_xbt_automaton_state_t s); -XBT_PUBLIC xbt_automaton_state_t xbt_automaton_state_exists(const_xbt_automaton_t a, const char* id); -XBT_PUBLIC void xbt_automaton_display(const_xbt_automaton_t a); -XBT_PUBLIC void xbt_automaton_exp_label_display(const_xbt_automaton_exp_label_t l); - -// xbt_automaton_propositional_symbol constructors: -XBT_PUBLIC xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new(const_xbt_automaton_t a, - const char* id, - int (*fct)(void)); -XBT_PUBLIC xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new_pointer(const_xbt_automaton_t a, - const char* id, - int* value); -XBT_PUBLIC xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new_callback( - const_xbt_automaton_t a, const char* id, xbt_automaton_propositional_symbol_callback_type callback, void* data, - xbt_automaton_propositional_symbol_free_function_type free_function); - -// xbt_automaton_propositional_symbol accessors: -XBT_PUBLIC xbt_automaton_propositional_symbol_callback_type -xbt_automaton_propositional_symbol_get_callback(const_xbt_automaton_propositional_symbol_t symbol); -XBT_PUBLIC void* xbt_automaton_propositional_symbol_get_data(const_xbt_automaton_propositional_symbol_t symbol); -XBT_PUBLIC const char* xbt_automaton_propositional_symbol_get_name(const_xbt_automaton_propositional_symbol_t symbol); - -// xbt_automaton_propositional_symbol methods! -XBT_PUBLIC int xbt_automaton_propositional_symbol_evaluate(const_xbt_automaton_propositional_symbol_t symbol); - -XBT_PUBLIC xbt_automaton_state_t xbt_automaton_get_current_state(const_xbt_automaton_t a); -XBT_PUBLIC int xbt_automaton_state_compare(const_xbt_automaton_state_t s1, const_xbt_automaton_state_t s2); -XBT_PUBLIC int xbt_automaton_propositional_symbols_compare_value(const_xbt_dynar_t s1, const_xbt_dynar_t s2); -XBT_PUBLIC int xbt_automaton_transition_compare(const_xbt_automaton_transition_t t1, - const_xbt_automaton_transition_t t2); -XBT_PUBLIC int xbt_automaton_exp_label_compare(const_xbt_automaton_exp_label_t l1, const_xbt_automaton_exp_label_t l2); -XBT_PUBLIC void xbt_automaton_state_free_voidp(void* s); -XBT_PUBLIC void xbt_automaton_state_free(xbt_automaton_state_t s); -XBT_PUBLIC void xbt_automaton_transition_free_voidp(void* t); -XBT_PUBLIC void xbt_automaton_exp_label_free_voidp(void* e); -XBT_PUBLIC void xbt_automaton_propositional_symbol_free_voidp(void* ps); -XBT_PUBLIC void xbt_automaton_free(xbt_automaton_t a); - -SG_END_DECL - -#endif diff --git a/include/xbt/automaton.hpp b/include/xbt/automaton.hpp deleted file mode 100644 index 18a7d6b693..0000000000 --- a/include/xbt/automaton.hpp +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (c) 2015-2023. 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 XBT_AUTOMATON_HPP -#define XBT_AUTOMATON_HPP - -#include - -#include - -namespace simgrid::xbt { - -/** Add a proposition to an automaton (the C++ way) - * - * This API hides all the callback and dynamic allocation hell from - * the used which can use C++ style functors and lambda expressions. - */ -template xbt_automaton_propositional_symbol_t add_proposition(const_xbt_automaton_t a, const char* id, F f) -{ - auto* callback = new F(std::move(f)); - return xbt_automaton_propositional_symbol_new_callback( - a, id, [](auto* cb) -> int { return (*(F*)cb)(); }, callback, [](auto* cb) -> void { delete (F*)cb; }); -} - -} // namespace simgrid::xbt -#endif diff --git a/sonar-project.properties b/sonar-project.properties index 03c0472747..a6d28f5ce8 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -127,13 +127,13 @@ sonar.issue.ignore.multicriteria.s5.ruleKey=cpp:S995 sonar.issue.ignore.multicriteria.s5.resourceKey=src/smpi/bindings/*.cpp # Exclude some files from the analysis: -# - the tests that we borrowed elsewhere (MPICH and MBI) +# - the tests that we borrowed elsewhere (MPICH, MBI, McMini) # - Flex-generated files # - Collectives that we borrowed elsewhere (mpich, openMPI and other implems) # - the NAS, that are included in our examples # - The Catch2 library, that is included in our unit tests # - The xxHash library, used by the MC -sonar.exclusions=src/3rd-party/*,teshsuite/smpi/mpich3-test/**,teshsuite/smpi/MBI/**,**/*_dtd.c,**/*_dtd.h,**/*yy.c,src/xbt/automaton/parserPromela.tab.*,src/smpi/colls/**/*,examples/smpi/NAS/*,examples/smpi/gemm/gemm.c +sonar.exclusions=src/3rd-party/*,teshsuite/smpi/mpich3-test/**,teshsuite/smpi/MBI/**,teshsuite/mc/mcmini/**,**/*_dtd.c,**/*_dtd.h,**/*yy.c,src/smpi/colls/**/*,examples/smpi/NAS/*,examples/smpi/gemm/gemm.c # Exclude our examples from the duplication detection. # Examples are expected to be somehow repetitive diff --git a/src/bindings/python/simgrid_python.cpp b/src/bindings/python/simgrid_python.cpp index 2f2ef70bec..53065f0a72 100644 --- a/src/bindings/python/simgrid_python.cpp +++ b/src/bindings/python/simgrid_python.cpp @@ -750,7 +750,8 @@ PYBIND11_MODULE(simgrid, m) py::class_(m, "Mutex", "A classical mutex, but blocking in the simulation world." "See the C++ documentation for details.") - .def(py::init<>(&Mutex::create), py::call_guard(), "Mutex constructor.") + .def(py::init<>(&Mutex::create), py::call_guard(), + "Mutex constructor (pass True as a parameter to get a recursive Mutex).", py::arg("recursive") = false) .def("lock", &Mutex::lock, py::call_guard(), "Block until the mutex is acquired.") .def("try_lock", &Mutex::try_lock, py::call_guard(), "Try to acquire the mutex. Return true if the mutex was acquired, false otherwise.") diff --git a/src/internal_config.h.in b/src/internal_config.h.in index b2ecf6efcb..59761d5c5b 100644 --- a/src/internal_config.h.in +++ b/src/internal_config.h.in @@ -59,8 +59,6 @@ #define PTH_STACKGROWTH @PTH_STACKGROWTH@ /* MC variables */ -/* Did we compile mmalloc in? */ -#cmakedefine01 HAVE_MMALLOC /* process_vm_readv: transfer data between process address spaces */ #cmakedefine01 HAVE_PROCESS_VM_READV @@ -82,8 +80,6 @@ /* Other function checks */ /* Function dlfunc */ #cmakedefine01 HAVE_DLFUNC -/* Function mmap */ -#cmakedefine01 HAVE_MMAP /* Function mremap */ #cmakedefine01 HAVE_MREMAP /* Function vasprintf */ diff --git a/src/kernel/EngineImpl.cpp b/src/kernel/EngineImpl.cpp index 9fa412e6ad..8b7b60a0cd 100644 --- a/src/kernel/EngineImpl.cpp +++ b/src/kernel/EngineImpl.cpp @@ -155,6 +155,9 @@ EngineImpl::~EngineImpl() for (auto const& [_, mailbox] : mailboxes_) delete mailbox; + for (auto const& [_, queue] : mqueues_) + delete queue; + /* Kill all actors (but maestro) */ maestro_->kill_all(); run_all_actors(); @@ -453,6 +456,9 @@ void EngineImpl::display_all_actor_status() const if (boost::dynamic_pointer_cast(actor->waiting_synchro_) != nullptr) synchro_description = "communication"; + if (boost::dynamic_pointer_cast(actor->waiting_synchro_) != nullptr) + synchro_description = "message"; + if (boost::dynamic_pointer_cast(actor->waiting_synchro_) != nullptr) synchro_description = "sleeping"; diff --git a/src/kernel/EngineImpl.hpp b/src/kernel/EngineImpl.hpp index 4c25e54720..149c0c2a36 100644 --- a/src/kernel/EngineImpl.hpp +++ b/src/kernel/EngineImpl.hpp @@ -16,6 +16,7 @@ #include "src/kernel/activity/ExecImpl.hpp" #include "src/kernel/activity/IoImpl.hpp" #include "src/kernel/activity/MailboxImpl.hpp" +#include "src/kernel/activity/MessageQueueImpl.hpp" #include "src/kernel/activity/SleepImpl.hpp" #include "src/kernel/activity/Synchro.hpp" #include "src/kernel/actor/ActorImpl.hpp" @@ -33,6 +34,7 @@ namespace simgrid::kernel { class EngineImpl { std::unordered_map netpoints_; std::unordered_map mailboxes_; + std::unordered_map mqueues_; std::unordered_map registered_functions; // Maps function names to actor code actor::ActorCodeFactory default_function; // Function to use as a fallback when the provided name matches nothing diff --git a/src/kernel/activity/CommImpl.cpp b/src/kernel/activity/CommImpl.cpp index 25a76617e4..72f114d072 100644 --- a/src/kernel/activity/CommImpl.cpp +++ b/src/kernel/activity/CommImpl.cpp @@ -23,17 +23,6 @@ namespace simgrid::kernel::activity { unsigned CommImpl::next_id_ = 0; -/* In stateful MC, we need to ignore some private memory that is not relevant to the application state */ -void CommImpl::setup_mc() -{ - MC_ignore(&CommImpl::next_id_, sizeof(CommImpl::next_id_)); -} - -CommImpl::CommImpl() -{ - MC_ignore((void*)&id_, sizeof(id_)); -} - std::function CommImpl::copy_data_callback_ = [](kernel::activity::CommImpl* comm, void* buff, size_t buff_size) { xbt_assert((buff_size == sizeof(void*)), "Cannot copy %zu bytes: must be sizeof(void*)", buff_size); @@ -124,8 +113,6 @@ CommImpl::~CommImpl() } else if (mbox_) { mbox_->remove(this); } - - MC_unignore((void*)&id_, sizeof(id_)); } /** @brief Starts the simulation of a communication synchro. */ diff --git a/src/kernel/activity/CommImpl.hpp b/src/kernel/activity/CommImpl.hpp index f3d98399ca..4f249a4bbf 100644 --- a/src/kernel/activity/CommImpl.hpp +++ b/src/kernel/activity/CommImpl.hpp @@ -36,7 +36,7 @@ class XBT_PUBLIC CommImpl : public ActivityImpl_T { const unsigned id_ = ++next_id_; // ID of this comm (for MC) -- 0 as an ID denotes "invalid/unknown comm" public: - CommImpl(); + CommImpl() = default; static void set_copy_data_callback(const std::function& callback); @@ -83,9 +83,6 @@ looking if a given communication matches my needs. For that, myself must match t expectations of the other side, too. See */ std::function copy_data_fun; - /* In stateful MC, we need to ignore some private memory that is not relevant to the application state */ - static void setup_mc(); - /* Model actions */ timeout_action_type src_timeout_{nullptr, [](resource::Action* a) { a->unref(); }}; /* timeout set by the sender */ timeout_action_type dst_timeout_{nullptr, [](resource::Action* a) { a->unref(); }}; /* timeout set by the receiver */ diff --git a/src/kernel/activity/MailboxImpl.hpp b/src/kernel/activity/MailboxImpl.hpp index d37e756f1f..172bda4cee 100644 --- a/src/kernel/activity/MailboxImpl.hpp +++ b/src/kernel/activity/MailboxImpl.hpp @@ -6,6 +6,7 @@ #ifndef SIMGRID_KERNEL_ACTIVITY_MAILBOX_HPP #define SIMGRID_KERNEL_ACTIVITY_MAILBOX_HPP +#include "simgrid/config.h" /* FIXME: KILLME. This makes the ABI config-dependent, but mandatory for the hack below */ #include "simgrid/s4u/Engine.hpp" #include "simgrid/s4u/Mailbox.hpp" #include "src/kernel/activity/CommImpl.hpp" @@ -19,6 +20,7 @@ class MailboxImpl { s4u::Mailbox piface_; std::string name_; actor::ActorImplPtr permanent_receiver_; // actor to which the mailbox is attached + std::deque comm_queue_; // messages already received in the permanent receive mode std::deque done_comm_queue_; diff --git a/src/kernel/activity/MessImpl.cpp b/src/kernel/activity/MessImpl.cpp new file mode 100644 index 0000000000..28679c2a4b --- /dev/null +++ b/src/kernel/activity/MessImpl.cpp @@ -0,0 +1,187 @@ +/* Copyright (c) 2023. 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 "src/kernel/EngineImpl.hpp" +#include "src/kernel/activity/MessImpl.hpp" +#include "src/kernel/activity/MessageQueueImpl.hpp" + +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_mess, kernel, "Kernel message synchronization"); + +namespace simgrid::kernel::activity { + +MessImpl::~MessImpl() +{ + if (queue_) + queue_->remove(this); +} + +MessImpl& MessImpl::set_type(MessImplType type) +{ + type_ = type; + return *this; +} + +MessImpl& MessImpl::set_queue(MessageQueueImpl* queue) +{ + queue_ = queue; + return *this; +} + +MessImpl& MessImpl::set_payload(void* payload) +{ + payload_ = payload; + return *this; +} + +MessImpl& MessImpl::set_dst_buff(unsigned char* buff, size_t* size) +{ + dst_buff_ = buff; + dst_buff_size_ = size; + return *this; +} + +MessImpl* MessImpl::start() +{ + if (get_state() == State::READY) { + XBT_DEBUG("Starting message exchange %p from '%s' to '%s' (state: %s)", this, src_actor_->get_host()->get_cname(), + dst_actor_->get_host()->get_cname(), get_state_str()); + set_state(State::RUNNING); + finish(); + } + return this; +} + +ActivityImplPtr MessImpl::iput(actor::MessIputSimcall* observer) +{ + auto* queue = observer->get_queue(); + XBT_DEBUG("put from message queue %p", queue); + + /* Prepare a synchro describing us, so that it gets passed to the user-provided filter of other side */ + MessImplPtr this_mess(new MessImpl()); + this_mess->set_type(MessImplType::PUT); + + /* Look for message synchro matching our needs. + * + * If it is not found then push our communication into the rendez-vous point */ + MessImplPtr other_mess = queue->find_matching_message(MessImplType::GET); + + if (not other_mess) { + other_mess = std::move(this_mess); + queue->push(other_mess); + } else { + XBT_DEBUG("Get already pushed"); + other_mess->set_state(State::READY); + } + + observer->set_message(other_mess.get()); + observer->get_issuer()->activities_.insert(other_mess); + + /* Setup synchro */ + other_mess->src_actor_ = observer->get_issuer(); + other_mess->payload_ = observer->get_payload(); + other_mess->start(); + + return other_mess; +} + +ActivityImplPtr MessImpl::iget(actor::MessIgetSimcall* observer) +{ + MessImplPtr this_mess(new MessImpl()); + this_mess->set_type(MessImplType::GET); + + auto* queue = observer->get_queue(); + XBT_DEBUG("get from message queue %p. this_synchro=%p", queue, this_mess.get()); + + MessImplPtr other_mess = queue->find_matching_message(MessImplType::PUT); + + if (other_mess == nullptr) { + XBT_DEBUG("Get pushed first (%zu comm enqueued so far)", queue->size()); + other_mess = std::move(this_mess); + queue->push(other_mess); + } else { + XBT_DEBUG("Match my %p with the existing %p", this_mess.get(), other_mess.get()); + + other_mess->set_state(State::READY); + } + + observer->get_issuer()->activities_.insert(other_mess); + observer->set_message(other_mess.get()); + + /* Setup synchro */ + other_mess->set_dst_buff(observer->get_dst_buff(), observer->get_dst_buff_size()); + other_mess->dst_actor_ = observer->get_issuer(); + + other_mess->start(); + + return other_mess; +} + +void MessImpl::wait_for(actor::ActorImpl* issuer, double timeout) +{ + XBT_DEBUG("MessImpl::wait_for(%g), %p, state %s", timeout, this, get_state_str()); + + /* Associate this simcall to the wait synchro */ + register_simcall(&issuer->simcall_); + ActivityImpl::wait_for(issuer, timeout); +} + +void MessImpl::finish() +{ + XBT_DEBUG("MessImpl::finish() comm %p, state %s, src_proc %p, dst_proc %p", this, get_state_str(), + src_actor_.get(), dst_actor_.get()); + + if (get_iface()) { + const auto& piface = static_cast(*get_iface()); + set_iface(nullptr); // reset iface to protect against multiple trigger of the on_completion signals + piface.fire_on_completion_for_real(); + piface.fire_on_this_completion_for_real(); + } + + /* Update synchro state */ + if (get_state() == State::RUNNING) { + set_state(State::DONE); + } + + /* If the synchro is still in a rendez-vous point then remove from it */ + if (queue_) + queue_->remove(this); + + if (get_state() == State::DONE && payload_ != nullptr) + *(void**)(dst_buff_) = payload_; + + while (not simcalls_.empty()) { + actor::Simcall* simcall = simcalls_.front(); + simcalls_.pop_front(); + + /* If a waitany simcall is waiting for this synchro to finish, then remove it from the other synchros in the waitany + * list. Afterwards, get the position of the actual synchro in the waitany list and return it as the result of the + * simcall */ + + if (simcall->call_ == actor::Simcall::Type::NONE) // FIXME: maybe a better way to handle this case + continue; // if actor handling comm is killed + + handle_activity_waitany(simcall); + + /* Check out for errors */ + + if (not simcall->issuer_->get_host()->is_on()) { + simcall->issuer_->set_wannadie(); + } else { + // Do not answer to dying actors + if (not simcall->issuer_->wannadie()) { + set_exception(simcall->issuer_); + simcall->issuer_->simcall_answer(); + } + } + + simcall->issuer_->waiting_synchro_ = nullptr; + simcall->issuer_->activities_.erase(this); + } +} + +} // namespace simgrid::kernel::activity diff --git a/src/kernel/activity/MessImpl.hpp b/src/kernel/activity/MessImpl.hpp new file mode 100644 index 0000000000..fad011c7b1 --- /dev/null +++ b/src/kernel/activity/MessImpl.hpp @@ -0,0 +1,50 @@ +/* Copyright (c) 2023. 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 SIMGRID_KERNEL_ACTIVITY_MESS_HPP +#define SIMGRID_KERNEL_ACTIVITY_MESS_HPP + +#include "src/kernel/activity/ActivityImpl.hpp" +#include "src/kernel/actor/ActorImpl.hpp" +#include "src/kernel/actor/CommObserver.hpp" + +namespace simgrid::kernel::activity { + +enum class MessImplType { PUT, GET }; + +class XBT_PUBLIC MessImpl : public ActivityImpl_T { + ~MessImpl() override; + + MessageQueueImpl* queue_ = nullptr; + void* payload_ = nullptr; + MessImplType type_ = MessImplType::PUT; + unsigned char* dst_buff_ = nullptr; + size_t* dst_buff_size_ = nullptr; + +public: + MessImpl& set_type(MessImplType type); + MessImplType get_type() const { return type_; } + MessImpl& set_payload(void* payload); + void* get_payload() { return payload_; } + + MessImpl& set_queue(MessageQueueImpl* queue); + MessageQueueImpl* get_queue() const { return queue_; } + MessImpl& set_dst_buff(unsigned char* buff, size_t* size); + + static ActivityImplPtr iput(actor::MessIputSimcall* observer); + static ActivityImplPtr iget(actor::MessIgetSimcall* observer); + + void wait_for(actor::ActorImpl* issuer, double timeout) override; + + MessImpl* start(); + void set_exception(actor::ActorImpl* issuer) override {}; + void finish() override; + + actor::ActorImplPtr src_actor_ = nullptr; + actor::ActorImplPtr dst_actor_ = nullptr; +}; +} // namespace simgrid::kernel::activity + +#endif diff --git a/src/kernel/activity/MessageQueueImpl.cpp b/src/kernel/activity/MessageQueueImpl.cpp new file mode 100644 index 0000000000..714f86bdd6 --- /dev/null +++ b/src/kernel/activity/MessageQueueImpl.cpp @@ -0,0 +1,54 @@ +/* Copyright (c) 2023. 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 "src/kernel/activity/MessageQueueImpl.hpp" + +#include + +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_mq, kernel, "Message queue implementation"); + +namespace simgrid::kernel::activity { + +unsigned MessageQueueImpl::next_id_ = 0; + +void MessageQueueImpl::push(const MessImplPtr& mess) +{ + mess->set_queue(this); + this->queue_.push_back(std::move(mess)); +} + +void MessageQueueImpl::remove(const MessImplPtr& mess) +{ + xbt_assert(mess->get_queue() == this, "Message %p is in queue %s, not queue %s", mess.get(), + (mess->get_queue() ? mess->get_queue()->get_cname() : "(null)"), get_cname()); + + mess->set_queue(nullptr); + auto it = std::find(queue_.begin(), queue_.end(), mess); + if (it != queue_.end()) + queue_.erase(it); + else + xbt_die("Message %p not found in queue %s", mess.get(), get_cname()); +} + +MessImplPtr MessageQueueImpl::find_matching_message(MessImplType type) +{ + auto iter = std::find_if(queue_.begin(), queue_.end(), [&type](const MessImplPtr& mess) + { + return (mess->get_type() == type); + }); + if (iter == queue_.end()) { + XBT_DEBUG("No matching message synchro found"); + return nullptr; + } + + const MessImplPtr& mess = *iter; + XBT_DEBUG("Found a matching message synchro %p", mess.get()); + mess->set_queue(nullptr); + MessImplPtr mess_cpy = mess; + queue_.erase(iter); + return mess_cpy; +} + +} // namespace simgrid::kernel::activity diff --git a/src/kernel/activity/MessageQueueImpl.hpp b/src/kernel/activity/MessageQueueImpl.hpp new file mode 100644 index 0000000000..4bc010f956 --- /dev/null +++ b/src/kernel/activity/MessageQueueImpl.hpp @@ -0,0 +1,52 @@ +/* Copyright (c) 2023. 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 SIMGRID_KERNEL_ACTIVITY_MESSAGEQUEUE_HPP +#define SIMGRID_KERNEL_ACTIVITY_MESSAGEQUEUE_HPP + +#include "simgrid/s4u/Engine.hpp" +#include "simgrid/s4u/MessageQueue.hpp" +#include "src/kernel/activity/MessImpl.hpp" + +namespace simgrid::kernel::activity { + +/** @brief Implementation of the s4u::MessageQueue */ + +class MessageQueueImpl { + s4u::MessageQueue piface_; + std::string name_; + std::deque queue_; + + friend s4u::Engine; + friend s4u::MessageQueue; + friend s4u::MessageQueue* s4u::Engine::message_queue_by_name_or_create(const std::string& name) const; + friend s4u::MessageQueue* s4u::MessageQueue::by_name(const std::string& name); + + static unsigned next_id_; // Next ID to be given + const unsigned id_ = next_id_++; + explicit MessageQueueImpl(const std::string& name) : piface_(this), name_(name) {} + MessageQueueImpl(const MailboxImpl&) = delete; + MessageQueueImpl& operator=(const MailboxImpl&) = delete; + +public: + /** @brief Public interface */ + unsigned get_id() const { return id_; } + + const s4u::MessageQueue* get_iface() const { return &piface_; } + s4u::MessageQueue* get_iface() { return &piface_; } + + const std::string& get_name() const { return name_; } + const char* get_cname() const { return name_.c_str(); } + void push(const MessImplPtr& mess); + void remove(const MessImplPtr& mess); + bool empty() const { return queue_.empty(); } + size_t size() const { return queue_.size(); } + const MessImplPtr& front() const { return queue_.front(); } + + MessImplPtr find_matching_message(MessImplType type); +}; +} // namespace simgrid::kernel::activity + +#endif diff --git a/src/kernel/activity/MutexImpl.cpp b/src/kernel/activity/MutexImpl.cpp index 43a511b9d3..c981c3ee76 100644 --- a/src/kernel/activity/MutexImpl.cpp +++ b/src/kernel/activity/MutexImpl.cpp @@ -47,13 +47,41 @@ unsigned MutexImpl::next_id_ = 0; MutexAcquisitionImplPtr MutexImpl::lock_async(actor::ActorImpl* issuer) { - auto res = MutexAcquisitionImplPtr(new kernel::activity::MutexAcquisitionImpl(issuer, this), true); - - if (owner_ != nullptr) { - /* Somebody is using the mutex; register the acquisition */ + /* If the mutex is recursive */ + if (is_recursive_) { + if (owner_ == issuer) { + recursive_depth++; + auto res = MutexAcquisitionImplPtr(new kernel::activity::MutexAcquisitionImpl(issuer, this), true); + res->grant(); + return res; + } else if (owner_ == nullptr) { // Free + owner_ = issuer; + recursive_depth = 1; + auto res = MutexAcquisitionImplPtr(new kernel::activity::MutexAcquisitionImpl(issuer, this), true); + res->grant(); + return res; + } + + for (auto acq : ongoing_acquisitions_) + if (acq->get_issuer() == issuer) { + acq->recursive_depth_++; + return acq; + } + + // Not yet in the ongoing acquisition list. Get in there + auto res = MutexAcquisitionImplPtr(new kernel::activity::MutexAcquisitionImpl(issuer, this), true); ongoing_acquisitions_.push_back(res); - } else { + return res; + } + + // None-recursive mutex + auto res = MutexAcquisitionImplPtr(new kernel::activity::MutexAcquisitionImpl(issuer, this), true); + if (owner_ == nullptr) { // Lock is free, take it owner_ = issuer; + recursive_depth = 1; + res->grant(); + } else { // Somebody is using the mutex; register the acquisition + ongoing_acquisitions_.push_back(res); } return res; } @@ -65,14 +93,14 @@ MutexAcquisitionImplPtr MutexImpl::lock_async(actor::ActorImpl* issuer) */ bool MutexImpl::try_lock(actor::ActorImpl* issuer) { - XBT_IN("(%p, %p)", this, issuer); - if (owner_ != nullptr) { - XBT_OUT(); - return false; + if (owner_ == issuer && is_recursive_) { + recursive_depth++; + return true; } + if (owner_ != nullptr) + return false; - owner_ = issuer; - XBT_OUT(); + owner_ = issuer; return true; } @@ -88,12 +116,20 @@ void MutexImpl::unlock(actor::ActorImpl* issuer) xbt_assert(issuer == owner_, "Cannot release that mutex: you're not the owner. %s is (pid:%ld).", owner_ != nullptr ? owner_->get_cname() : "(nobody)", owner_ != nullptr ? owner_->get_pid() : -1); + if (is_recursive_) { + recursive_depth--; + if (recursive_depth > 0) // Still owning the lock + return; + } + if (not ongoing_acquisitions_.empty()) { /* Give the ownership to the first waiting actor */ auto acq = ongoing_acquisitions_.front(); ongoing_acquisitions_.pop_front(); owner_ = acq->get_issuer(); + acq->grant(); + recursive_depth = acq->recursive_depth_; if (acq == owner_->waiting_synchro_) acq->finish(); // else, the issuer is not blocked on this acquisition so no need to release it diff --git a/src/kernel/activity/MutexImpl.hpp b/src/kernel/activity/MutexImpl.hpp index 3eebec2b12..9d9242b4a5 100644 --- a/src/kernel/activity/MutexImpl.hpp +++ b/src/kernel/activity/MutexImpl.hpp @@ -42,11 +42,18 @@ namespace simgrid::kernel::activity { class XBT_PUBLIC MutexAcquisitionImpl : public ActivityImpl_T { actor::ActorImpl* issuer_ = nullptr; MutexImpl* mutex_ = nullptr; + int recursive_depth_ = 1; + // TODO: use granted_ this instead of owner_ == self to test(). + // This is mandatory to get double-lock on non-recursive locks to properly deadlock + bool granted_ = false; + + friend MutexImpl; public: MutexAcquisitionImpl(actor::ActorImpl* issuer, MutexImpl* mutex) : issuer_(issuer), mutex_(mutex) {} MutexImplPtr get_mutex() { return mutex_; } actor::ActorImpl* get_issuer() { return issuer_; } + void grant() { granted_ = true; } bool test(actor::ActorImpl* issuer = nullptr) override; void wait_for(actor::ActorImpl* issuer, double timeout) override; @@ -63,11 +70,13 @@ class XBT_PUBLIC MutexImpl { std::deque ongoing_acquisitions_; static unsigned next_id_; unsigned id_ = next_id_++; + bool is_recursive_ = false; + int recursive_depth = 0; friend MutexAcquisitionImpl; public: - MutexImpl() : piface_(this) {} + MutexImpl(bool recursive = false) : piface_(this), is_recursive_(recursive) {} MutexImpl(MutexImpl const&) = delete; MutexImpl& operator=(MutexImpl const&) = delete; diff --git a/src/kernel/actor/CommObserver.cpp b/src/kernel/actor/CommObserver.cpp index 6f13e3ea46..d860c8c221 100644 --- a/src/kernel/actor/CommObserver.cpp +++ b/src/kernel/actor/CommObserver.cpp @@ -6,6 +6,7 @@ #include "simgrid/s4u/Host.hpp" #include "src/kernel/activity/CommImpl.hpp" #include "src/kernel/activity/MailboxImpl.hpp" +#include "src/kernel/activity/MessageQueueImpl.hpp" #include "src/kernel/actor/ActorImpl.hpp" #include "src/kernel/actor/SimcallObserver.hpp" #include "src/mc/mc_config.hpp" @@ -221,8 +222,8 @@ void CommIsendSimcall::serialize(std::stringstream& stream) const } std::string CommIsendSimcall::to_string() const { - return "CommAsyncSend(comm_id: " + std::to_string(comm_->get_id()) + " mbox:" + std::to_string(mbox_->get_id()) + - " tag: " + std::to_string(tag_) + ")"; + return "CommAsyncSend(comm_id: " + std::to_string((comm_ ? comm_->get_id() : 0)) + " mbox:" + + std::to_string(mbox_->get_id()) + " tag: " + std::to_string(tag_) + ")"; } void CommIrecvSimcall::serialize(std::stringstream& stream) const @@ -233,10 +234,35 @@ void CommIrecvSimcall::serialize(std::stringstream& stream) const XBT_DEBUG("RecvObserver comm:%p mbox:%u tag:%d", comm_, mbox_->get_id(), tag_); stream << ' ' << fun_call_; } + std::string CommIrecvSimcall::to_string() const { - return "CommAsyncRecv(comm_id: " + std::to_string(comm_->get_id()) + " mbox:" + std::to_string(mbox_->get_id()) + - " tag: " + std::to_string(tag_) + ")"; + return "CommAsyncRecv(comm_id: " + std::to_string((comm_ ? comm_->get_id() : 0)) + " mbox:" + + std::to_string(mbox_->get_id()) + " tag: " + std::to_string(tag_) + ")"; +} + +void MessIputSimcall::serialize(std::stringstream& stream) const +{ + stream << mess_ << ' ' << queue_; + XBT_DEBUG("PutObserver mess:%p queue:%p", mess_, queue_); } +std::string MessIputSimcall::to_string() const +{ + return "MessAsyncPut(queue:" + queue_->get_name() + ")"; +} + +void MessIgetSimcall::serialize(std::stringstream& stream) const +{ + stream << mess_ << ' ' << queue_; + XBT_DEBUG("GettObserver mess:%p queue:%p", mess_, queue_); +} + +std::string MessIgetSimcall::to_string() const +{ + return "MessAsyncGet(queue:" + queue_->get_name() + ")"; +} + + + } // namespace simgrid::kernel::actor diff --git a/src/kernel/actor/CommObserver.hpp b/src/kernel/actor/CommObserver.hpp index ab036510ee..161e095e05 100644 --- a/src/kernel/actor/CommObserver.hpp +++ b/src/kernel/actor/CommObserver.hpp @@ -186,6 +186,52 @@ public: auto const& get_copy_data_fun() const { return copy_data_fun_; } }; +class MessIputSimcall final : public SimcallObserver { + activity::MessageQueueImpl* queue_; + void* payload_; + activity::MessImpl* mess_ = {}; + +public: + MessIputSimcall( + ActorImpl* actor, activity::MessageQueueImpl* queue, void* payload) + : SimcallObserver(actor) + , queue_(queue) + , payload_(payload) + { + } + void serialize(std::stringstream& stream) const override; + std::string to_string() const override; + activity::MessageQueueImpl* get_queue() const { return queue_; } + void* get_payload() const { return payload_; } + void set_message(activity::MessImpl* mess) { mess_ = mess; } +}; + +class MessIgetSimcall final : public SimcallObserver { + activity::MessageQueueImpl* queue_; + unsigned char* dst_buff_; + size_t* dst_buff_size_; + void* payload_; + activity::MessImpl* mess_ = {}; + +public: + MessIgetSimcall(ActorImpl* actor, activity::MessageQueueImpl* queue, unsigned char* dst_buff, size_t* dst_buff_size, + void* payload) + : SimcallObserver(actor) + , queue_(queue) + , dst_buff_(dst_buff) + , dst_buff_size_(dst_buff_size) + , payload_(payload) + { + } + void serialize(std::stringstream& stream) const override; + std::string to_string() const override; + activity::MessageQueueImpl* get_queue() const { return queue_; } + unsigned char* get_dst_buff() const { return dst_buff_; } + size_t* get_dst_buff_size() const { return dst_buff_size_; } + void* get_payload() const { return payload_; } + void set_message(activity::MessImpl* mess) { mess_ = mess; } +}; + } // namespace simgrid::kernel::actor #endif diff --git a/src/kernel/actor/SimcallObserver.cpp b/src/kernel/actor/SimcallObserver.cpp index 2d2cf8827e..3bd6ab97f1 100644 --- a/src/kernel/actor/SimcallObserver.cpp +++ b/src/kernel/actor/SimcallObserver.cpp @@ -73,6 +73,15 @@ std::string ActorJoinSimcall::to_string() const { return "ActorJoin(pid:" + std::to_string(other_->get_pid()) + ")"; } +void ActorSleepSimcall::serialize(std::stringstream& stream) const +{ + stream << (short)mc::Transition::Type::ACTOR_SLEEP; +} + +std::string ActorSleepSimcall::to_string() const +{ + return "ActorSleep()"; +} void ObjectAccessSimcallObserver::serialize(std::stringstream& stream) const { diff --git a/src/kernel/actor/SimcallObserver.hpp b/src/kernel/actor/SimcallObserver.hpp index 4cb7f22c3c..d43ac00ead 100644 --- a/src/kernel/actor/SimcallObserver.hpp +++ b/src/kernel/actor/SimcallObserver.hpp @@ -127,6 +127,14 @@ public: double get_timeout() const { return timeout_; } }; +class ActorSleepSimcall final : public SimcallObserver { + +public: + ActorSleepSimcall(ActorImpl* actor) : SimcallObserver(actor) {} + void serialize(std::stringstream& stream) const override; + std::string to_string() const override; +}; + class ObjectAccessSimcallObserver final : public SimcallObserver { ObjectAccessSimcallItem* const object_; diff --git a/src/kernel/context/Context.cpp b/src/kernel/context/Context.cpp index c4f79b46a4..5736b265cd 100644 --- a/src/kernel/context/Context.cpp +++ b/src/kernel/context/Context.cpp @@ -54,12 +54,6 @@ void Context::set_current(Context* self) current_context_ = self; } -void Context::declare_context(std::size_t size) -{ - /* Store the address of the stack in heap to compare it apart of heap comparison */ - MC_ignore_heap(this, size); -} - Context* ContextFactory::attach(actor::ActorImpl*) { xbt_die("Cannot attach with this ContextFactory.\n" diff --git a/src/kernel/context/Context.hpp b/src/kernel/context/Context.hpp index 196139975d..16c5e82274 100644 --- a/src/kernel/context/Context.hpp +++ b/src/kernel/context/Context.hpp @@ -35,7 +35,6 @@ protected: template T* new_context(Args&&... args) { auto* context = new T(std::forward(args)...); - context->declare_context(sizeof(T)); return context; } }; @@ -49,7 +48,6 @@ class XBT_PUBLIC Context { std::function code_; actor::ActorImpl* actor_ = nullptr; bool is_maestro_; - void declare_context(std::size_t size); public: static e_xbt_parmap_mode_t parallel_mode; diff --git a/src/kernel/context/ContextRaw.cpp b/src/kernel/context/ContextRaw.cpp index 1c29c667a6..de72fce947 100644 --- a/src/kernel/context/ContextRaw.cpp +++ b/src/kernel/context/ContextRaw.cpp @@ -190,8 +190,6 @@ RawContext::RawContext(std::function&& code, actor::ActorImpl* actor, Sw XBT_VERB("Creating a context of stack %uMb", actor->get_stacksize() / 1024 / 1024); if (has_code()) { this->stack_top_ = raw_makecontext(get_stack(), actor->get_stacksize(), smx_ctx_wrapper, this); - } else { - MC_ignore_heap(&stack_top_, sizeof stack_top_); } } diff --git a/src/kernel/context/ContextSwapped.cpp b/src/kernel/context/ContextSwapped.cpp index 1f3cd31e3a..aff10af720 100644 --- a/src/kernel/context/ContextSwapped.cpp +++ b/src/kernel/context/ContextSwapped.cpp @@ -82,17 +82,9 @@ SwappedContext::SwappedContext(std::function&& code, actor::ActorImpl* a #endif size_t size = actor->get_stacksize() + guard_size; -#if SIMGRID_HAVE_STATEFUL_MC - /* Cannot use posix_memalign when SIMGRID_HAVE_STATEFUL_MC. Align stack by hand, and save the - * pointer returned by xbt_malloc0. */ - auto* alloc = static_cast(xbt_malloc0(size + xbt_pagesize)); - stack_ = alloc - (reinterpret_cast(alloc) & (xbt_pagesize - 1)) + xbt_pagesize; - reinterpret_cast(stack_)[-1] = alloc; -#else void* alloc; xbt_assert(posix_memalign(&alloc, xbt_pagesize, size) == 0, "Failed to allocate stack."); this->stack_ = static_cast(alloc); -#endif /* This is fatal. We are going to fail at some point when we try reusing this. */ xbt_assert( @@ -146,10 +138,6 @@ SwappedContext::~SwappedContext() XBT_WARN("Failed to remove page protection: %s", strerror(errno)); /* try to pursue anyway */ } -#if SIMGRID_HAVE_STATEFUL_MC - /* Retrieve the saved pointer. See the initialization above. */ - stack_ = reinterpret_cast(stack_)[-1]; -#endif } xbt_free(stack_); diff --git a/src/kernel/context/ContextUnix.cpp b/src/kernel/context/ContextUnix.cpp index 98e372daf3..2061a2535e 100644 --- a/src/kernel/context/ContextUnix.cpp +++ b/src/kernel/context/ContextUnix.cpp @@ -60,11 +60,6 @@ UContext::UContext(std::function&& code, actor::ActorImpl* actor, Swappe UContext* arg = this; memcpy(ctx_addr, &arg, sizeof arg); makecontext(&this->uc_, (void (*)())sysv_ctx_wrapper, 2, ctx_addr[0], ctx_addr[1]); - -#if SIMGRID_HAVE_STATEFUL_MC - if (MC_is_active()) - simgrid::mc::AppSide::get()->declare_stack(get_stack(), stack_size, &uc_); -#endif } } diff --git a/src/kernel/resource/HostImpl.cpp b/src/kernel/resource/HostImpl.cpp index b4c78c5721..da11f9aa1e 100644 --- a/src/kernel/resource/HostImpl.cpp +++ b/src/kernel/resource/HostImpl.cpp @@ -237,7 +237,7 @@ s4u::Disk* HostImpl::create_disk(const std::string& name, double read_bandwidth, void HostImpl::add_disk(const s4u::Disk* disk) { - disks_[disk->get_name()] = kernel::resource::DiskImplPtr(disk->get_impl()); + disks_.insert({disk->get_name(), kernel::resource::DiskImplPtr(disk->get_impl())}); } void HostImpl::remove_disk(const std::string& name) diff --git a/src/kernel/resource/models/network_ns3.cpp b/src/kernel/resource/models/network_ns3.cpp index b2064421aa..3d4c0650ff 100644 --- a/src/kernel/resource/models/network_ns3.cpp +++ b/src/kernel/resource/models/network_ns3.cpp @@ -119,8 +119,14 @@ static void zoneCreation_cb(simgrid::s4u::NetZone const& zone) wifiPhy.Set("Antennas", ns3::UintegerValue(nss_value)); wifiPhy.Set("MaxSupportedTxSpatialStreams", ns3::UintegerValue(nss_value)); wifiPhy.Set("MaxSupportedRxSpatialStreams", ns3::UintegerValue(nss_value)); -#if NS3_MINOR_VERSION > 33 +#if NS3_MINOR_VERSION < 33 + // This fails with "The channel width does not uniquely identify an operating channel" on v3.34, + // so we specified the ChannelWidth of wifiPhy to 40, above, when creating wifiPhy with v3.34 and higher + ns3::Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/ChannelWidth", ns3::UintegerValue(40)); +#elif NS3_MINOR_VERSION < 36 wifiPhy.Set("ChannelWidth", ns3::UintegerValue(40)); +#else + wifiPhy.Set("ChannelSettings", ns3::StringValue("{0, 40, BAND_UNSPECIFIED, 0}")); #endif wifiMac.SetType("ns3::ApWifiMac", "Ssid", ns3::SsidValue(ssid)); @@ -166,12 +172,6 @@ static void zoneCreation_cb(simgrid::s4u::NetZone const& zone) ns3::Simulator::Schedule(ns3::Seconds(start_time_value), &resumeWifiDevice, device); } -#if NS3_MINOR_VERSION < 33 - // This fails with "The channel width does not uniquely identify an operating channel" on v3.34, - // so we specified the ChannelWidth of wifiPhy to 40, above, when creating wifiPhy with v3.34 and higher - ns3::Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/ChannelWidth", ns3::UintegerValue(40)); -#endif - mobility.SetPositionAllocator(positionAllocS); mobility.Install(nodes); ns3::Ipv4AddressHelper address; diff --git a/src/mc/AddressSpace.hpp b/src/mc/AddressSpace.hpp deleted file mode 100644 index f817bf0d33..0000000000 --- a/src/mc/AddressSpace.hpp +++ /dev/null @@ -1,135 +0,0 @@ -/* Copyright (c) 2008-2023. 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 SIMGRID_MC_ADDRESS_SPACE_H -#define SIMGRID_MC_ADDRESS_SPACE_H - -#include "src/mc/mc_forward.hpp" -#include "src/mc/remote/RemotePtr.hpp" - -namespace simgrid::mc { - -/** Options for read operations - * - * This is a set of flags managed with bitwise operators. Only the - * meaningful operations are defined: addition, conversions to/from - * integers are not allowed. - */ -class ReadOptions { - std::uint32_t value_ = 0; - constexpr explicit ReadOptions(std::uint32_t value) : value_(value) {} - -public: - constexpr ReadOptions() = default; - - explicit constexpr operator bool() const { return value_ != 0; } - constexpr bool operator!() const { return value_ == 0; } - - constexpr ReadOptions operator|(ReadOptions const& that) const - { - return ReadOptions(value_ | that.value_); - } - constexpr ReadOptions operator&(ReadOptions const& that) const - { - return ReadOptions(value_ & that.value_); - } - constexpr ReadOptions operator^(ReadOptions const& that) const - { - return ReadOptions(value_ ^ that.value_); - } - constexpr ReadOptions operator~() const - { - return ReadOptions(~value_); - } - - ReadOptions& operator|=(ReadOptions const& that) - { - value_ |= that.value_; - return *this; - } - ReadOptions& operator&=(ReadOptions const& that) - { - value_ &= that.value_; - return *this; - } - ReadOptions& operator^=(ReadOptions const& that) - { - value_ ^= that.value_; - return *this; - } - - /** Copy the data to the given buffer */ - static constexpr ReadOptions none() { return ReadOptions(0); } - - /** Allows to return a pointer to another buffer where the data is - * available instead of copying the data into the buffer - */ - static constexpr ReadOptions lazy() { return ReadOptions(1); } -}; - -/** A given state of a given process (abstract base class) - * - * Currently, this might either be: - * - * * the current state of an existing process; - * - * * a snapshot. - */ -class AddressSpace { -private: - RemoteProcessMemory* remote_process_memory_; - -public: - explicit AddressSpace(RemoteProcessMemory* process) : remote_process_memory_(process) {} - virtual ~AddressSpace() = default; - - /** The process of this address space - * - * This is where we can get debug information, memory layout, etc. - */ - simgrid::mc::RemoteProcessMemory* get_remote_process_memory() const { return remote_process_memory_; } - - /** Read data from the address space - * - * @param buffer target buffer for the data - * @param size number of bytes to read - * @param address remote source address of the data - * @param options - */ - virtual void* read_bytes(void* buffer, std::size_t size, RemotePtr address, - ReadOptions options = ReadOptions::none()) const = 0; - - /** Read a given data structure from the address space */ - template inline void read(T* buffer, RemotePtr ptr) const { this->read_bytes(buffer, sizeof(T), ptr); } - - template inline void read(Remote& buffer, RemotePtr ptr) const - { - this->read_bytes(buffer.get_buffer(), sizeof(T), ptr); - } - - /** Read a given data structure from the address space - * - * This version returns by value. - */ - template inline Remote read(RemotePtr ptr) const - { - Remote res; - this->read_bytes(&res, sizeof(T), ptr); - return res; - } - - /** Read a string of known size */ - std::string read_string(RemotePtr address, std::size_t len) const - { - std::string res; - res.resize(len); - this->read_bytes(&res[0], len, address); - return res; - } -}; - -} // namespace simgrid::mc - -#endif diff --git a/src/mc/VisitedState.cpp b/src/mc/VisitedState.cpp deleted file mode 100644 index 8e19472627..0000000000 --- a/src/mc/VisitedState.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (c) 2011-2023. 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 "src/mc/VisitedState.hpp" -#include "src/mc/explo/Exploration.hpp" -#include "src/mc/mc_config.hpp" -#include "src/mc/mc_private.hpp" - -#include -#include -#include -#include - -XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_VisitedState, mc, "Logging specific to state equality detection mechanisms"); - -namespace simgrid::mc { - -/** @brief Save the current state */ -VisitedState::VisitedState(unsigned long state_number, unsigned int actor_count, RemoteApp& remote_app) - : heap_bytes_used_(remote_app.get_remote_process_memory()->get_remote_heap_bytes()) - , actor_count_(actor_count) - , num_(state_number) -{ - this->system_state_ = std::make_shared(state_number, remote_app.get_page_store(), - *remote_app.get_remote_process_memory()); -} - -void VisitedStates::prune() -{ - while (states_.size() > (std::size_t)_sg_mc_max_visited_states) { - XBT_DEBUG("Try to remove visited state (maximum number of stored states reached)"); - auto min_element = boost::range::min_element( - states_, [](const std::unique_ptr& a, - const std::unique_ptr& b) { return a->num_ < b->num_; }); - xbt_assert(min_element != states_.end()); - // and drop it: - states_.erase(min_element); - XBT_DEBUG("Remove visited state (maximum number of stored states reached)"); - } -} - -/** @brief Checks whether a given state has already been visited by the algorithm. */ -std::unique_ptr -VisitedStates::addVisitedState(unsigned long state_number, simgrid::mc::State* graph_state, RemoteApp& remote_app) -{ - auto new_state = - std::make_unique(state_number, graph_state->get_actor_count(), remote_app); - - graph_state->set_system_state(new_state->system_state_); - XBT_DEBUG("Snapshot %p of visited state %ld (exploration stack state %ld)", new_state->system_state_.get(), - new_state->num_, graph_state->get_num()); - - auto [range_begin, range_end] = boost::range::equal_range(states_, new_state.get(), [](auto const& a, auto const& b) { - return std::make_pair(a->actor_count_, a->heap_bytes_used_) < std::make_pair(b->actor_count_, b->heap_bytes_used_); - }); - - for (auto i = range_begin; i != range_end; ++i) { - auto& visited_state = *i; - if (visited_state->system_state_->equals_to(*new_state->system_state_.get(), - *remote_app.get_remote_process_memory())) { - // The state has been visited: - - std::unique_ptr old_state = std::move(visited_state); - - if (old_state->original_num_ == -1) // I'm the copy of an original process - new_state->original_num_ = old_state->num_; - else // I'm the copy of a copy - new_state->original_num_ = old_state->original_num_; - - XBT_DEBUG("State %ld already visited ! (equal to state %ld (state %ld in dot_output))", new_state->num_, - old_state->num_, new_state->original_num_); - - /* Replace the old state with the new one (with a bigger num) - (when the max number of visited states is reached, the oldest - one is removed according to its number (= with the min number) */ - XBT_DEBUG("Replace visited state %ld with the new visited state %ld", old_state->num_, new_state->num_); - - visited_state = std::move(new_state); - return old_state; - } - } - - XBT_DEBUG("Insert new visited state %ld (total : %lu)", new_state->num_, (unsigned long)states_.size()); - states_.insert(range_begin, std::move(new_state)); - this->prune(); - return nullptr; -} - -} // namespace simgrid::mc diff --git a/src/mc/VisitedState.hpp b/src/mc/VisitedState.hpp deleted file mode 100644 index b2f2694c56..0000000000 --- a/src/mc/VisitedState.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (c) 2007-2023. 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 SIMGRID_MC_VISITED_STATE_HPP -#define SIMGRID_MC_VISITED_STATE_HPP - -#include "src/mc/api/State.hpp" -#include "src/mc/sosp/Snapshot.hpp" - -#include -#include - -namespace simgrid::mc { - -class XBT_PRIVATE VisitedState { -public: - std::shared_ptr system_state_ = nullptr; - std::size_t heap_bytes_used_ = 0; - int actor_count_; - long num_; // unique id of that state in the storage of all stored IDs - long original_num_ = -1; // num field of the VisitedState to which I was declared equal to (used for dot_output) - - explicit VisitedState(unsigned long state_number, unsigned int actor_count, RemoteApp& remote_app); -}; - -class XBT_PRIVATE VisitedStates { - std::vector> states_; -public: - void clear() { states_.clear(); } - std::unique_ptr addVisitedState(unsigned long state_number, - simgrid::mc::State* graph_state, RemoteApp& remote_app); - -private: - void prune(); -}; - -} // namespace simgrid::mc - -#endif diff --git a/src/mc/api/RemoteApp.cpp b/src/mc/api/RemoteApp.cpp index 49622dd275..dc6c7d0d54 100644 --- a/src/mc/api/RemoteApp.cpp +++ b/src/mc/api/RemoteApp.cpp @@ -32,23 +32,15 @@ namespace simgrid::mc { static std::string master_socket_name; -RemoteApp::RemoteApp(const std::vector& args, bool need_memory_introspection) : app_args_(args) +RemoteApp::RemoteApp(const std::vector& args) : app_args_(args) { - if (need_memory_introspection) { -#if SIMGRID_HAVE_STATEFUL_MC - checker_side_ = std::make_unique(app_args_, need_memory_introspection); - initial_snapshot_ = std::make_shared(0, page_store_, *checker_side_->get_remote_memory()); -#else - xbt_die("SimGrid MC was compiled without memory introspection support."); -#endif - } else { - master_socket_ = socket(AF_UNIX, + master_socket_ = socket(AF_UNIX, #ifdef __APPLE__ - SOCK_STREAM, /* Mac OSX does not have AF_UNIX + SOCK_SEQPACKET, even if that's faster */ + SOCK_STREAM, /* Mac OSX does not have AF_UNIX + SOCK_SEQPACKET, even if that's faster */ #else - SOCK_SEQPACKET, + SOCK_SEQPACKET, #endif - 0); + 0); xbt_assert(master_socket_ != -1, "Cannot create the master socket: %s", strerror(errno)); master_socket_name = "/tmp/simgrid-mc-" + std::to_string(getpid()); @@ -75,19 +67,13 @@ RemoteApp::RemoteApp(const std::vector& args, bool need_memory_introspect xbt_assert(listen(master_socket_, SOMAXCONN) >= 0, "Cannot listen to the master socket: %s.", strerror(errno)); - application_factory_ = std::make_unique(app_args_, need_memory_introspection); + application_factory_ = std::make_unique(app_args_); checker_side_ = application_factory_->clone(master_socket_, master_socket_name); - } } void RemoteApp::restore_initial_state() { - if (initial_snapshot_ == nullptr) // No memory introspection checker_side_ = application_factory_->clone(master_socket_, master_socket_name); -#if SIMGRID_HAVE_STATEFUL_MC - else - initial_snapshot_->restore(*checker_side_->get_remote_memory()); -#endif } unsigned long RemoteApp::get_maxpid() const @@ -158,7 +144,8 @@ void RemoteApp::get_actors_status(std::map& whereto) const actor_transitions.emplace_back(deserialize_transition(actor.aid, times_considered, stream)); } - XBT_DEBUG("Received %zu transitions for actor %ld", actor_transitions.size(), actor.aid); + XBT_DEBUG("Received %zu transitions for actor %ld. The first one is %s", actor_transitions.size(), actor.aid, + (actor_transitions.size() > 0 ? actor_transitions[0]->to_string().c_str() : "null")); whereto.try_emplace(actor.aid, actor.aid, actor.enabled, actor.max_considered, std::move(actor_transitions)); } } @@ -200,10 +187,6 @@ Transition* RemoteApp::handle_simcall(aid_t aid, int times_considered, bool new_ m.times_considered_ = times_considered; checker_side_->get_channel().send(m); -#if SIMGRID_HAVE_STATEFUL_MC - if (auto* memory = get_remote_process_memory(); memory != nullptr) - memory->clear_cache(); -#endif if (checker_side_->running()) checker_side_->dispatch_events(); // The app may send messages while processing the transition diff --git a/src/mc/api/RemoteApp.hpp b/src/mc/api/RemoteApp.hpp index dbb5e5dc85..6954a985bf 100644 --- a/src/mc/api/RemoteApp.hpp +++ b/src/mc/api/RemoteApp.hpp @@ -10,7 +10,6 @@ #include "src/mc/api/ActorState.hpp" #include "src/mc/remote/CheckerSide.hpp" #include "src/mc/remote/RemotePtr.hpp" -#include "src/mc/sosp/PageStore.hpp" #include @@ -26,12 +25,6 @@ namespace simgrid::mc { */ class XBT_PUBLIC RemoteApp { private: -#if SIMGRID_HAVE_STATEFUL_MC - PageStore page_store_{500}; - std::shared_ptr initial_snapshot_; -#else - void* initial_snapshot_ = nullptr; // The code tests it to decide whether to use the refork exec path -#endif std::unique_ptr checker_side_; std::unique_ptr application_factory_; // when no meminfo, create checker_side_ by cloning this one int master_socket_ = -1; @@ -50,7 +43,7 @@ public: * * The code is expected to `exec` the model-checked application. */ - explicit RemoteApp(const std::vector& args, bool need_memory_introspection); + explicit RemoteApp(const std::vector& args); void restore_initial_state(); void wait_for_requests(); @@ -69,13 +62,6 @@ public: /** Take a transition. A new Transition is created iff the last parameter is true */ Transition* handle_simcall(aid_t aid, int times_considered, bool new_transition); - -#if SIMGRID_HAVE_STATEFUL_MC - /* Get the memory of the remote process */ - RemoteProcessMemory* get_remote_process_memory() { return checker_side_->get_remote_memory(); } - - PageStore& get_page_store() { return page_store_; } -#endif }; } // namespace simgrid::mc diff --git a/src/mc/api/State.cpp b/src/mc/api/State.cpp index 866a1d0400..aff9d5cb60 100644 --- a/src/mc/api/State.cpp +++ b/src/mc/api/State.cpp @@ -38,13 +38,6 @@ State::State(RemoteApp& remote_app) : num_(++expended_states_) THROW_IMPOSSIBLE; remote_app.get_actors_status(strategy_->actors_to_run_); - -#if SIMGRID_HAVE_STATEFUL_MC - /* Stateful model checking */ - if ((_sg_mc_checkpoint > 0 && (num_ % _sg_mc_checkpoint == 0)) || _sg_mc_termination) - system_state_ = std::make_shared(num_, remote_app.get_page_store(), - *remote_app.get_remote_process_memory()); -#endif } State::State(RemoteApp& remote_app, std::shared_ptr parent_state) @@ -64,12 +57,6 @@ State::State(RemoteApp& remote_app, std::shared_ptr parent_state) remote_app.get_actors_status(strategy_->actors_to_run_); -#if SIMGRID_HAVE_STATEFUL_MC /* Stateful model checking */ - if ((_sg_mc_checkpoint > 0 && (num_ % _sg_mc_checkpoint == 0)) || _sg_mc_termination) - system_state_ = std::make_shared(num_, remote_app.get_page_store(), - *remote_app.get_remote_process_memory()); -#endif - /* Copy the sleep set and eventually removes things from it: */ /* For each actor in the previous sleep set, keep it if it is not dependent with current transition. * And if we kept it and the actor is enabled in this state, mark the actor as already done, so that @@ -252,14 +239,18 @@ void State::sprout_tree_from_parent_state() "parent with an empty wakeup tree. This indicates either that ODPOR " "actor selection in State.cpp is incorrect, or that the code " "deciding when to make subtrees in ODPOR is incorrect"); - xbt_assert((get_transition_in()->aid_ == min_process_node.value()->get_actor()) && - (get_transition_in()->type_ == min_process_node.value()->get_action()->type_), - "We tried to make a subtree from a parent state who claimed to have executed `%s` on actor %ld " - "but whose wakeup tree indicates it should have executed `%s` on actor %ld. This indicates " - "that exploration is not following ODPOR. Are you sure you're choosing actors " - "to schedule from the wakeup tree?", - get_transition_in()->to_string(false).c_str(), get_transition_in()->aid_, - min_process_node.value()->get_action()->to_string(false).c_str(), min_process_node.value()->get_actor()); + if (not(get_transition_in()->aid_ == min_process_node.value()->get_actor() && + get_transition_in()->type_ == min_process_node.value()->get_action()->type_)) { + XBT_ERROR("We tried to make a subtree from a parent state who claimed to have executed `%s` on actor %ld " + "but whose wakeup tree indicates it should have executed `%s` on actor %ld. This indicates " + "that exploration is not following ODPOR. Are you sure you're choosing actors " + "to schedule from the wakeup tree? Trace so far:", + get_transition_in()->to_string(false).c_str(), get_transition_in()->aid_, + min_process_node.value()->get_action()->to_string(false).c_str(), min_process_node.value()->get_actor()); + for (auto elm : Exploration::get_instance()->get_textual_trace()) + XBT_ERROR("%s", elm.c_str()); + xbt_abort(); + } this->wakeup_tree_ = odpor::WakeupTree::make_subtree_rooted_at(min_process_node.value()); } diff --git a/src/mc/api/State.hpp b/src/mc/api/State.hpp index f10d7bd51d..de11f78e88 100644 --- a/src/mc/api/State.hpp +++ b/src/mc/api/State.hpp @@ -13,10 +13,6 @@ #include "src/mc/explo/odpor/WakeupTree.hpp" #include "src/mc/transition/Transition.hpp" -#if SIMGRID_HAVE_STATEFUL_MC -#include "src/mc/sosp/Snapshot.hpp" -#endif - namespace simgrid::mc { /* A node in the exploration graph (kind-of) */ @@ -32,9 +28,6 @@ class XBT_PRIVATE State : public xbt::Extendable { /** Sequential state ID (used for debugging) */ long num_ = 0; - /** Snapshot of system state (if needed) */ - std::shared_ptr system_state_; - /** Unique parent of this state. Required both for sleep set computation and for guided model-checking */ std::shared_ptr parent_state_ = nullptr; @@ -98,9 +91,6 @@ public: unsigned long get_actor_count() const { return strategy_->actors_to_run_.size(); } bool is_actor_enabled(aid_t actor) const { return strategy_->actors_to_run_.at(actor).is_enabled(); } - Snapshot* get_system_state() const { return system_state_.get(); } - void set_system_state(std::shared_ptr state) { system_state_ = std::move(state); } - /** * @brief Computes the backtrack set for this state * according to its definition in SimGrid. diff --git a/src/mc/api/strategy/BasicStrategy.hpp b/src/mc/api/strategy/BasicStrategy.hpp index fd28633977..de0fe65d9b 100644 --- a/src/mc/api/strategy/BasicStrategy.hpp +++ b/src/mc/api/strategy/BasicStrategy.hpp @@ -7,13 +7,17 @@ #define SIMGRID_MC_BASICSTRATEGY_HPP #include "Strategy.hpp" +#include "src/mc/explo/Exploration.hpp" + +XBT_LOG_EXTERNAL_CATEGORY(mc_dfs); namespace simgrid::mc { /** Basic MC guiding class which corresponds to no guide. When asked for different states * it will follow a depth first search politics to minize the number of opened states. */ class BasicStrategy : public Strategy { - int depth_ = _sg_mc_max_depth; // Arbitrary starting point. next_transition must return a positiv value to work with threshold in DFSExplorer + int depth_ = _sg_mc_max_depth; // Arbitrary starting point. next_transition must return a positive value to work with + // threshold in DFSExplorer public: void copy_from(const Strategy* strategy) override @@ -21,7 +25,16 @@ public: const auto* cast_strategy = dynamic_cast(strategy); xbt_assert(cast_strategy != nullptr); depth_ = cast_strategy->depth_ - 1; - xbt_assert(depth_ > 0, "The exploration reached a depth greater than %d. We will stop here to prevent weird interaction with DFSExplorer. If you want to change that behaviour, you should augment the size of the search by using --cfg=model-check/max-depth:", _sg_mc_max_depth.get()); + if (depth_ <= 0) { + XBT_CERROR(mc_dfs, + "The exploration reached a depth greater than %d. Change the depth limit with " + "--cfg=model-check/max-depth. Here are the 100 first trace elements", + _sg_mc_max_depth.get()); + auto trace = Exploration::get_instance()->get_textual_trace(100); + for (auto elm : trace) + XBT_CERROR(mc_dfs, " %s", elm.c_str()); + xbt_die("Aborting now."); + } } BasicStrategy() = default; ~BasicStrategy() override = default; diff --git a/src/mc/compare.cpp b/src/mc/compare.cpp deleted file mode 100644 index 9fe80723b7..0000000000 --- a/src/mc/compare.cpp +++ /dev/null @@ -1,1300 +0,0 @@ -/* Copyright (c) 2008-2023. 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. */ - -/** \file compare.cpp Memory snapshotting and comparison */ - -#include "src/mc/mc_config.hpp" -#include "src/mc/mc_private.hpp" -#include "src/mc/sosp/RemoteProcessMemory.hpp" -#include "src/mc/sosp/Snapshot.hpp" -#include "xbt/ex.h" - -#include - -XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_compare, mc, "Logging specific to mc_compare in mc"); - -namespace simgrid::mc { - -/*********************************** Heap comparison ***********************************/ -/***************************************************************************************/ - -class HeapLocation { -public: - int block_ = 0; - int fragment_ = 0; - - HeapLocation() = default; - explicit HeapLocation(int block, int fragment = 0) : block_(block), fragment_(fragment) {} - - bool operator==(HeapLocation const& that) const - { - return block_ == that.block_ && fragment_ == that.fragment_; - } - bool operator<(HeapLocation const& that) const - { - return std::make_pair(block_, fragment_) < std::make_pair(that.block_, that.fragment_); - } -}; - -using HeapLocationPair = std::array; -using HeapLocationPairs = std::set; - -class HeapArea : public HeapLocation { -public: - bool valid_ = false; - HeapArea() = default; - explicit HeapArea(int block) : valid_(true) { block_ = block; } - HeapArea(int block, int fragment) : valid_(true) - { - block_ = block; - fragment_ = fragment; - } -}; - -class ProcessComparisonState { -public: - const std::vector* to_ignore = nullptr; - std::vector equals_to; - std::vector types; - std::size_t heapsize = 0; - - void initHeapInformation(const s_xbt_mheap_t* heap, const std::vector& i); -}; - -class StateComparator { -public: - s_xbt_mheap_t std_heap_copy; - std::size_t heaplimit; - std::array processStates; - - std::unordered_set, simgrid::xbt::hash>> - compared_pointers; - - void clear() - { - compared_pointers.clear(); - } - - int initHeapInformation(RemoteProcessMemory& appli, const s_xbt_mheap_t* heap1, const s_xbt_mheap_t* heap2, - const std::vector& i1, const std::vector& i2); - - template HeapArea& equals_to_(std::size_t i, std::size_t j) - { - return processStates[rank - 1].equals_to[MAX_FRAGMENT_PER_BLOCK * i + j]; - } - template Type*& types_(std::size_t i, std::size_t j) - { - return processStates[rank - 1].types[MAX_FRAGMENT_PER_BLOCK * i + j]; - } - - template HeapArea const& equals_to_(std::size_t i, std::size_t j) const - { - return processStates[rank - 1].equals_to[MAX_FRAGMENT_PER_BLOCK * i + j]; - } - template Type* const& types_(std::size_t i, std::size_t j) const - { - return processStates[rank - 1].types[MAX_FRAGMENT_PER_BLOCK * i + j]; - } - - /** Check whether two blocks are known to be matching - * - * @param b1 Block of state 1 - * @param b2 Block of state 2 - * @return if the blocks are known to be matching - */ - bool blocksEqual(int b1, int b2) const - { - return this->equals_to_<1>(b1, 0).block_ == b2 && this->equals_to_<2>(b2, 0).block_ == b1; - } - - /** Check whether two fragments are known to be matching - * - * @param b1 Block of state 1 - * @param f1 Fragment of state 1 - * @param b2 Block of state 2 - * @param f2 Fragment of state 2 - * @return if the fragments are known to be matching - */ - int fragmentsEqual(int b1, int f1, int b2, int f2) const - { - return this->equals_to_<1>(b1, f1).block_ == b2 && this->equals_to_<1>(b1, f1).fragment_ == f2 && - this->equals_to_<2>(b2, f2).block_ == b1 && this->equals_to_<2>(b2, f2).fragment_ == f1; - } - - void match_equals(const HeapLocationPairs* list); -}; - -} // namespace simgrid::mc - -/************************************************************************************/ - -static ssize_t heap_comparison_ignore_size(const std::vector* ignore_list, - const void* address) -{ - auto pos = std::lower_bound(ignore_list->begin(), ignore_list->end(), address, - [](auto const& reg, auto const* addr) { return reg.address < addr; }); - return (pos != ignore_list->end() && pos->address == address) ? pos->size : -1; -} - -static bool is_stack(const simgrid::mc::RemoteProcessMemory& process, const void* address) -{ - auto const& stack_areas = process.stack_areas(); - return std::any_of(stack_areas.begin(), stack_areas.end(), - [address](auto const& stack) { return stack.address == address; }); -} - -// TODO, this should depend on the snapshot? -static bool is_block_stack(const simgrid::mc::RemoteProcessMemory& process, int block) -{ - auto const& stack_areas = process.stack_areas(); - return std::any_of(stack_areas.begin(), stack_areas.end(), - [block](auto const& stack) { return stack.block == block; }); -} - -namespace simgrid::mc { - -void StateComparator::match_equals(const HeapLocationPairs* list) -{ - for (auto const& pair : *list) { - if (pair[0].fragment_ != -1) { - this->equals_to_<1>(pair[0].block_, pair[0].fragment_) = HeapArea(pair[1].block_, pair[1].fragment_); - this->equals_to_<2>(pair[1].block_, pair[1].fragment_) = HeapArea(pair[0].block_, pair[0].fragment_); - } else { - this->equals_to_<1>(pair[0].block_, 0) = HeapArea(pair[1].block_, pair[1].fragment_); - this->equals_to_<2>(pair[1].block_, 0) = HeapArea(pair[0].block_, pair[0].fragment_); - } - } -} - -void ProcessComparisonState::initHeapInformation(const s_xbt_mheap_t* heap, const std::vector& i) -{ - auto heaplimit = heap->heaplimit; - this->heapsize = heap->heapsize; - this->to_ignore = &i; - this->equals_to.assign(heaplimit * MAX_FRAGMENT_PER_BLOCK, HeapArea()); - this->types.assign(heaplimit * MAX_FRAGMENT_PER_BLOCK, nullptr); -} - -int StateComparator::initHeapInformation(simgrid::mc::RemoteProcessMemory& memory, const s_xbt_mheap_t* heap1, - const s_xbt_mheap_t* heap2, const std::vector& i1, - const std::vector& i2) -{ - if ((heap1->heaplimit != heap2->heaplimit) || (heap1->heapsize != heap2->heapsize)) - return -1; - this->heaplimit = heap1->heaplimit; - this->std_heap_copy = *memory.get_heap(); - this->processStates[0].initHeapInformation(heap1, i1); - this->processStates[1].initHeapInformation(heap2, i2); - return 0; -} - -// TODO, have a robust way to find it in O(1) -static inline Region* MC_get_heap_region(const Snapshot& snapshot) -{ - for (auto const& region : snapshot.snapshot_regions_) - if (region->region_type() == RegionType::Heap) - return region.get(); - xbt_die("No heap region"); -} - -static bool heap_area_differ(const RemoteProcessMemory& process, StateComparator& state, const void* area1, - const void* area2, const Snapshot& snapshot1, const Snapshot& snapshot2, - HeapLocationPairs* previous, Type* type, int pointer_level); - -/* Compares the content of each heap fragment between the two states, at the bit level. - * - * This operation is costly (about 5 seconds per snapshots' pair to compare on a small program), - * but hard to optimize because our algorithm is too hackish. - * - * Going at bit level can trigger syntaxtic differences on states that are semantically equivalent. - * - * Padding bytes constitute the first source of such syntaxtic difference: Any malloced memory contains spaces that - * are not used to enforce the memory alignment constraints of the CPU. So, cruft of irrelevant changes could get - * added on these bits. But this case is handled properly, as any memory block is zeroed by mmalloc before being handled - * back, not only for calloc but also for malloc. So the memory interstices due to padding bytes are properly zeroed. - * - * Another source of such change comes from the order of mallocs, that may well change from one execution path to - * another. This will change the malloc fragment in which the data is stored and the pointer values (syntaxtic - * difference) while the semantic of the state remains the same. - * - * To fix this, this code relies on a hugly hack. When we see a difference during the bit-level comparison, - * we first check if it could be explained by a pointer-to-block difference. Ie, if when interpreting the memory - * area containing that difference as a pointer, I get the pointer to a valid fragment in the heap (in both snapshots). - * - * This is why we cannot pre-compute a bit-level hash of the heap content: we discover the pointers to other memory - * fragment when a difference is found during the bit-level exploration. Fixing this would require to save typing - * information about the memory fragments, which is something that could be done with https://github.com/tudasc/TypeART - * This would give us all pointers in the mallocated memory, allowing the graph traversal needed to precompute the hash. - * - * Using a hash without paying attention to malloc fragment reordering would lead to false negatives: - * semantically equivalent states would be detected as [syntaxically] different. It's of no importance for the - * state-equality reduction (we would re-explore semantically equivalent states), but it would endanger the soundness - * of the liveness model-checker, as state-equality is used to detect the loops that constitute the accepting states of - * the verified property. So we could miss counter-examples to the verified property. Not good. Not good at all. - */ -static bool mmalloc_heap_differ(const RemoteProcessMemory& process, StateComparator& state, const Snapshot& snapshot1, - const Snapshot& snapshot2) -{ - /* Check busy blocks */ - size_t i1 = 1; - - malloc_info heapinfo_temp1; - malloc_info heapinfo_temp2; - malloc_info heapinfo_temp2b; - - const Region* heap_region1 = MC_get_heap_region(snapshot1); - const Region* heap_region2 = MC_get_heap_region(snapshot2); - - // This is the address of std_heap->heapinfo in the application process: - uint64_t heapinfo_address = process.heap_address.address() + offsetof(s_xbt_mheap_t, heapinfo); - - // This is in snapshot do not use them directly: - const malloc_info* heapinfos1 = snapshot1.read(remote(heapinfo_address)); - const malloc_info* heapinfos2 = snapshot2.read(remote(heapinfo_address)); - - while (i1 < state.heaplimit) { - const auto* heapinfo1 = - static_cast(heap_region1->read(&heapinfo_temp1, &heapinfos1[i1], sizeof(malloc_info))); - const auto* heapinfo2 = - static_cast(heap_region2->read(&heapinfo_temp2, &heapinfos2[i1], sizeof(malloc_info))); - - if (heapinfo1->type == MMALLOC_TYPE_FREE || heapinfo1->type == MMALLOC_TYPE_HEAPINFO) { /* Free block */ - i1 ++; - continue; - } - - xbt_assert(heapinfo1->type >= 0, "Unknown mmalloc block type: %d", heapinfo1->type); - - void* addr_block1 = (ADDR2UINT(i1) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase; - - if (heapinfo1->type == MMALLOC_TYPE_UNFRAGMENTED) { /* Large block */ - if (is_stack(process, addr_block1)) { - for (size_t k = 0; k < heapinfo1->busy_block.size; k++) - state.equals_to_<1>(i1 + k, 0) = HeapArea(i1, -1); - for (size_t k = 0; k < heapinfo2->busy_block.size; k++) - state.equals_to_<2>(i1 + k, 0) = HeapArea(i1, -1); - i1 += heapinfo1->busy_block.size; - continue; - } - - if (state.equals_to_<1>(i1, 0).valid_) { - i1++; - continue; - } - - size_t i2 = 1; - bool equal = false; - - /* Try first to associate to same block in the other heap */ - if (heapinfo2->type == heapinfo1->type && state.equals_to_<2>(i1, 0).valid_ == 0) { - const void* addr_block2 = (ADDR2UINT(i1) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase; - if (not heap_area_differ(process, state, addr_block1, addr_block2, snapshot1, snapshot2, nullptr, nullptr, 0)) { - for (size_t k = 1; k < heapinfo2->busy_block.size; k++) - state.equals_to_<2>(i1 + k, 0) = HeapArea(i1, -1); - for (size_t k = 1; k < heapinfo1->busy_block.size; k++) - state.equals_to_<1>(i1 + k, 0) = HeapArea(i1, -1); - equal = true; - i1 += heapinfo1->busy_block.size; - } - } - - while (i2 < state.heaplimit && not equal) { - const void* addr_block2 = (ADDR2UINT(i2) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase; - - if (i2 == i1) { - i2++; - continue; - } - - const auto* heapinfo2b = - static_cast(heap_region2->read(&heapinfo_temp2b, &heapinfos2[i2], sizeof(malloc_info))); - - if (heapinfo2b->type != MMALLOC_TYPE_UNFRAGMENTED) { - i2++; - continue; - } - - if (state.equals_to_<2>(i2, 0).valid_) { - i2++; - continue; - } - - if (not heap_area_differ(process, state, addr_block1, addr_block2, snapshot1, snapshot2, nullptr, nullptr, 0)) { - for (size_t k = 1; k < heapinfo2b->busy_block.size; k++) - state.equals_to_<2>(i2 + k, 0) = HeapArea(i1, -1); - for (size_t k = 1; k < heapinfo1->busy_block.size; k++) - state.equals_to_<1>(i1 + k, 0) = HeapArea(i2, -1); - equal = true; - i1 += heapinfo1->busy_block.size; - } - i2++; - } - - if (not equal) { - XBT_DEBUG("Block %zu not found (size_used = %zu, addr = %p)", i1, heapinfo1->busy_block.busy_size, addr_block1); - return true; - } - } else { /* Fragmented block */ - for (size_t j1 = 0; j1 < (size_t)(BLOCKSIZE >> heapinfo1->type); j1++) { - if (heapinfo1->busy_frag.frag_size[j1] == -1) /* Free fragment_ */ - continue; - - if (state.equals_to_<1>(i1, j1).valid_) - continue; - - void* addr_frag1 = (char*)addr_block1 + (j1 << heapinfo1->type); - - size_t i2 = 1; - bool equal = false; - - /* Try first to associate to same fragment_ in the other heap */ - if (heapinfo2->type == heapinfo1->type && not state.equals_to_<2>(i1, j1).valid_) { - const void* addr_block2 = (ADDR2UINT(i1) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase; - const void* addr_frag2 = (const char*)addr_block2 + (j1 << heapinfo2->type); - if (not heap_area_differ(process, state, addr_frag1, addr_frag2, snapshot1, snapshot2, nullptr, nullptr, 0)) - equal = true; - } - - while (i2 < state.heaplimit && not equal) { - const auto* heapinfo2b = - static_cast(heap_region2->read(&heapinfo_temp2b, &heapinfos2[i2], sizeof(malloc_info))); - - if (heapinfo2b->type == MMALLOC_TYPE_FREE || heapinfo2b->type == MMALLOC_TYPE_HEAPINFO) { - i2 ++; - continue; - } - - // We currently do not match fragments with unfragmented blocks (maybe we should). - if (heapinfo2b->type == MMALLOC_TYPE_UNFRAGMENTED) { - i2++; - continue; - } - - xbt_assert(heapinfo2b->type >= 0, "Unknown mmalloc block type: %d", heapinfo2b->type); - - for (size_t j2 = 0; j2 < (size_t)(BLOCKSIZE >> heapinfo2b->type); j2++) { - if (i2 == i1 && j2 == j1) - continue; - - if (state.equals_to_<2>(i2, j2).valid_) - continue; - - const void* addr_block2 = (ADDR2UINT(i2) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase; - const void* addr_frag2 = (const char*)addr_block2 + (j2 << heapinfo2b->type); - - if (not heap_area_differ(process, state, addr_frag1, addr_frag2, snapshot1, snapshot2, nullptr, nullptr, - 0)) { - equal = true; - break; - } - } - i2++; - } - - if (not equal) { - XBT_DEBUG("Block %zu, fragment_ %zu not found (size_used = %zd, address = %p)\n", i1, j1, - heapinfo1->busy_frag.frag_size[j1], addr_frag1); - return true; - } - } - i1++; - } - } - - /* All blocks/fragments are equal to another block/fragment_ ? */ - for (size_t i = 1; i < state.heaplimit; i++) { - const auto* heapinfo1 = - static_cast(heap_region1->read(&heapinfo_temp1, &heapinfos1[i], sizeof(malloc_info))); - - if (heapinfo1->type == MMALLOC_TYPE_UNFRAGMENTED && i1 == state.heaplimit && heapinfo1->busy_block.busy_size > 0 && - not state.equals_to_<1>(i, 0).valid_) { - XBT_DEBUG("Block %zu not found (size used = %zu)", i, heapinfo1->busy_block.busy_size); - return true; - } - - if (heapinfo1->type <= 0) - continue; - for (size_t j = 0; j < (size_t)(BLOCKSIZE >> heapinfo1->type); j++) - if (i1 == state.heaplimit && heapinfo1->busy_frag.frag_size[j] > 0 && not state.equals_to_<1>(i, j).valid_) { - XBT_DEBUG("Block %zu, Fragment %zu not found (size used = %zd)", i, j, heapinfo1->busy_frag.frag_size[j]); - return true; - } - } - - for (size_t i = 1; i < state.heaplimit; i++) { - const auto* heapinfo2 = - static_cast(heap_region2->read(&heapinfo_temp2, &heapinfos2[i], sizeof(malloc_info))); - if (heapinfo2->type == MMALLOC_TYPE_UNFRAGMENTED && i1 == state.heaplimit && heapinfo2->busy_block.busy_size > 0 && - not state.equals_to_<2>(i, 0).valid_) { - XBT_DEBUG("Block %zu not found (size used = %zu)", i, - heapinfo2->busy_block.busy_size); - return true; - } - - if (heapinfo2->type <= 0) - continue; - - for (size_t j = 0; j < (size_t)(BLOCKSIZE >> heapinfo2->type); j++) - if (i1 == state.heaplimit && heapinfo2->busy_frag.frag_size[j] > 0 && not state.equals_to_<2>(i, j).valid_) { - XBT_DEBUG("Block %zu, Fragment %zu not found (size used = %zd)", - i, j, heapinfo2->busy_frag.frag_size[j]); - return true; - } - } - return false; -} - -/** - * - * @param state - * @param real_area1 Process address for state 1 - * @param real_area2 Process address for state 2 - * @param snapshot1 Snapshot of state 1 - * @param snapshot2 Snapshot of state 2 - * @param previous - * @param size - * @param check_ignore - * @return true when different, false otherwise (same or unknown) - */ -static bool heap_area_differ_without_type(const RemoteProcessMemory& process, StateComparator& state, - const void* real_area1, const void* real_area2, const Snapshot& snapshot1, - const Snapshot& snapshot2, HeapLocationPairs* previous, int size, - int check_ignore) -{ - const Region* heap_region1 = MC_get_heap_region(snapshot1); - const Region* heap_region2 = MC_get_heap_region(snapshot2); - - for (int i = 0; i < size; ) { - if (check_ignore > 0) { - ssize_t ignore1 = heap_comparison_ignore_size(state.processStates[0].to_ignore, (const char*)real_area1 + i); - if (ignore1 != -1) { - ssize_t ignore2 = heap_comparison_ignore_size(state.processStates[1].to_ignore, (const char*)real_area2 + i); - if (ignore2 == ignore1) { - if (ignore1 == 0) { - return false; - } else { - i = i + ignore2; - check_ignore--; - continue; - } - } - } - } - - if (MC_snapshot_region_memcmp((const char*)real_area1 + i, heap_region1, (const char*)real_area2 + i, heap_region2, - 1) != 0) { - int pointer_align = (i / sizeof(void *)) * sizeof(void *); - const void* addr_pointed1 = snapshot1.read(remote((void* const*)((const char*)real_area1 + pointer_align))); - const void* addr_pointed2 = snapshot2.read(remote((void* const*)((const char*)real_area2 + pointer_align))); - - if (process.in_maestro_stack(remote(addr_pointed1)) && process.in_maestro_stack(remote(addr_pointed2))) { - i = pointer_align + sizeof(void *); - continue; - } - - if (snapshot1.on_heap(addr_pointed1) && snapshot2.on_heap(addr_pointed2)) { - // Both addresses are in the heap: - if (heap_area_differ(process, state, addr_pointed1, addr_pointed2, snapshot1, snapshot2, previous, nullptr, 0)) - return true; - i = pointer_align + sizeof(void *); - continue; - } - return true; - } - i++; - } - return false; -} - -/** - * - * @param state - * @param real_area1 Process address for state 1 - * @param real_area2 Process address for state 2 - * @param snapshot1 Snapshot of state 1 - * @param snapshot2 Snapshot of state 2 - * @param previous - * @param type - * @param area_size either a byte_size or an elements_count (?) - * @param check_ignore - * @param pointer_level - * @return true when different, false otherwise (same or unknown) - */ -static bool heap_area_differ_with_type(const simgrid::mc::RemoteProcessMemory& process, StateComparator& state, - const void* real_area1, const void* real_area2, const Snapshot& snapshot1, - const Snapshot& snapshot2, HeapLocationPairs* previous, const Type* type, - int area_size, int check_ignore, int pointer_level) -{ - // HACK: This should not happen but in practice, there are some - // DW_TAG_typedef without an associated DW_AT_type: - //<1><538832>: Abbrev Number: 111 (DW_TAG_typedef) - // <538833> DW_AT_name : (indirect string, offset: 0x2292f3): gregset_t - // <538837> DW_AT_decl_file : 98 - // <538838> DW_AT_decl_line : 37 - if (type == nullptr) - return false; - - if (is_stack(process, real_area1) && is_stack(process, real_area2)) - return false; - - if (check_ignore > 0) { - ssize_t ignore1 = heap_comparison_ignore_size(state.processStates[0].to_ignore, real_area1); - if (ignore1 > 0 && heap_comparison_ignore_size(state.processStates[1].to_ignore, real_area2) == ignore1) - return false; - } - - const Type* subtype; - const Type* subsubtype; - int elm_size; - const void* addr_pointed1; - const void* addr_pointed2; - - const Region* heap_region1 = MC_get_heap_region(snapshot1); - const Region* heap_region2 = MC_get_heap_region(snapshot2); - - switch (type->type) { - case DW_TAG_unspecified_type: - return true; - - case DW_TAG_base_type: - if (not type->name.empty() && type->name == "char") { /* String, hence random (arbitrary ?) size */ - if (real_area1 == real_area2) - return false; - else - return MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, area_size) != 0; - } else { - if (area_size != -1 && type->byte_size != area_size) - return false; - else - return MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, type->byte_size) != 0; - } - - case DW_TAG_enumeration_type: - if (area_size != -1 && type->byte_size != area_size) - return false; - return MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, type->byte_size) != 0; - - case DW_TAG_typedef: - case DW_TAG_const_type: - case DW_TAG_volatile_type: - return heap_area_differ_with_type(process, state, real_area1, real_area2, snapshot1, snapshot2, previous, - type->subtype, area_size, check_ignore, pointer_level); - - case DW_TAG_array_type: - subtype = type->subtype; - switch (subtype->type) { - case DW_TAG_unspecified_type: - return true; - - case DW_TAG_base_type: - case DW_TAG_enumeration_type: - case DW_TAG_pointer_type: - case DW_TAG_reference_type: - case DW_TAG_rvalue_reference_type: - case DW_TAG_structure_type: - case DW_TAG_class_type: - case DW_TAG_union_type: - if (subtype->full_type) - subtype = subtype->full_type; - elm_size = subtype->byte_size; - break; - // TODO, just remove the type indirection? - case DW_TAG_const_type: - case DW_TAG_typedef: - case DW_TAG_volatile_type: - subsubtype = subtype->subtype; - if (subsubtype->full_type) - subsubtype = subsubtype->full_type; - elm_size = subsubtype->byte_size; - break; - default: - return false; - } - for (int i = 0; i < type->element_count; i++) { - // TODO, add support for variable stride (DW_AT_byte_stride) - if (heap_area_differ_with_type(process, state, (const char*)real_area1 + (i * elm_size), - (const char*)real_area2 + (i * elm_size), snapshot1, snapshot2, previous, - type->subtype, subtype->byte_size, check_ignore, pointer_level)) - return true; - } - return false; - - case DW_TAG_reference_type: - case DW_TAG_rvalue_reference_type: - case DW_TAG_pointer_type: - if (type->subtype && type->subtype->type == DW_TAG_subroutine_type) { - addr_pointed1 = snapshot1.read(remote((void* const*)real_area1)); - addr_pointed2 = snapshot2.read(remote((void* const*)real_area2)); - return (addr_pointed1 != addr_pointed2); - } - pointer_level++; - if (pointer_level <= 1) { - addr_pointed1 = snapshot1.read(remote((void* const*)real_area1)); - addr_pointed2 = snapshot2.read(remote((void* const*)real_area2)); - if (snapshot1.on_heap(addr_pointed1) && snapshot2.on_heap(addr_pointed2)) - return heap_area_differ(process, state, addr_pointed1, addr_pointed2, snapshot1, snapshot2, previous, - type->subtype, pointer_level); - else - return (addr_pointed1 != addr_pointed2); - } - for (size_t i = 0; i < (area_size / sizeof(void*)); i++) { - addr_pointed1 = snapshot1.read(remote((void* const*)((const char*)real_area1 + i * sizeof(void*)))); - addr_pointed2 = snapshot2.read(remote((void* const*)((const char*)real_area2 + i * sizeof(void*)))); - bool differ = snapshot1.on_heap(addr_pointed1) && snapshot2.on_heap(addr_pointed2) - ? heap_area_differ(process, state, addr_pointed1, addr_pointed2, snapshot1, snapshot2, - previous, type->subtype, pointer_level) - : addr_pointed1 != addr_pointed2; - if (differ) - return true; - } - return false; - - case DW_TAG_structure_type: - case DW_TAG_class_type: - if (type->full_type) - type = type->full_type; - if (type->byte_size == 0) - return false; - if (area_size != -1 && type->byte_size != area_size) { - if (area_size <= type->byte_size || area_size % type->byte_size != 0) - return false; - for (size_t i = 0; i < (size_t)(area_size / type->byte_size); i++) { - if (heap_area_differ_with_type(process, state, (const char*)real_area1 + i * type->byte_size, - (const char*)real_area2 + i * type->byte_size, snapshot1, snapshot2, previous, - type, -1, check_ignore, 0)) - return true; - } - } else { - for (const simgrid::mc::Member& member : type->members) { - // TODO, optimize this? (for the offset case) - const void* real_member1 = dwarf::resolve_member(real_area1, type, &member, &snapshot1); - const void* real_member2 = dwarf::resolve_member(real_area2, type, &member, &snapshot2); - if (heap_area_differ_with_type(process, state, real_member1, real_member2, snapshot1, snapshot2, previous, - member.type, -1, check_ignore, 0)) - return true; - } - } - return false; - - case DW_TAG_union_type: - return heap_area_differ_without_type(process, state, real_area1, real_area2, snapshot1, snapshot2, previous, - type->byte_size, check_ignore); - - default: - THROW_IMPOSSIBLE; - } -} - -/** Infer the type of a part of the block from the type of the block - * - * TODO, handle DW_TAG_array_type as well as arrays of the object ((*p)[5], p[5]) - * - * TODO, handle subfields ((*p).bar.foo, (*p)[5].bar…) - * - * @param type DWARF type ID of the root address - * @param area_size - * @return DWARF type ID for given offset - */ -static Type* get_offset_type(void* real_base_address, Type* type, int offset, int area_size, const Snapshot& snapshot) -{ - // Beginning of the block, the inferred variable type if the type of the block: - if (offset == 0) - return type; - - switch (type->type) { - case DW_TAG_structure_type: - case DW_TAG_class_type: - if (type->full_type) - type = type->full_type; - if (area_size != -1 && type->byte_size != area_size) { - if (area_size > type->byte_size && area_size % type->byte_size == 0) - return type; - else - return nullptr; - } - - for (const simgrid::mc::Member& member : type->members) { - if (member.has_offset_location()) { - // We have the offset, use it directly (shortcut): - if (member.offset() == offset) - return member.type; - } else { - void* real_member = dwarf::resolve_member(real_base_address, type, &member, &snapshot); - if ((char*)real_member - (char*)real_base_address == offset) - return member.type; - } - } - return nullptr; - - default: - /* FIXME: other cases ? */ - return nullptr; - } -} - -/** - * - * @param area1 Process address for state 1 - * @param area2 Process address for state 2 - * @param snapshot1 Snapshot of state 1 - * @param snapshot2 Snapshot of state 2 - * @param previous Pairs of blocks already compared on the current path (or nullptr) - * @param type_id Type of variable - * @param pointer_level - * @return true when different, false otherwise (same or unknown) - */ -static bool heap_area_differ(const RemoteProcessMemory& process, StateComparator& state, const void* area1, - const void* area2, const Snapshot& snapshot1, const Snapshot& snapshot2, - HeapLocationPairs* previous, Type* type, int pointer_level) -{ - ssize_t block1; - ssize_t block2; - ssize_t size; - int check_ignore = 0; - - int type_size = -1; - int offset1 = 0; - int offset2 = 0; - int new_size1 = -1; - int new_size2 = -1; - - Type* new_type1 = nullptr; - - bool match_pairs = false; - - // This is the address of std_heap->heapinfo in the application process: - uint64_t heapinfo_address = process.heap_address.address() + offsetof(s_xbt_mheap_t, heapinfo); - - const malloc_info* heapinfos1 = snapshot1.read(remote(heapinfo_address)); - const malloc_info* heapinfos2 = snapshot2.read(remote(heapinfo_address)); - - malloc_info heapinfo_temp1; - malloc_info heapinfo_temp2; - - simgrid::mc::HeapLocationPairs current; - if (previous == nullptr) { - previous = ¤t; - match_pairs = true; - } - - // Get block number: - block1 = ((const char*)area1 - (const char*)state.std_heap_copy.heapbase) / BLOCKSIZE + 1; - block2 = ((const char*)area2 - (const char*)state.std_heap_copy.heapbase) / BLOCKSIZE + 1; - - // If either block is a stack block: - if (is_block_stack(process, (int)block1) && is_block_stack(process, (int)block2)) { - previous->insert(HeapLocationPair{{HeapLocation(block1, -1), HeapLocation(block2, -1)}}); - if (match_pairs) - state.match_equals(previous); - return false; - } - - // If either block is not in the expected area of memory: - if (((const char*)area1 < (const char*)state.std_heap_copy.heapbase) || - (block1 > (ssize_t)state.processStates[0].heapsize) || - ((const char*)area2 < (const char*)state.std_heap_copy.heapbase) || - (block2 > (ssize_t)state.processStates[1].heapsize)) { - return true; - } - - // Process address of the block: - void* real_addr_block1 = (ADDR2UINT(block1) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase; - void* real_addr_block2 = (ADDR2UINT(block2) - 1) * BLOCKSIZE + (char*)state.std_heap_copy.heapbase; - - if (type) { - if (type->full_type) - type = type->full_type; - - // This assume that for "boring" types (volatile ...) byte_size is absent: - while (type->byte_size == 0 && type->subtype != nullptr) - type = type->subtype; - - // Find type_size: - if (type->type == DW_TAG_pointer_type || - (type->type == DW_TAG_base_type && not type->name.empty() && type->name == "char")) - type_size = -1; - else - type_size = type->byte_size; - } - - const Region* heap_region1 = MC_get_heap_region(snapshot1); - const Region* heap_region2 = MC_get_heap_region(snapshot2); - - const auto* heapinfo1 = - static_cast(heap_region1->read(&heapinfo_temp1, &heapinfos1[block1], sizeof(malloc_info))); - const auto* heapinfo2 = - static_cast(heap_region2->read(&heapinfo_temp2, &heapinfos2[block2], sizeof(malloc_info))); - - if ((heapinfo1->type == MMALLOC_TYPE_FREE || heapinfo1->type==MMALLOC_TYPE_HEAPINFO) - && (heapinfo2->type == MMALLOC_TYPE_FREE || heapinfo2->type ==MMALLOC_TYPE_HEAPINFO)) { - /* Free block */ - if (match_pairs) - state.match_equals(previous); - return false; - } - - if (heapinfo1->type == MMALLOC_TYPE_UNFRAGMENTED && heapinfo2->type == MMALLOC_TYPE_UNFRAGMENTED) { - /* Complete block */ - - // TODO, lookup variable type from block type as done for fragmented blocks - - if (state.equals_to_<1>(block1, 0).valid_ && state.equals_to_<2>(block2, 0).valid_ && - state.blocksEqual(block1, block2)) { - if (match_pairs) - state.match_equals(previous); - return false; - } - - if (type_size != -1 && type_size != (ssize_t)heapinfo1->busy_block.busy_size && - type_size != (ssize_t)heapinfo2->busy_block.busy_size && type->name.empty()) { - if (match_pairs) - state.match_equals(previous); - return false; - } - - if (heapinfo1->busy_block.size != heapinfo2->busy_block.size || - heapinfo1->busy_block.busy_size != heapinfo2->busy_block.busy_size) - return true; - - if (not previous->insert(HeapLocationPair{{HeapLocation(block1, -1), HeapLocation(block2, -1)}}).second) { - if (match_pairs) - state.match_equals(previous); - return false; - } - - size = heapinfo1->busy_block.busy_size; - - // Remember (basic) type inference. - // The current data structure only allows us to do this for the whole block. - if (type != nullptr && area1 == real_addr_block1) - state.types_<1>(block1, 0) = type; - if (type != nullptr && area2 == real_addr_block2) - state.types_<2>(block2, 0) = type; - - if (size <= 0) { - if (match_pairs) - state.match_equals(previous); - return false; - } - - if (heapinfo1->busy_block.ignore > 0 && heapinfo2->busy_block.ignore == heapinfo1->busy_block.ignore) - check_ignore = heapinfo1->busy_block.ignore; - - } else if ((heapinfo1->type > 0) && (heapinfo2->type > 0)) { /* Fragmented block */ - // Fragment number: - ssize_t frag1 = (ADDR2UINT(area1) % BLOCKSIZE) >> heapinfo1->type; - ssize_t frag2 = (ADDR2UINT(area2) % BLOCKSIZE) >> heapinfo2->type; - - // Process address of the fragment_: - void* real_addr_frag1 = (char*)real_addr_block1 + (frag1 << heapinfo1->type); - void* real_addr_frag2 = (char*)real_addr_block2 + (frag2 << heapinfo2->type); - - // Check the size of the fragments against the size of the type: - if (type_size != -1) { - if (heapinfo1->busy_frag.frag_size[frag1] == -1 || heapinfo2->busy_frag.frag_size[frag2] == -1) { - if (match_pairs) - state.match_equals(previous); - return false; - } - // ? - if (type_size != heapinfo1->busy_frag.frag_size[frag1] - || type_size != heapinfo2->busy_frag.frag_size[frag2]) { - if (match_pairs) - state.match_equals(previous); - return false; - } - } - - // Check if the blocks are already matched together: - if (state.equals_to_<1>(block1, frag1).valid_ && state.equals_to_<2>(block2, frag2).valid_ && - state.fragmentsEqual(block1, frag1, block2, frag2)) { - if (match_pairs) - state.match_equals(previous); - return false; - } - // Compare the size of both fragments: - if (heapinfo1->busy_frag.frag_size[frag1] != heapinfo2->busy_frag.frag_size[frag2]) { - if (type_size == -1) { - if (match_pairs) - state.match_equals(previous); - return false; - } else - return true; - } - - // Size of the fragment_: - size = heapinfo1->busy_frag.frag_size[frag1]; - - // Remember (basic) type inference. - // The current data structure only allows us to do this for the whole fragment_. - if (type != nullptr && area1 == real_addr_frag1) - state.types_<1>(block1, frag1) = type; - if (type != nullptr && area2 == real_addr_frag2) - state.types_<2>(block2, frag2) = type; - - // The type of the variable is already known: - if (type) { - new_type1 = type; - } - // Type inference from the block type. - else if (state.types_<1>(block1, frag1) != nullptr || state.types_<2>(block2, frag2) != nullptr) { - Type* new_type2 = nullptr; - - offset1 = (const char*)area1 - (const char*)real_addr_frag1; - offset2 = (const char*)area2 - (const char*)real_addr_frag2; - - if (state.types_<1>(block1, frag1) != nullptr && state.types_<2>(block2, frag2) != nullptr) { - new_type1 = get_offset_type(real_addr_frag1, state.types_<1>(block1, frag1), offset1, size, snapshot1); - new_type2 = get_offset_type(real_addr_frag2, state.types_<2>(block2, frag2), offset1, size, snapshot2); - } else if (state.types_<1>(block1, frag1) != nullptr) { - new_type1 = get_offset_type(real_addr_frag1, state.types_<1>(block1, frag1), offset1, size, snapshot1); - new_type2 = get_offset_type(real_addr_frag2, state.types_<1>(block1, frag1), offset2, size, snapshot2); - } else if (state.types_<2>(block2, frag2) != nullptr) { - new_type1 = get_offset_type(real_addr_frag1, state.types_<2>(block2, frag2), offset1, size, snapshot1); - new_type2 = get_offset_type(real_addr_frag2, state.types_<2>(block2, frag2), offset2, size, snapshot2); - } else { - if (match_pairs) - state.match_equals(previous); - return false; - } - - if (new_type1 != nullptr && new_type2 != nullptr && new_type1 != new_type2) { - type = new_type1; - while (type->byte_size == 0 && type->subtype != nullptr) - type = type->subtype; - new_size1 = type->byte_size; - - type = new_type2; - while (type->byte_size == 0 && type->subtype != nullptr) - type = type->subtype; - new_size2 = type->byte_size; - - } else { - if (match_pairs) - state.match_equals(previous); - return false; - } - } - - if (new_size1 > 0 && new_size1 == new_size2) { - type = new_type1; - size = new_size1; - } - - if (offset1 == 0 && offset2 == 0 && - not previous->insert(HeapLocationPair{{HeapLocation(block1, frag1), HeapLocation(block2, frag2)}}).second) { - if (match_pairs) - state.match_equals(previous); - return false; - } - - if (size <= 0) { - if (match_pairs) - state.match_equals(previous); - return false; - } - - if ((heapinfo1->busy_frag.ignore[frag1] > 0) && - (heapinfo2->busy_frag.ignore[frag2] == heapinfo1->busy_frag.ignore[frag1])) - check_ignore = heapinfo1->busy_frag.ignore[frag1]; - } else - return true; - - /* Start comparison */ - if (type ? heap_area_differ_with_type(process, state, area1, area2, snapshot1, snapshot2, previous, type, size, - check_ignore, pointer_level) - : heap_area_differ_without_type(process, state, area1, area2, snapshot1, snapshot2, previous, size, - check_ignore)) - return true; - - if (match_pairs) - state.match_equals(previous); - return false; -} -} // namespace simgrid::mc - -/************************** Snapshot comparison *******************************/ -/******************************************************************************/ - -static bool areas_differ_with_type(const simgrid::mc::RemoteProcessMemory& process, simgrid::mc::StateComparator& state, - const void* real_area1, const simgrid::mc::Snapshot& snapshot1, - simgrid::mc::Region* region1, const void* real_area2, - const simgrid::mc::Snapshot& snapshot2, simgrid::mc::Region* region2, - const simgrid::mc::Type* type, int pointer_level) -{ - const simgrid::mc::Type* subtype; - const simgrid::mc::Type* subsubtype; - int elm_size; - - xbt_assert(type != nullptr); - switch (type->type) { - case DW_TAG_unspecified_type: - return true; - - case DW_TAG_base_type: - case DW_TAG_enumeration_type: - case DW_TAG_union_type: - return MC_snapshot_region_memcmp(real_area1, region1, real_area2, region2, type->byte_size) != 0; - case DW_TAG_typedef: - case DW_TAG_volatile_type: - case DW_TAG_const_type: - return areas_differ_with_type(process, state, real_area1, snapshot1, region1, real_area2, snapshot2, region2, - type->subtype, pointer_level); - case DW_TAG_array_type: - subtype = type->subtype; - switch (subtype->type) { - case DW_TAG_unspecified_type: - return true; - - case DW_TAG_base_type: - case DW_TAG_enumeration_type: - case DW_TAG_pointer_type: - case DW_TAG_reference_type: - case DW_TAG_rvalue_reference_type: - case DW_TAG_structure_type: - case DW_TAG_class_type: - case DW_TAG_union_type: - if (subtype->full_type) - subtype = subtype->full_type; - elm_size = subtype->byte_size; - break; - case DW_TAG_const_type: - case DW_TAG_typedef: - case DW_TAG_volatile_type: - subsubtype = subtype->subtype; - if (subsubtype->full_type) - subsubtype = subsubtype->full_type; - elm_size = subsubtype->byte_size; - break; - default: - return false; - } - for (int i = 0; i < type->element_count; i++) { - size_t off = i * elm_size; - if (areas_differ_with_type(process, state, (const char*)real_area1 + off, snapshot1, region1, - (const char*)real_area2 + off, snapshot2, region2, type->subtype, pointer_level)) - return true; - } - break; - case DW_TAG_pointer_type: - case DW_TAG_reference_type: - case DW_TAG_rvalue_reference_type: { - const void* addr_pointed1 = MC_region_read_pointer(region1, real_area1); - const void* addr_pointed2 = MC_region_read_pointer(region2, real_area2); - - if (type->subtype && type->subtype->type == DW_TAG_subroutine_type) - return (addr_pointed1 != addr_pointed2); - if (addr_pointed1 == nullptr && addr_pointed2 == nullptr) - return false; - if (addr_pointed1 == nullptr || addr_pointed2 == nullptr) - return true; - if (not state.compared_pointers.insert(std::make_pair(addr_pointed1, addr_pointed2)).second) - return false; - - pointer_level++; - - // Some cases are not handled here: - // * the pointers lead to different areas (one to the heap, the other to the RW segment ...) - // * a pointer leads to the read-only segment of the current object - // * a pointer lead to a different ELF object - - if (snapshot1.on_heap(addr_pointed1)) { - if (not snapshot2.on_heap(addr_pointed2)) - return true; - // The pointers are both in the heap: - return simgrid::mc::heap_area_differ(process, state, addr_pointed1, addr_pointed2, snapshot1, snapshot2, - nullptr, type->subtype, pointer_level); - - } else if (region1->contain(simgrid::mc::remote(addr_pointed1))) { - // The pointers are both in the current object R/W segment: - if (not region2->contain(simgrid::mc::remote(addr_pointed2))) - return true; - if (not type->type_id) - return (addr_pointed1 != addr_pointed2); - else - return areas_differ_with_type(process, state, addr_pointed1, snapshot1, region1, addr_pointed2, snapshot2, - region2, type->subtype, pointer_level); - } else { - // TODO, We do not handle very well the case where - // it belongs to a different (non-heap) region from the current one. - - return (addr_pointed1 != addr_pointed2); - } - } - case DW_TAG_structure_type: - case DW_TAG_class_type: - for (const simgrid::mc::Member& member : type->members) { - const void* member1 = simgrid::dwarf::resolve_member(real_area1, type, &member, &snapshot1); - const void* member2 = simgrid::dwarf::resolve_member(real_area2, type, &member, &snapshot2); - simgrid::mc::Region* subregion1 = snapshot1.get_region(member1, region1); // region1 is hinted - simgrid::mc::Region* subregion2 = snapshot2.get_region(member2, region2); // region2 is hinted - if (areas_differ_with_type(process, state, member1, snapshot1, subregion1, member2, snapshot2, subregion2, - member.type, pointer_level)) - return true; - } - break; - case DW_TAG_subroutine_type: - return false; - default: - XBT_VERB("Unknown case: %d", type->type); - break; - } - - return false; -} - -static bool global_variables_differ(const simgrid::mc::RemoteProcessMemory& process, - simgrid::mc::StateComparator& state, - const simgrid::mc::ObjectInformation* object_info, simgrid::mc::Region* r1, - simgrid::mc::Region* r2, const simgrid::mc::Snapshot& snapshot1, - const simgrid::mc::Snapshot& snapshot2) -{ - xbt_assert(r1 && r2, "Missing region."); - - const std::vector& variables = object_info->global_variables; - - for (simgrid::mc::Variable const& current_var : variables) { - // If the variable is not in this object, skip it: - // We do not expect to find a pointer to something which is not reachable - // by the global variables. - if ((char*)current_var.address < object_info->start_rw || (char*)current_var.address > object_info->end_rw) - continue; - - const simgrid::mc::Type* bvariable_type = current_var.type; - if (areas_differ_with_type(process, state, current_var.address, snapshot1, r1, current_var.address, snapshot2, r2, - bvariable_type, 0)) { - XBT_VERB("Global variable %s (%p) is different between snapshots", current_var.name.c_str(), current_var.address); - return true; - } - } - - return false; -} - -static bool local_variables_differ(const simgrid::mc::RemoteProcessMemory& process, simgrid::mc::StateComparator& state, - const simgrid::mc::Snapshot& snapshot1, const simgrid::mc::Snapshot& snapshot2, - const_mc_snapshot_stack_t stack1, const_mc_snapshot_stack_t stack2) -{ - if (stack1->local_variables.size() != stack2->local_variables.size()) { - XBT_VERB("Different number of local variables"); - return true; - } - - for (unsigned int cursor = 0; cursor < stack1->local_variables.size(); cursor++) { - const_local_variable_t current_var1 = &stack1->local_variables[cursor]; - const_local_variable_t current_var2 = &stack2->local_variables[cursor]; - if (current_var1->name != current_var2->name || current_var1->subprogram != current_var2->subprogram || - current_var1->ip != current_var2->ip) { - // TODO, fix current_varX->subprogram->name to include name if DW_TAG_inlined_subprogram - XBT_VERB("Different name of variable (%s - %s) or frame (%s - %s) or ip (%lu - %lu)", current_var1->name.c_str(), - current_var2->name.c_str(), current_var1->subprogram->name.c_str(), - current_var2->subprogram->name.c_str(), current_var1->ip, current_var2->ip); - return true; - } - - if (areas_differ_with_type(process, state, current_var1->address, snapshot1, - snapshot1.get_region(current_var1->address), current_var2->address, snapshot2, - snapshot2.get_region(current_var2->address), current_var1->type, 0)) { - XBT_VERB("Local variable %s (%p - %p) in frame %s is different between snapshots", current_var1->name.c_str(), - current_var1->address, current_var2->address, current_var1->subprogram->name.c_str()); - return true; - } - } - return false; -} - -namespace simgrid::mc { -bool Snapshot::equals_to(const Snapshot& other, RemoteProcessMemory& memory) -{ - /* TODO: the memory parameter should be eventually removed. It seems to be there because each snapshot lacks some sort - of metadata. That's OK for now (letting appart the fact that we cannot have a nice operator== because we need that - extra parameter), but it will fall short when we want to have parallel explorations, with more than one - RemoteProcess. At the very least, snapshots will need to know the remote process they are corresponding to, and more - probably they will need to embeed all their metadata to let the remoteprocesses die before the end of the - exploration. */ - - /* TODO: This method should moved to Snapshot.cpp, but it needs the StateComparator that is declared locally to this - * file only. */ - - static StateComparator state_comparator; // TODO, make this a field of a persistant state object - - if (hash_ != other.hash_) { - XBT_VERB("(%ld - %ld) Different hash: 0x%" PRIx64 "--0x%" PRIx64, this->num_state_, other.num_state_, this->hash_, - other.hash_); - return false; - } - XBT_VERB("(%ld - %ld) Same hash: 0x%" PRIx64, this->num_state_, other.num_state_, this->hash_); - - /* TODO: re-enable the quick filter of counting enabled processes in each snapshots */ - - /* Compare size of stacks */ - for (unsigned long i = 0; i < this->stacks_.size(); i++) { - size_t size_used1 = this->stack_sizes_[i]; - size_t size_used2 = other.stack_sizes_[i]; - if (size_used1 != size_used2) { - XBT_VERB("(%ld - %ld) Different size used in stacks: %zu - %zu", num_state_, other.num_state_, size_used1, - size_used2); - return false; - } - } - - /* Init heap information used in heap comparison algorithm */ - const s_xbt_mheap_t* heap1 = static_cast( - this->read_bytes(alloca(sizeof(s_xbt_mheap_t)), sizeof(s_xbt_mheap_t), memory.heap_address, ReadOptions::lazy())); - const s_xbt_mheap_t* heap2 = static_cast( - other.read_bytes(alloca(sizeof(s_xbt_mheap_t)), sizeof(s_xbt_mheap_t), memory.heap_address, ReadOptions::lazy())); - if (state_comparator.initHeapInformation(memory, heap1, heap2, this->to_ignore_, other.to_ignore_) == -1) { - XBT_VERB("(%ld - %ld) Different heap information", this->num_state_, other.num_state_); - return false; - } - - /* Stacks comparison */ - for (unsigned int cursor = 0; cursor < this->stacks_.size(); cursor++) { - const_mc_snapshot_stack_t stack1 = &this->stacks_[cursor]; - const_mc_snapshot_stack_t stack2 = &other.stacks_[cursor]; - - if (local_variables_differ(memory, state_comparator, *this, other, stack1, stack2)) { - XBT_VERB("(%ld - %ld) Different local variables between stacks %u", this->num_state_, other.num_state_, - cursor + 1); - return false; - } - } - - size_t regions_count = this->snapshot_regions_.size(); - if (regions_count != other.snapshot_regions_.size()) - return false; - - for (size_t k = 0; k != regions_count; ++k) { - Region* region1 = this->snapshot_regions_[k].get(); - Region* region2 = other.snapshot_regions_[k].get(); - - // Preconditions: - if (region1->region_type() != RegionType::Data) - continue; - - xbt_assert(region1->region_type() == region2->region_type()); - xbt_assert(region1->object_info() == region2->object_info()); - xbt_assert(region1->object_info()); - - /* Compare global variables */ - if (global_variables_differ(memory, state_comparator, region1->object_info(), region1, region2, *this, other)) { - std::string const& name = region1->object_info()->file_name; - XBT_VERB("(%ld - %ld) Different global variables in %s", this->num_state_, other.num_state_, name.c_str()); - return false; - } - } - - XBT_VERB(" Compare heap..."); - /* Compare heap */ - if (mmalloc_heap_differ(memory, state_comparator, *this, other)) { - XBT_VERB("(%ld - %ld) Different heap (mmalloc_heap_differ)", this->num_state_, other.num_state_); - return false; - } - - XBT_VERB("(%ld - %ld) No difference found", this->num_state_, other.num_state_); - - return true; -} -} // namespace simgrid::mc diff --git a/src/mc/explo/CommunicationDeterminismChecker.cpp b/src/mc/explo/CommunicationDeterminismChecker.cpp index 8a70fc7cac..639b28c1f4 100644 --- a/src/mc/explo/CommunicationDeterminismChecker.cpp +++ b/src/mc/explo/CommunicationDeterminismChecker.cpp @@ -14,6 +14,7 @@ #include "xbt/string.hpp" #include +#include XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_comm_determinism, mc, "Logging specific to MC communication determinism detection"); @@ -327,7 +328,7 @@ Exploration* create_communication_determinism_checker(const std::vector& XBT_DEBUG("********* Start communication determinism verification *********"); - auto* base = new DFSExplorer(args, mode, true); + auto* base = new DFSExplorer(args, mode); auto* extension = new CommDetExtension(*base); DFSExplorer::on_exploration_start([extension](RemoteApp const&) { diff --git a/src/mc/explo/DFSExplorer.cpp b/src/mc/explo/DFSExplorer.cpp index b23ce48938..f82d8da149 100644 --- a/src/mc/explo/DFSExplorer.cpp +++ b/src/mc/explo/DFSExplorer.cpp @@ -10,11 +10,6 @@ #include "src/mc/mc_record.hpp" #include "src/mc/transition/Transition.hpp" -#if SIMGRID_HAVE_STATEFUL_MC -#include "src/mc/VisitedState.hpp" -#endif - -#include "src/xbt/mmalloc/mmprivate.h" #include "xbt/log.h" #include "xbt/string.hpp" #include "xbt/sysdep.h" @@ -44,30 +39,6 @@ xbt::signal DFSExplorer::on_transition_execute_si xbt::signal DFSExplorer::on_log_state_signal; -void DFSExplorer::check_non_termination(const State* current_state) -{ -#if SIMGRID_HAVE_STATEFUL_MC - for (auto const& state : stack_) { - if (state->get_system_state()->equals_to(*current_state->get_system_state(), - *get_remote_app().get_remote_process_memory())) { - XBT_INFO("Non-progressive cycle: state %ld -> state %ld", state->get_num(), current_state->get_num()); - XBT_INFO("******************************************"); - XBT_INFO("*** NON-PROGRESSIVE CYCLE DETECTED ***"); - XBT_INFO("******************************************"); - XBT_INFO("Counter-example execution trace:"); - for (auto const& s : get_textual_trace()) - XBT_INFO(" %s", s.c_str()); - XBT_INFO("You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with " - "--cfg=model-check/replay:'%s'", - get_record_trace().to_string().c_str()); - log_state(); - - throw McError(ExitStatus::NON_TERMINATION); - } - } -#endif -} - RecordTrace DFSExplorer::get_record_trace() // override { RecordTrace res; @@ -152,18 +123,6 @@ void DFSExplorer::run() continue; } -#if SIMGRID_HAVE_STATEFUL_MC - // Backtrack if we are revisiting a state we saw previously while applying state-equality reduction - if (visited_state_ != nullptr) { - XBT_DEBUG("State already visited (equal to state %ld), exploration stopped on this path.", - visited_state_->original_num_ == -1 ? visited_state_->num_ : visited_state_->original_num_); - - visited_state_ = nullptr; - this->backtrack(); - continue; - } -#endif - if (reduction_mode_ == ReductionMode::odpor) { // In the case of ODPOR, the wakeup tree for this // state may be empty if we're exploring new territory @@ -253,8 +212,10 @@ void DFSExplorer::run() continue; } else if (prev_state->get_transition_out()->depends(state->get_transition_out().get())) { XBT_VERB("Dependent Transitions:"); - XBT_VERB(" %s (state=%ld)", prev_state->get_transition_out()->to_string().c_str(), prev_state->get_num()); - XBT_VERB(" %s (state=%ld)", state->get_transition_out()->to_string().c_str(), state->get_num()); + XBT_VERB(" #%ld %s (state=%ld)", prev_state->get_transition_out()->aid_, + prev_state->get_transition_out()->to_string().c_str(), prev_state->get_num()); + XBT_VERB(" #%ld %s (state=%ld)", state->get_transition_out()->aid_, + state->get_transition_out()->to_string().c_str(), state->get_num()); if (prev_state->is_actor_enabled(issuer_id)) { if (not prev_state->is_actor_done(issuer_id)) { @@ -273,8 +234,10 @@ void DFSExplorer::run() break; } else { XBT_VERB("INDEPENDENT Transitions:"); - XBT_VERB(" %s (state=%ld)", prev_state->get_transition_out()->to_string().c_str(), prev_state->get_num()); - XBT_VERB(" %s (state=%ld)", state->get_transition_out()->to_string().c_str(), state->get_num()); + XBT_VERB(" #%ld %s (state=%ld)", prev_state->get_transition_out()->aid_, + prev_state->get_transition_out()->to_string().c_str(), prev_state->get_num()); + XBT_VERB(" #%ld %s (state=%ld)", state->get_transition_out()->aid_, + state->get_transition_out()->to_string().c_str(), state->get_num()); } tmp_stack.pop_back(); } @@ -324,36 +287,18 @@ void DFSExplorer::run() if (stack_.back()->count_todo_multiples() > 0) opened_states_.emplace_back(stack_.back()); - if (_sg_mc_termination) - this->check_non_termination(next_state.get()); - -#if SIMGRID_HAVE_STATEFUL_MC - /* Check whether we already explored next_state in the past (but only if interested in state-equality reduction) - */ - if (_sg_mc_max_visited_states > 0) - visited_state_ = visited_states_.addVisitedState(next_state->get_num(), next_state.get(), get_remote_app()); -#endif - stack_.emplace_back(std::move(next_state)); /* If this is a new state (or if we don't care about state-equality reduction) */ - if (visited_state_ == nullptr) { - /* Get an enabled process and insert it in the interleave set of the next state */ - if (reduction_mode_ == ReductionMode::dpor) - stack_.back()->consider_best(); // Take only one transition if DPOR: others may be considered later if required - else { - stack_.back()->consider_all(); - } - - dot_output("\"%ld\" -> \"%ld\" [%s];\n", state->get_num(), stack_.back()->get_num(), - state->get_transition_out()->dot_string().c_str()); -#if SIMGRID_HAVE_STATEFUL_MC - } else { - dot_output("\"%ld\" -> \"%ld\" [%s];\n", state->get_num(), - visited_state_->original_num_ == -1 ? visited_state_->num_ : visited_state_->original_num_, - state->get_transition_out()->dot_string().c_str()); -#endif + /* Get an enabled process and insert it in the interleave set of the next state */ + if (reduction_mode_ == ReductionMode::dpor) + stack_.back()->consider_best(); // Take only one transition if DPOR: others may be considered later if required + else { + stack_.back()->consider_all(); } + + dot_output("\"%ld\" -> \"%ld\" [%s];\n", state->get_num(), stack_.back()->get_num(), + state->get_transition_out()->dot_string().c_str()); } log_state(); } @@ -486,41 +431,16 @@ void DFSExplorer::backtrack() backtrack_count_++; XBT_DEBUG("Backtracking to state#%ld", backtracking_point->get_num()); -#if SIMGRID_HAVE_STATEFUL_MC - /* If asked to rollback on a state that has a snapshot, restore it */ - if (const auto* system_state = backtracking_point->get_system_state()) { - system_state->restore(*get_remote_app().get_remote_process_memory()); - on_restore_system_state_signal(backtracking_point.get(), get_remote_app()); - this->restore_stack(backtracking_point); - return; - } -#endif - // Search how to restore the backtracking point - State* init_state = nullptr; std::deque replay_recipe; for (auto* s = backtracking_point.get(); s != nullptr; s = s->get_parent_state().get()) { -#if SIMGRID_HAVE_STATEFUL_MC - if (s->get_system_state() != nullptr) { // Found a state that I can restore - init_state = s; - break; - } -#endif if (s->get_transition_in() != nullptr) // The root has no transition_in replay_recipe.push_front(s->get_transition_in().get()); } - // Restore the init_state, if any - if (init_state != nullptr) { -#if SIMGRID_HAVE_STATEFUL_MC - const auto* system_state = init_state->get_system_state(); - system_state->restore(*get_remote_app().get_remote_process_memory()); - on_restore_system_state_signal(init_state, get_remote_app()); -#endif - } else { // Restore the initial state if no intermediate state was found - get_remote_app().restore_initial_state(); - on_restore_initial_state_signal(get_remote_app()); - } + // Restore the initial state if no intermediate state was found + get_remote_app().restore_initial_state(); + on_restore_initial_state_signal(get_remote_app()); /* if no snapshot, we need to restore the initial state and replay the transitions */ /* Traverse the stack from the state at position start and re-execute the transitions */ @@ -532,23 +452,9 @@ void DFSExplorer::backtrack() this->restore_stack(backtracking_point); } -DFSExplorer::DFSExplorer(const std::vector& args, ReductionMode mode, bool need_memory_info) - : Exploration(args, need_memory_info || _sg_mc_termination -#if SIMGRID_HAVE_STATEFUL_MC - || _sg_mc_checkpoint > 0 -#endif - ) - , reduction_mode_(mode) +DFSExplorer::DFSExplorer(const std::vector& args, ReductionMode mode) : Exploration(args), reduction_mode_(mode) { - if (_sg_mc_termination) { - if (mode != ReductionMode::none) { - XBT_INFO("Check non progressive cycles (turning DPOR off)"); - reduction_mode_ = ReductionMode::none; - } else { - XBT_INFO("Check non progressive cycles"); - } - } else - XBT_INFO("Start a DFS exploration. Reduction is: %s.", to_c_str(reduction_mode_)); + XBT_INFO("Start a DFS exploration. Reduction is: %s.", to_c_str(reduction_mode_)); auto initial_state = std::make_shared(get_remote_app()); diff --git a/src/mc/explo/DFSExplorer.hpp b/src/mc/explo/DFSExplorer.hpp index a0dc478c0c..bb80b08f98 100644 --- a/src/mc/explo/DFSExplorer.hpp +++ b/src/mc/explo/DFSExplorer.hpp @@ -12,10 +12,6 @@ #include "src/mc/explo/odpor/Execution.hpp" #include "src/mc/mc_config.hpp" -#if SIMGRID_HAVE_STATEFUL_MC -#include "src/mc/VisitedState.hpp" -#endif - #include #include #include @@ -47,7 +43,7 @@ private: static xbt::signal on_log_state_signal; public: - explicit DFSExplorer(const std::vector& args, ReductionMode mode, bool need_memory_info = false); + explicit DFSExplorer(const std::vector& args, ReductionMode mode); void run() override; RecordTrace get_record_trace() override; void log_state() override; @@ -92,7 +88,6 @@ public: static void on_log_state(std::function const& f) { on_log_state_signal.connect(f); } private: - void check_non_termination(const State* current_state); void backtrack(); /** Stack representing the position in the exploration graph */ @@ -107,13 +102,6 @@ private: /** Per-actor clock vectors used to compute the "happens-before" relation */ std::unordered_map per_actor_clocks_; -#if SIMGRID_HAVE_STATEFUL_MC - VisitedStates visited_states_; - std::unique_ptr visited_state_; -#else - void* visited_state_ = nullptr; /* The code uses it to detect whether we are doing stateful MC */ -#endif - /** Opened states are states that still contains todo actors. * When backtracking, we pick a state from it*/ std::vector> opened_states_; diff --git a/src/mc/explo/Exploration.cpp b/src/mc/explo/Exploration.cpp index 3c8e6507bf..58bc34d610 100644 --- a/src/mc/explo/Exploration.cpp +++ b/src/mc/explo/Exploration.cpp @@ -10,10 +10,6 @@ #include "src/mc/mc_private.hpp" #include "xbt/string.hpp" -#if SIMGRID_HAVE_STATEFUL_MC -#include "src/mc/sosp/RemoteProcessMemory.hpp" -#endif - #include XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_explo, mc, "Generic exploration algorithm of the model-checker"); @@ -25,8 +21,7 @@ static simgrid::config::Flag cfg_dot_output_file{ Exploration* Exploration::instance_ = nullptr; // singleton instance -Exploration::Exploration(const std::vector& args, bool need_memory_introspection) - : remote_app_(std::make_unique(args, need_memory_introspection)) +Exploration::Exploration(const std::vector& args) : remote_app_(std::make_unique(args)) { xbt_assert(instance_ == nullptr, "Cannot have more than one exploration instance"); instance_ = this; @@ -83,7 +78,7 @@ static const char* signal_name(int status) } } -std::vector Exploration::get_textual_trace() +std::vector Exploration::get_textual_trace(int max_elements) { std::vector trace; for (auto const& transition : get_record_trace()) { @@ -93,6 +88,9 @@ std::vector Exploration::get_textual_trace() transition->to_string().c_str())); else trace.push_back(xbt::string_printf("Actor %ld in simcall %s", transition->aid_, transition->to_string().c_str())); + max_elements--; + if (max_elements == 0) + break; } return trace; } @@ -116,18 +114,6 @@ XBT_ATTRIB_NORETURN void Exploration::report_crash(int status) "--cfg=model-check/replay:'%s'", get_record_trace().to_string().c_str()); log_state(); - if (xbt_log_no_loc) { - XBT_INFO("Stack trace not displayed because you passed --log=no_loc"); - } else { -#if SIMGRID_HAVE_STATEFUL_MC - const auto* memory = get_remote_app().get_remote_process_memory(); - if (memory) { - XBT_INFO("Stack trace:"); - memory->dump_stack(); - } else -#endif - XBT_INFO("Stack trace not shown because there is no memory introspection."); - } throw McError(ExitStatus::PROGRAM_CRASH); } diff --git a/src/mc/explo/Exploration.hpp b/src/mc/explo/Exploration.hpp index 64114d4bf2..8ef417c627 100644 --- a/src/mc/explo/Exploration.hpp +++ b/src/mc/explo/Exploration.hpp @@ -36,7 +36,7 @@ class Exploration : public xbt::Extendable { FILE* dot_output_ = nullptr; public: - explicit Exploration(const std::vector& args, bool need_memory_introspection); + explicit Exploration(const std::vector& args); virtual ~Exploration(); static Exploration* get_instance() { return instance_; } @@ -60,7 +60,7 @@ public: virtual RecordTrace get_record_trace() = 0; /** Generate a textual execution trace of the simulated application */ - std::vector get_textual_trace(); + std::vector get_textual_trace(int max_elements = -1); /** Log additional information about the state of the model-checker */ virtual void log_state(); @@ -72,7 +72,6 @@ public: }; // External constructors so that the types (and the types of their content) remain hidden -XBT_PUBLIC Exploration* create_liveness_checker(const std::vector& args); XBT_PUBLIC Exploration* create_dfs_exploration(const std::vector& args, ReductionMode mode); XBT_PUBLIC Exploration* create_communication_determinism_checker(const std::vector& args, ReductionMode mode); XBT_PUBLIC Exploration* create_udpor_checker(const std::vector& args); diff --git a/src/mc/explo/LivenessChecker.cpp b/src/mc/explo/LivenessChecker.cpp deleted file mode 100644 index 3d60ef96e4..0000000000 --- a/src/mc/explo/LivenessChecker.cpp +++ /dev/null @@ -1,437 +0,0 @@ -/* Copyright (c) 2011-2023. 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 "src/mc/explo/LivenessChecker.hpp" -#include "src/mc/api/RemoteApp.hpp" -#include "src/mc/mc_config.hpp" -#include "src/mc/mc_exit.hpp" -#include "src/mc/mc_private.hpp" - -#include -#include - -XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_liveness, mc, "Logging specific to algorithms for liveness properties verification"); - -/********* Static functions *********/ - -namespace simgrid::mc { - -VisitedPair::VisitedPair(int pair_num, xbt_automaton_state_t prop_state, - std::shared_ptr> atomic_propositions, std::shared_ptr app_state, - RemoteApp& remote_app) - : num(pair_num), prop_state_(prop_state) -{ - auto* memory = remote_app.get_remote_process_memory(); - this->app_state_ = std::move(app_state); - if (not this->app_state_->get_system_state()) - this->app_state_->set_system_state(std::make_shared(pair_num, remote_app.get_page_store(), *memory)); - this->heap_bytes_used = memory->get_remote_heap_bytes(); - this->actor_count_ = app_state_->get_actor_count(); - this->other_num = -1; - this->atomic_propositions = std::move(atomic_propositions); -} - -bool LivenessChecker::evaluate_label(const xbt_automaton_exp_label* l, std::vector const& values) -{ - switch (l->type) { - case xbt_automaton_exp_label::AUT_OR: - return evaluate_label(l->u.or_and.left_exp, values) || evaluate_label(l->u.or_and.right_exp, values); - case xbt_automaton_exp_label::AUT_AND: - return evaluate_label(l->u.or_and.left_exp, values) && evaluate_label(l->u.or_and.right_exp, values); - case xbt_automaton_exp_label::AUT_NOT: - return not evaluate_label(l->u.exp_not, values); - case xbt_automaton_exp_label::AUT_PREDICAT: - return values.at(compare_automaton_exp_label(l)) != 0; - case xbt_automaton_exp_label::AUT_ONE: - return true; - default: - xbt_die("Unexpected value for automaton"); - } -} - -Pair::Pair(unsigned long expanded_pairs) : num(expanded_pairs) {} - -std::shared_ptr> LivenessChecker::get_proposition_values() const -{ - auto values = automaton_propositional_symbol_evaluate(); - return std::make_shared>(std::move(values)); -} - -std::shared_ptr LivenessChecker::insert_acceptance_pair(simgrid::mc::Pair* pair) -{ - auto new_pair = std::make_shared(pair->num, pair->prop_state_, pair->atomic_propositions, - pair->app_state_, get_remote_app()); - - auto [res_begin, - res_end] = boost::range::equal_range(acceptance_pairs_, new_pair.get(), [](auto const& a, auto const& b) { - return std::make_pair(a->actor_count_, a->heap_bytes_used) < std::make_pair(b->actor_count_, b->heap_bytes_used); - }); - - if (pair->search_cycle) - for (auto i = res_begin; i != res_end; ++i) { - std::shared_ptr const& pair_test = *i; - if (xbt_automaton_state_compare(pair_test->prop_state_, new_pair->prop_state_) != 0 || - *(pair_test->atomic_propositions) != *(new_pair->atomic_propositions) || - (not pair_test->app_state_->get_system_state()->equals_to(*new_pair->app_state_->get_system_state(), - *get_remote_app().get_remote_process_memory()))) - continue; - XBT_INFO("Pair %d already reached (equal to pair %d) !", new_pair->num, pair_test->num); - exploration_stack_.pop_back(); - dot_output("\"%d\" -> \"%d\" [%s];\n", this->previous_pair_, pair_test->num, this->previous_request_.c_str()); - return nullptr; - } - - acceptance_pairs_.insert(res_begin, new_pair); - return new_pair; -} - -void LivenessChecker::remove_acceptance_pair(int pair_num) -{ - for (auto i = acceptance_pairs_.begin(); i != acceptance_pairs_.end(); ++i) - if ((*i)->num == pair_num) { - acceptance_pairs_.erase(i); - break; - } -} - -void LivenessChecker::replay() -{ - XBT_DEBUG("**** Begin Replay ****"); - - /* Intermediate backtracking */ - if (_sg_mc_checkpoint > 0) { - const Pair* pair = exploration_stack_.back().get(); - if (const auto* system_state = pair->app_state_->get_system_state()) { - system_state->restore(*get_remote_app().get_remote_process_memory()); - return; - } - } - - get_remote_app().restore_initial_state(); - - /* Traverse the stack from the initial state and re-execute the transitions */ - int depth = 1; - for (std::shared_ptr const& pair : exploration_stack_) { - if (pair == exploration_stack_.back()) - break; - - std::shared_ptr state = pair->app_state_; - - if (pair->exploration_started) { - state->get_transition_out()->replay(get_remote_app()); - XBT_DEBUG("Replay (depth = %d) : %s (%p)", depth, state->get_transition_out()->to_string().c_str(), state.get()); - } - - /* Update statistics */ - visited_pairs_count_++; - depth++; - } - XBT_DEBUG("**** End Replay ****"); -} - -/** - * @brief Checks whether a given pair has already been visited by the algorithm. - */ -int LivenessChecker::insert_visited_pair(std::shared_ptr visited_pair, simgrid::mc::Pair* pair) -{ - if (_sg_mc_max_visited_states == 0) - return -1; - - if (visited_pair == nullptr) - visited_pair = std::make_shared(pair->num, pair->prop_state_, pair->atomic_propositions, - pair->app_state_, get_remote_app()); - - auto [range_begin, - range_end] = boost::range::equal_range(visited_pairs_, visited_pair.get(), [](auto const& a, auto const& b) { - return std::make_pair(a->actor_count_, a->heap_bytes_used) < std::make_pair(b->actor_count_, b->heap_bytes_used); - }); - - for (auto i = range_begin; i != range_end; ++i) { - const VisitedPair* pair_test = i->get(); - if (xbt_automaton_state_compare(pair_test->prop_state_, visited_pair->prop_state_) != 0 || - *(pair_test->atomic_propositions) != *(visited_pair->atomic_propositions) || - (not pair_test->app_state_->get_system_state()->equals_to(*visited_pair->app_state_->get_system_state(), - *get_remote_app().get_remote_process_memory()))) - continue; - if (pair_test->other_num == -1) - visited_pair->other_num = pair_test->num; - else - visited_pair->other_num = pair_test->other_num; - XBT_DEBUG("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))", visited_pair->num, pair_test->num, - visited_pair->other_num); - (*i) = std::move(visited_pair); - return (*i)->other_num; - } - - visited_pairs_.insert(range_begin, std::move(visited_pair)); - this->purge_visited_pairs(); - return -1; -} - -void LivenessChecker::purge_visited_pairs() -{ - if (_sg_mc_max_visited_states != 0 && visited_pairs_.size() > (std::size_t)_sg_mc_max_visited_states) { - // Remove the oldest entry with a linear search: - visited_pairs_.erase( - boost::min_element(visited_pairs_, [](std::shared_ptr const a, - std::shared_ptr const& b) { return a->num < b->num; })); - } -} - -LivenessChecker::LivenessChecker(const std::vector& args) : Exploration(args, true) {} -LivenessChecker::~LivenessChecker() -{ - xbt_automaton_free(property_automaton_); -} - -xbt_automaton_t LivenessChecker::property_automaton_ = nullptr; - -void LivenessChecker::automaton_load(const char* file) const -{ - if (property_automaton_ == nullptr) - property_automaton_ = xbt_automaton_new(); - - xbt_automaton_load(property_automaton_, file); -} - -std::vector LivenessChecker::automaton_propositional_symbol_evaluate() const -{ - unsigned int cursor = 0; - std::vector values; - xbt_automaton_propositional_symbol_t ps = nullptr; - xbt_dynar_foreach (property_automaton_->propositional_symbols, cursor, ps) - values.push_back(xbt_automaton_propositional_symbol_evaluate(ps)); - return values; -} - -std::vector LivenessChecker::get_automaton_state() const -{ - std::vector automaton_stack; - unsigned int cursor = 0; - xbt_automaton_state_t automaton_state; - xbt_dynar_foreach (property_automaton_->states, cursor, automaton_state) - if (automaton_state->type == -1) - automaton_stack.push_back(automaton_state); - return automaton_stack; -} - -int LivenessChecker::compare_automaton_exp_label(const xbt_automaton_exp_label* l) const -{ - unsigned int cursor = 0; - xbt_automaton_propositional_symbol_t p = nullptr; - xbt_dynar_foreach (property_automaton_->propositional_symbols, cursor, p) { - if (std::strcmp(xbt_automaton_propositional_symbol_get_name(p), l->u.predicat) == 0) - return cursor; - } - return -1; -} - -void LivenessChecker::set_property_automaton(xbt_automaton_state_t const& automaton_state) const -{ - property_automaton_->current_state = automaton_state; -} - -xbt_automaton_exp_label_t LivenessChecker::get_automaton_transition_label(xbt_dynar_t const& dynar, int index) const -{ - const xbt_automaton_transition* transition = xbt_dynar_get_as(dynar, index, xbt_automaton_transition_t); - return transition->label; -} - -xbt_automaton_state_t LivenessChecker::get_automaton_transition_dst(xbt_dynar_t const& dynar, int index) const -{ - const xbt_automaton_transition* transition = xbt_dynar_get_as(dynar, index, xbt_automaton_transition_t); - return transition->dst; -} -void LivenessChecker::automaton_register_symbol(RemoteProcessMemory const& remote_process, const char* name, - RemotePtr address) -{ - if (property_automaton_ == nullptr) - property_automaton_ = xbt_automaton_new(); - - xbt::add_proposition(property_automaton_, name, - [&remote_process, address]() { return remote_process.read(address); }); -} - -RecordTrace LivenessChecker::get_record_trace() // override -{ - RecordTrace res; - for (std::shared_ptr const& pair : exploration_stack_) - if (pair->app_state_->get_transition_out() != nullptr) - res.push_back(pair->app_state_->get_transition_out().get()); - return res; -} - -void LivenessChecker::log_state() // override -{ - XBT_INFO("Expanded pairs = %lu", expanded_pairs_count_); - XBT_INFO("Visited pairs = %lu", visited_pairs_count_); - XBT_INFO("Executed transitions = %lu", Transition::get_executed_transitions()); - Exploration::log_state(); -} - -void LivenessChecker::show_acceptance_cycle(std::size_t depth) -{ - XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"); - XBT_INFO("| ACCEPTANCE CYCLE |"); - XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"); - XBT_INFO("Counter-example that violates formula:"); - for (auto const& s : this->get_textual_trace()) - XBT_INFO(" %s", s.c_str()); - XBT_INFO("You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with " - "--cfg=model-check/replay:'%s'", - get_record_trace().to_string().c_str()); - log_state(); - XBT_INFO("Counter-example depth: %zu", depth); -} - -std::shared_ptr LivenessChecker::create_pair(const Pair* current_pair, xbt_automaton_state_t state, - std::shared_ptr> propositions) -{ - ++expanded_pairs_count_; - auto next_pair = std::make_shared(expanded_pairs_count_); - next_pair->prop_state_ = state; - next_pair->app_state_ = std::make_shared(get_remote_app()); - next_pair->atomic_propositions = std::move(propositions); - if (current_pair) - next_pair->depth = current_pair->depth + 1; - else - next_pair->depth = 1; - /* Add all enabled actors to the interleave set of the initial state */ - for (auto const& [aid, _] : next_pair->app_state_->get_actors_list()) - if (next_pair->app_state_->is_actor_enabled(aid)) - next_pair->app_state_->consider_one(aid); - - next_pair->requests = next_pair->app_state_->count_todo(); - /* FIXME : get search_cycle value for each accepting state */ - if (next_pair->prop_state_->type == 1 || (current_pair && current_pair->search_cycle)) - next_pair->search_cycle = true; - else - next_pair->search_cycle = false; - return next_pair; -} - -void LivenessChecker::backtrack() -{ - /* Traverse the stack backwards until a pair with a non empty interleave - set is found, deleting all the pairs that have it empty in the way. */ - while (not exploration_stack_.empty()) { - std::shared_ptr current_pair = exploration_stack_.back(); - exploration_stack_.pop_back(); - if (current_pair->requests > 0) { - /* We found a backtracking point */ - XBT_DEBUG("Backtracking to depth %d", current_pair->depth); - exploration_stack_.push_back(std::move(current_pair)); - this->replay(); - XBT_DEBUG("Backtracking done"); - break; - } else { - XBT_DEBUG("Delete pair %d at depth %d", current_pair->num, current_pair->depth); - if (current_pair->prop_state_->type == 1) - this->remove_acceptance_pair(current_pair->num); - } - } -} - -void LivenessChecker::run() -{ - XBT_INFO("Check the liveness property %s", _sg_mc_property_file.get().c_str()); - automaton_load(_sg_mc_property_file.get().c_str()); - - XBT_DEBUG("Starting the liveness algorithm"); - - /* Initialize */ - this->previous_pair_ = 0; - - std::shared_ptr> propos = this->get_proposition_values(); - - // For each initial state of the property automaton, push a - // (application_state, automaton_state) pair to the exploration stack: - auto automaton_stack = get_automaton_state(); - for (auto* automaton_state : automaton_stack) { - if (automaton_state->type == -1) - exploration_stack_.push_back(this->create_pair(nullptr, automaton_state, propos)); - } - - /* Actually run the double DFS search for counter-examples */ - while (not exploration_stack_.empty()) { - std::shared_ptr current_pair = exploration_stack_.back(); - - /* Update current state in buchi automaton */ - set_property_automaton(current_pair->prop_state_); - - XBT_DEBUG( - "********************* ( Depth = %d, search_cycle = %d, interleave size = %zu, pair_num = %d, requests = %d)", - current_pair->depth, current_pair->search_cycle, current_pair->app_state_->count_todo(), current_pair->num, - current_pair->requests); - - if (current_pair->requests == 0) { - this->backtrack(); - continue; - } - - std::shared_ptr reached_pair; - if (current_pair->prop_state_->type == 1 && not current_pair->exploration_started) { - reached_pair = this->insert_acceptance_pair(current_pair.get()); - if (reached_pair == nullptr) { - this->show_acceptance_cycle(current_pair->depth); - throw McError(ExitStatus::LIVENESS); - } - } - - /* Pair already visited ? stop the exploration on the current path */ - if (not current_pair->exploration_started) { - int visited_num = this->insert_visited_pair(reached_pair, current_pair.get()); - if (visited_num != -1) { - dot_output("\"%d\" -> \"%d\" [%s];\n", this->previous_pair_, visited_num, this->previous_request_.c_str()); - - XBT_DEBUG("Pair already visited (equal to pair %d), exploration on the current path stopped.", visited_num); - current_pair->requests = 0; - this->backtrack(); - continue; - } - } - - current_pair->app_state_->execute_next(current_pair->app_state_->next_transition(), get_remote_app()); - XBT_DEBUG("Execute: %s", current_pair->app_state_->get_transition_out()->to_string().c_str()); - - /* Update the dot output */ - if (this->previous_pair_ != 0 && this->previous_pair_ != current_pair->num) { - dot_output("\"%d\" -> \"%d\" [%s];\n", this->previous_pair_, current_pair->num, this->previous_request_.c_str()); - this->previous_request_.clear(); - } - this->previous_pair_ = current_pair->num; - this->previous_request_ = current_pair->app_state_->get_transition_out()->dot_string(); - if (current_pair->search_cycle) - dot_output("%d [shape=doublecircle];\n", current_pair->num); - - if (not current_pair->exploration_started) - visited_pairs_count_++; - - current_pair->requests--; - current_pair->exploration_started = true; - - /* Get values of atomic propositions (variables used in the property formula) */ - std::shared_ptr> prop_values = this->get_proposition_values(); - - // For each enabled transition in the property automaton, push a - // (application_state, automaton_state) pair to the exploration stack: - for (int i = xbt_dynar_length(current_pair->prop_state_->out) - 1; i >= 0; i--) { - const auto* transition_succ_label = get_automaton_transition_label(current_pair->prop_state_->out, i); - auto* transition_succ_dst = get_automaton_transition_dst(current_pair->prop_state_->out, i); - if (evaluate_label(transition_succ_label, *prop_values)) - exploration_stack_.push_back(this->create_pair(current_pair.get(), transition_succ_dst, prop_values)); - } - } - - XBT_INFO("No property violation found."); - log_state(); -} - -Exploration* create_liveness_checker(const std::vector& args) -{ - return new LivenessChecker(args); -} - -} // namespace simgrid::mc diff --git a/src/mc/explo/LivenessChecker.hpp b/src/mc/explo/LivenessChecker.hpp deleted file mode 100644 index baed48eb0f..0000000000 --- a/src/mc/explo/LivenessChecker.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/* Copyright (c) 2007-2023. 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 SIMGRID_MC_LIVENESS_CHECKER_HPP -#define SIMGRID_MC_LIVENESS_CHECKER_HPP - -#include "src/mc/api/State.hpp" -#include "src/mc/explo/Exploration.hpp" -#include "xbt/automaton.hpp" - -#include -#include -#include - -namespace simgrid::mc { - -class XBT_PRIVATE Pair { -public: - int num = 0; - bool search_cycle = false; - std::shared_ptr app_state_ = nullptr; /* State of the application (including system state) */ - xbt_automaton_state_t prop_state_ = nullptr; /* State of the property automaton */ - std::shared_ptr> atomic_propositions; - int requests = 0; - int depth = 0; - bool exploration_started = false; - - explicit Pair(unsigned long expanded_pairs); - - Pair(Pair const&) = delete; - Pair& operator=(Pair const&) = delete; -}; - -class XBT_PRIVATE VisitedPair { -public: - int num; - int other_num = 0; /* Dot output for */ - std::shared_ptr app_state_ = nullptr; /* State of the application (including system state) */ - xbt_automaton_state_t prop_state_; /* State of the property automaton */ - std::shared_ptr> atomic_propositions; - std::size_t heap_bytes_used = 0; - int actor_count_; - - VisitedPair(int pair_num, xbt_automaton_state_t prop_state, - std::shared_ptr> atomic_propositions, std::shared_ptr app_state, - RemoteApp& remote_app); -}; - -class XBT_PRIVATE LivenessChecker : public Exploration { -public: - explicit LivenessChecker(const std::vector& args); - ~LivenessChecker() override; - - void run() override; - RecordTrace get_record_trace() override; - void log_state() override; - -private: - std::shared_ptr> get_proposition_values() const; - std::shared_ptr insert_acceptance_pair(Pair* pair); - int insert_visited_pair(std::shared_ptr visited_pair, Pair* pair); - void show_acceptance_cycle(std::size_t depth); - void replay(); - void remove_acceptance_pair(int pair_num); - void purge_visited_pairs(); - void backtrack(); - std::shared_ptr create_pair(const Pair* pair, xbt_automaton_state_t state, - std::shared_ptr> propositions); - - // A stack of (application_state, automaton_state) pairs for DFS exploration: - std::list> exploration_stack_; - std::list> acceptance_pairs_; - std::list> visited_pairs_; - unsigned long visited_pairs_count_ = 0; - unsigned long expanded_pairs_count_ = 0; - int previous_pair_ = 0; - std::string previous_request_; - - /* The property automaton must be a static because it's sometimes used before the explorer is even created. - * - * This can happen if some symbols are created during the application's initialization process, before the first - * decision point for the model-checker. Since the first snapshot is taken at the first decision point and since the - * explorer is created after the first snapshot, this may result in some symbols being registered even before the - * model-checker notices that this is a LivenessChecker to create. - * - * This situation is unfortunate, but I guess that it's the best I can achieve given the state of our initialization - * code. - */ - static xbt_automaton_t property_automaton_; - bool evaluate_label(const xbt_automaton_exp_label* l, std::vector const& values); - -public: - void automaton_load(const char* file) const; - std::vector automaton_propositional_symbol_evaluate() const; - std::vector get_automaton_state() const; - int compare_automaton_exp_label(const xbt_automaton_exp_label* l) const; - void set_property_automaton(xbt_automaton_state_t const& automaton_state) const; - xbt_automaton_exp_label_t get_automaton_transition_label(xbt_dynar_t const& dynar, int index) const; - xbt_automaton_state_t get_automaton_transition_dst(xbt_dynar_t const& dynar, int index) const; - static void automaton_register_symbol(RemoteProcessMemory const& remote_process, const char* name, - RemotePtr addr); -}; - -} // namespace simgrid::mc - -#endif diff --git a/src/mc/explo/UdporChecker.cpp b/src/mc/explo/UdporChecker.cpp index c8bac5bbd2..f5c512f480 100644 --- a/src/mc/explo/UdporChecker.cpp +++ b/src/mc/explo/UdporChecker.cpp @@ -19,7 +19,7 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_udpor, mc, "Logging specific to verification namespace simgrid::mc::udpor { -UdporChecker::UdporChecker(const std::vector& args) : Exploration(args, true) {} +UdporChecker::UdporChecker(const std::vector& args) : Exploration(args) {} void UdporChecker::run() { diff --git a/src/mc/explo/odpor/ReversibleRaceCalculator.hpp b/src/mc/explo/odpor/ReversibleRaceCalculator.hpp index 283b7c9dcc..88c6839bb0 100644 --- a/src/mc/explo/odpor/ReversibleRaceCalculator.hpp +++ b/src/mc/explo/odpor/ReversibleRaceCalculator.hpp @@ -9,7 +9,7 @@ #include "src/mc/explo/odpor/Execution.hpp" #include "src/mc/explo/odpor/odpor_forward.hpp" #include "src/mc/transition/Transition.hpp" -#include "src/mc/transition/TransitionActorJoin.hpp" +#include "src/mc/transition/TransitionActor.hpp" #include "src/mc/transition/TransitionAny.hpp" #include "src/mc/transition/TransitionComm.hpp" #include "src/mc/transition/TransitionObjectAccess.hpp" diff --git a/src/mc/explo/simgrid_mc.cpp b/src/mc/explo/simgrid_mc.cpp index 513c99727e..51871357ee 100644 --- a/src/mc/explo/simgrid_mc.cpp +++ b/src/mc/explo/simgrid_mc.cpp @@ -35,16 +35,12 @@ int main(int argc, char** argv) std::unique_ptr explo; -#if SIMGRID_HAVE_STATEFUL_MC if (_sg_mc_comms_determinism || _sg_mc_send_determinism) explo = std::unique_ptr( create_communication_determinism_checker(argv_copy, get_model_checking_reduction())); else if (_sg_mc_unfolding_checker) explo = std::unique_ptr(create_udpor_checker(argv_copy)); - else if (not _sg_mc_property_file.get().empty()) - explo = std::unique_ptr(create_liveness_checker(argv_copy)); else -#endif explo = std::unique_ptr(create_dfs_exploration(argv_copy, get_model_checking_reduction())); ExitStatus status; diff --git a/src/mc/explo/udpor/ExtensionSetCalculator.hpp b/src/mc/explo/udpor/ExtensionSetCalculator.hpp index 60a4ac375b..cd68c9c7ff 100644 --- a/src/mc/explo/udpor/ExtensionSetCalculator.hpp +++ b/src/mc/explo/udpor/ExtensionSetCalculator.hpp @@ -9,7 +9,7 @@ #include "src/mc/explo/udpor/EventSet.hpp" #include "src/mc/explo/udpor/udpor_forward.hpp" #include "src/mc/transition/Transition.hpp" -#include "src/mc/transition/TransitionActorJoin.hpp" +#include "src/mc/transition/TransitionActor.hpp" #include "src/mc/transition/TransitionAny.hpp" #include "src/mc/transition/TransitionComm.hpp" #include "src/mc/transition/TransitionObjectAccess.hpp" diff --git a/src/mc/explo/udpor/UnfoldingEvent.cpp b/src/mc/explo/udpor/UnfoldingEvent.cpp index 92ac709f74..8651a2ac42 100644 --- a/src/mc/explo/udpor/UnfoldingEvent.cpp +++ b/src/mc/explo/udpor/UnfoldingEvent.cpp @@ -58,7 +58,7 @@ std::string UnfoldingEvent::to_string() const } dependencies_string += "]"; - return xbt::string_printf("Event %lu, Actor %ld: %s (%zu dependencies: %s)", this->id, associated_transition->aid_, + return xbt::string_printf("Event %lu, Actor %ld: %s (%lu dependencies: %s)", this->id, associated_transition->aid_, associated_transition->to_string().c_str(), immediate_causes.size(), dependencies_string.c_str()); } diff --git a/src/mc/explo/udpor/UnfoldingEvent.hpp b/src/mc/explo/udpor/UnfoldingEvent.hpp index 5486709576..98f40ad996 100644 --- a/src/mc/explo/udpor/UnfoldingEvent.hpp +++ b/src/mc/explo/udpor/UnfoldingEvent.hpp @@ -97,7 +97,7 @@ private: * @brief An identifier which is used to sort events * deterministically */ - uint64_t id = 0; + unsigned long id = 0; }; } // namespace simgrid::mc::udpor diff --git a/src/mc/explo/udpor/udpor_forward.hpp b/src/mc/explo/udpor/udpor_forward.hpp index 23c13f3bec..a279b8f884 100644 --- a/src/mc/explo/udpor/udpor_forward.hpp +++ b/src/mc/explo/udpor/udpor_forward.hpp @@ -17,13 +17,13 @@ namespace simgrid::mc::udpor { class Comb; -class ExtensionSetCalculator; +struct ExtensionSetCalculator; class EventSet; class Configuration; class History; class Unfolding; class UnfoldingEvent; -class maximal_subsets_iterator; +struct maximal_subsets_iterator; } // namespace simgrid::mc::udpor diff --git a/src/mc/inspect/DwarfExpression.cpp b/src/mc/inspect/DwarfExpression.cpp deleted file mode 100644 index 2e74410e91..0000000000 --- a/src/mc/inspect/DwarfExpression.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* Copyright (c) 2014-2023. 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 "src/mc/AddressSpace.hpp" -#include "src/mc/inspect/DwarfExpression.hpp" -#include "src/mc/inspect/Frame.hpp" -#include "src/mc/inspect/LocationList.hpp" -#include "src/mc/inspect/ObjectInformation.hpp" -#include "src/mc/inspect/mc_dwarf.hpp" -#include "src/mc/mc_private.hpp" - -namespace simgrid::dwarf { - -void execute(const Dwarf_Op* ops, std::size_t n, const ExpressionContext& context, ExpressionStack& stack) -{ - for (size_t i = 0; i != n; ++i) { - const Dwarf_Op* op = ops + i; - std::uint8_t atom = op->atom; - intptr_t first; - intptr_t second; - - switch (atom) { - // Push the CFA (Canonical Frame Address): - case DW_OP_call_frame_cfa: - /* See 6.4 of DWARF4 (http://dwarfstd.org/doc/DWARF4.pdf#page=140): - * - * > Typically, the CFA is defined to be the value of the stack - * > pointer at the call site in the previous frame (which may be - * > different from its value on entry to the current frame). - * - * We need to unwind the frame in order to get the SP of the parent - * frame. - * - * Warning: the CFA returned by libunwind (UNW_X86_64_RSP, etc.) - * is the SP of the *current* frame. */ - if (context.cursor) { - // Get frame: - unw_cursor_t cursor = *(context.cursor); - unw_step(&cursor); - - unw_word_t res; - unw_get_reg(&cursor, UNW_REG_SP, &res); - stack.push(res); - break; - } - throw evaluation_error("Missing cursor"); - - // Frame base: - case DW_OP_fbreg: - stack.push((std::uintptr_t)context.frame_base + op->number); - break; - - // Address from the base address of this ELF object. - // Push the address on the stack (base_address + argument). - case DW_OP_addr: - if (context.object_info) { - Dwarf_Off addr = (Dwarf_Off)(std::uintptr_t)context.object_info->base_address() + op->number; - stack.push(addr); - break; - } - throw evaluation_error("No base address"); - - // ***** Stack manipulation: - - // Push another copy/duplicate the value at the top of the stack: - case DW_OP_dup: - stack.dup(); - break; - - // Pop/drop the top of the stack: - case DW_OP_drop: - (void)stack.pop(); - break; - - case DW_OP_swap: - stack.swap(); - break; - - // Duplicate the value under the top of the stack: - case DW_OP_over: - stack.push(stack.top(1)); - break; - - // ***** Operations: - // Those usually take the top of the stack and the next value as argument - // and replace the top of the stack with the computed value - // (stack.top() += stack.before_top()). - - case DW_OP_plus: - first = stack.pop(); - second = stack.pop(); - stack.push(first + second); - break; - - case DW_OP_mul: - first = stack.pop(); - second = stack.pop(); - stack.push(first * second); - break; - - case DW_OP_plus_uconst: - stack.top() += op->number; - break; - - case DW_OP_not: - stack.top() = ~stack.top(); - break; - - case DW_OP_neg: - stack.top() = -(intptr_t)stack.top(); - break; - - case DW_OP_minus: - first = stack.pop(); - second = stack.pop(); - stack.push(second - first); - break; - - case DW_OP_and: - first = stack.pop(); - second = stack.pop(); - stack.push(first & second); - break; - - case DW_OP_or: - first = stack.pop(); - second = stack.pop(); - stack.push(first | second); - break; - - case DW_OP_xor: - first = stack.pop(); - second = stack.pop(); - stack.push(first ^ second); - break; - - case DW_OP_nop: - break; - - // ***** Deference (memory fetch) - - case DW_OP_deref_size: - throw evaluation_error("Unsupported operation"); - - case DW_OP_deref: - // Computed address: - if (not context.address_space) - throw evaluation_error("Missing address space"); - context.address_space->read_bytes(&stack.top(), sizeof(uintptr_t), mc::remote(stack.top())); - break; - - default: - - // Registers: - if (static const std::unordered_set registers = - {DW_OP_breg0, DW_OP_breg1, DW_OP_breg2, DW_OP_breg3, DW_OP_breg4, DW_OP_breg5, DW_OP_breg6, - DW_OP_breg7, DW_OP_breg8, DW_OP_breg9, DW_OP_breg10, DW_OP_breg11, DW_OP_breg12, DW_OP_breg13, - DW_OP_breg14, DW_OP_breg15, DW_OP_breg16, DW_OP_breg17, DW_OP_breg18, DW_OP_breg19, DW_OP_breg20, - DW_OP_breg21, DW_OP_breg22, DW_OP_breg23, DW_OP_breg24, DW_OP_breg25, DW_OP_breg26, DW_OP_breg27, - DW_OP_breg28, DW_OP_breg29, DW_OP_breg30, DW_OP_breg31}; - registers.count(atom) > 0) { - // Push register + constant: - int register_id = dwarf_register_to_libunwind(op->atom - DW_OP_breg0); - unw_word_t res; - if (not context.cursor) - throw evaluation_error("Missing stack context"); - unw_get_reg(context.cursor, register_id, &res); - stack.push(res + op->number); - break; - } - - // ***** Constants: - - // Short constant literals: - if (static const std::unordered_set literals = {DW_OP_lit0, DW_OP_lit1, DW_OP_lit2, DW_OP_lit3, - DW_OP_lit4, DW_OP_lit5, DW_OP_lit6, DW_OP_lit7, - DW_OP_lit8, DW_OP_lit9, DW_OP_lit10, DW_OP_lit11, - DW_OP_lit12, DW_OP_lit13, DW_OP_lit14, DW_OP_lit15, - DW_OP_lit16, DW_OP_lit17, DW_OP_lit18, DW_OP_lit19, - DW_OP_lit20, DW_OP_lit21, DW_OP_lit22, DW_OP_lit23, - DW_OP_lit24, DW_OP_lit25, DW_OP_lit26, DW_OP_lit27, - DW_OP_lit28, DW_OP_lit29, DW_OP_lit30, DW_OP_lit31}; - literals.count(atom) > 0) { - // Push a literal/constant on the stack: - stack.push(atom - DW_OP_lit0); - break; - } - - // General constants: - if (static const std::unordered_set constants = {DW_OP_const1u, DW_OP_const2u, DW_OP_const4u, - DW_OP_const8u, DW_OP_const1s, DW_OP_const2s, - DW_OP_const4s, DW_OP_const8s, DW_OP_constu, - DW_OP_consts}; - constants.count(atom) > 0) { - // Push the constant argument on the stack. - stack.push(op->number); - break; - } - - // Not handled: - throw evaluation_error("Unsupported operation"); - } - } -} - -} // namespace simgrid::dwarf diff --git a/src/mc/inspect/DwarfExpression.hpp b/src/mc/inspect/DwarfExpression.hpp deleted file mode 100644 index 2e8de126d0..0000000000 --- a/src/mc/inspect/DwarfExpression.hpp +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (c) 2015-2023. 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 SIMGRID_MC_DWARF_EXPRESSION_HPP -#define SIMGRID_MC_DWARF_EXPRESSION_HPP - -#include -#include - -#include -#include // runtime_error -#include -#include - -#include -#include - -#include "src/mc/inspect/mc_dwarf.hpp" -#include "src/mc/mc_forward.hpp" - -/** @file DwarfExpression.hpp - * - * Evaluation of DWARF location expressions. - */ - -namespace simgrid::dwarf { - -/** A DWARF expression - * - * DWARF defines a simple stack-based VM for evaluating expressions - * (such as locations of variables, etc.): a DWARF expression is - * just a sequence of dwarf instructions. We currently directly use - * `Dwarf_Op` from `dwarf.h` for dwarf instructions. - */ -using DwarfExpression = std::vector; - -/** Context of evaluation of a DWARF expression - * - * Some DWARF instructions need to read the CPU registers, - * the process memory, etc. All those information are gathered in - * the evaluation context. - */ -struct ExpressionContext { - /** CPU state (registers) */ - unw_cursor_t* cursor = nullptr; - void* frame_base = nullptr; - const mc::AddressSpace* address_space = nullptr; /** Address space used to read memory */ - mc::ObjectInformation* object_info = nullptr; -}; - -/** When an error happens in the execution of a DWARF expression */ -class evaluation_error : public std::runtime_error { -public: - using std::runtime_error::runtime_error; -}; - -/** A stack for evaluating a DWARF expression - * - * DWARF expressions work by manipulating a stack of integer values. - */ -class ExpressionStack { -public: - using value_type = std::uintptr_t; - static constexpr std::size_t MAX_SIZE = 64; - -private: - // Values of the stack (the top is stack_[size_ - 1]): - std::array stack_{{0}}; - size_t size_ = 0; - -public: - // Access: - std::size_t size() const { return size_; } - bool empty() const { return size_ == 0; } - void clear() { size_ = 0; } - uintptr_t& operator[](int i) { return stack_[i]; } - uintptr_t const& operator[](int i) const { return stack_[i]; } - - /** Top of the stack */ - value_type& top() - { - if (size_ == 0) - throw evaluation_error("Empty stack"); - return stack_[size_ - 1]; - } - - /** Access the i-th element from the top of the stack */ - value_type& top(unsigned i) - { - if (size_ < i) - throw evaluation_error("Invalid element"); - return stack_[size_ - 1 - i]; - } - - /** Push a value on the top of the stack */ - void push(value_type value) - { - if (size_ == stack_.size()) - throw evaluation_error("DWARF stack overflow"); - stack_[size_] = value; - size_++; - } - - /* Pop a value from the top of the stack */ - value_type pop() - { - if (size_ == 0) - throw evaluation_error("DWARF stack underflow"); - --size_; - return stack_[size_]; - } - - // These are DWARF operations (DW_OP_foo): - - /* Push a copy of the top-value (DW_OP_dup) */ - void dup() { push(top()); } - - /* Swap the two top-most values */ - void swap() { std::swap(top(), top(1)); } -}; - -/** Executes a DWARF expression - * - * @param ops DWARF expression instructions - * @param n number of instructions - * @param context evaluation context (registers, memory, etc.) - * @param stack DWARf stack where the operations are executed - */ -void execute(const Dwarf_Op* ops, std::size_t n, ExpressionContext const& context, ExpressionStack& stack); - -/** Executes/evaluates a DWARF expression - * - * @param expression DWARF expression to execute - * @param context evaluation context (registers, memory, etc.) - * @param stack DWARf stack where the operations are executed - */ -inline void execute(simgrid::dwarf::DwarfExpression const& expression, ExpressionContext const& context, - ExpressionStack& stack) -{ - execute(expression.data(), expression.size(), context, stack); -} - -} // namespace simgrid::dwarf - -#endif diff --git a/src/mc/inspect/Frame.cpp b/src/mc/inspect/Frame.cpp deleted file mode 100644 index 9d804543dc..0000000000 --- a/src/mc/inspect/Frame.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (c) 2007-2023. 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 "xbt/sysdep.h" - -#include "src/mc/inspect/Frame.hpp" - -namespace simgrid::mc { - -void* Frame::frame_base(unw_cursor_t& unw_cursor) const -{ - simgrid::dwarf::Location location = - simgrid::dwarf::resolve(frame_base_location, object_info, &unw_cursor, nullptr, nullptr); - if (location.in_memory()) - return location.address(); - else if (location.in_register()) { - // This is a special case. - // The register is not the location of the frame base - // (a frame base cannot be located in a register). - // Instead, DWARF defines this to mean that the register - // contains the address of the frame base. - unw_word_t word; - unw_get_reg(&unw_cursor, location.register_id(), &word); - return (void*)word; - } else - xbt_die("Unexpected location type"); -} - -} // namespace simgrid::mc diff --git a/src/mc/inspect/Frame.hpp b/src/mc/inspect/Frame.hpp deleted file mode 100644 index d02e25ea4f..0000000000 --- a/src/mc/inspect/Frame.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/* Copyright (c) 2007-2023. 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 SIMGRID_MC_FRAME_HPP -#define SIMGRID_MC_FRAME_HPP - -#include -#include - -#include "xbt/base.h" -#include "xbt/range.hpp" - -#include "src/mc/inspect/LocationList.hpp" -#include "src/mc/inspect/Variable.hpp" -#include "src/mc/mc_forward.hpp" - -namespace simgrid::mc { - -/** Debug information about a given function or scope within a function */ -class Frame { -public: - /** Kind of scope (DW_TAG_subprogram, DW_TAG_inlined_subroutine, etc.) */ - int tag = DW_TAG_invalid; - - /** Name of the function (if it is a function) */ - std::string name; - - /** Range of instruction addresses for which this scope is valid */ - simgrid::xbt::Range range{0, 0}; - - simgrid::dwarf::LocationList frame_base_location; - - /** List of the variables (sorted by name) */ - std::vector variables; - - /* Unique identifier for this scope (in the object_info) - * - * This is the global DWARF offset of the DIE. */ - unsigned long int id = 0; - - std::vector scopes; - - /** Value of `DW_AT_abstract_origin` - * - * For inlined subprograms, this is the ID of the - * parent function. - */ - unsigned long int abstract_origin_id = 0; - - simgrid::mc::ObjectInformation* object_info = nullptr; - - void* frame_base(unw_cursor_t& unw_cursor) const; - void remove_variable(char* name); -}; -} // namespace simgrid::mc - -#endif diff --git a/src/mc/inspect/LocationList.cpp b/src/mc/inspect/LocationList.cpp deleted file mode 100644 index 18a585d385..0000000000 --- a/src/mc/inspect/LocationList.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright (c) 2004-2023. 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 "src/mc/inspect/LocationList.hpp" -#include "src/mc/inspect/ObjectInformation.hpp" -#include "src/mc/inspect/mc_dwarf.hpp" - -#include "xbt/asserts.h" -#include "xbt/log.h" -#include "xbt/sysdep.h" - -#include -#include -#include -#include - -XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(mc_dwarf); - -namespace simgrid::dwarf { - -/** Resolve a location expression */ -Location resolve(simgrid::dwarf::DwarfExpression const& expression, simgrid::mc::ObjectInformation* object_info, - unw_cursor_t* c, void* frame_pointer_address, const simgrid::mc::AddressSpace* address_space) -{ - simgrid::dwarf::ExpressionContext context; - context.frame_base = frame_pointer_address; - context.cursor = c; - context.address_space = address_space; - context.object_info = object_info; - - if (not expression.empty() && expression[0].atom >= DW_OP_reg0 && expression[0].atom <= DW_OP_reg31) { - int dwarf_register = expression[0].atom - DW_OP_reg0; - xbt_assert(c, "Missing frame context for register operation DW_OP_reg%i", dwarf_register); - return Location(dwarf_register_to_libunwind(dwarf_register)); - } - - simgrid::dwarf::ExpressionStack stack; - simgrid::dwarf::execute(expression, context, stack); - return Location((void*)stack.top()); -} - -// TODO, move this in a method of LocationList -static simgrid::dwarf::DwarfExpression const* find_expression(simgrid::dwarf::LocationList const& locations, - unw_word_t ip) -{ - for (simgrid::dwarf::LocationListEntry const& entry : locations) - if (entry.valid_for_ip(ip)) - return &entry.expression(); - return nullptr; -} - -Location resolve(simgrid::dwarf::LocationList const& locations, simgrid::mc::ObjectInformation* object_info, - unw_cursor_t* c, void* frame_pointer_address, const simgrid::mc::AddressSpace* address_space) -{ - unw_word_t ip = 0; - if (c) - xbt_assert(unw_get_reg(c, UNW_REG_IP, &ip) == 0, "Could not resolve IP"); - simgrid::dwarf::DwarfExpression const* expression = find_expression(locations, ip); - xbt_assert(expression != nullptr, "Could not resolve location"); - return simgrid::dwarf::resolve(*expression, object_info, c, frame_pointer_address, address_space); -} - -LocationList location_list(const simgrid::mc::ObjectInformation& info, Dwarf_Attribute& attr) -{ - LocationList locations; - std::ptrdiff_t offset = 0; - while (true) { - Dwarf_Addr base; - Dwarf_Addr start; - Dwarf_Addr end; - Dwarf_Op* ops; - std::size_t len; - - offset = dwarf_getlocations(&attr, offset, &base, &start, &end, &ops, &len); - - if (offset == -1) - XBT_WARN("Error while loading location list: %s", dwarf_errmsg(-1)); - if (offset <= 0) - break; - - auto base_address = reinterpret_cast(info.base_address()); - - LocationListEntry::range_type range; - if (start == 0) - // If start == 0, this is not a location list: - range = {0, UINT64_MAX}; - else - range = {base_address + start, base_address + end}; - - locations.emplace_back(DwarfExpression(ops, ops + len), range); - } - - return locations; -} -} // namespace simgrid::dwarf diff --git a/src/mc/inspect/LocationList.hpp b/src/mc/inspect/LocationList.hpp deleted file mode 100644 index 9504a98f73..0000000000 --- a/src/mc/inspect/LocationList.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (c) 2004-2023. 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 SIMGRID_MC_OBJECT_LOCATION_H -#define SIMGRID_MC_OBJECT_LOCATION_H - -#include "xbt/base.h" -#include "xbt/range.hpp" - -#include "src/mc/inspect/DwarfExpression.hpp" -#include "src/mc/mc_base.hpp" -#include "src/mc/mc_forward.hpp" - -#include -#include - -namespace simgrid::dwarf { - -/** A DWARF expression with optional validity constraints */ -class LocationListEntry { -public: - using range_type = simgrid::xbt::Range; - -private: - DwarfExpression expression_; - // By default, the expression is always valid: - range_type range_ = {0, UINT64_MAX}; - -public: - LocationListEntry() = default; - LocationListEntry(DwarfExpression expression, range_type range) : expression_(std::move(expression)), range_(range) {} - explicit LocationListEntry(DwarfExpression expression) : expression_(std::move(expression)) {} - - DwarfExpression& expression() { return expression_; } - DwarfExpression const& expression() const { return expression_; } - bool valid_for_ip(unw_word_t ip) const { return range_.contain(ip); } -}; - -using LocationList = std::vector; - -/** Location of some variable in memory - * - * The variable is located either in memory of a register. - */ -class Location { -private: - void* memory_ = nullptr; - int register_id_ = 0; - -public: - explicit Location(void* x) : memory_(x) {} - explicit Location(int register_id) : register_id_(register_id) {} - // Type of location: - bool in_register() const { return memory_ == nullptr; } - bool in_memory() const { return memory_ != nullptr; } - - // Get the location: - void* address() const { return memory_; } - int register_id() const { return register_id_; } -}; - -XBT_PRIVATE -Location resolve(simgrid::dwarf::DwarfExpression const& expression, simgrid::mc::ObjectInformation* object_info, - unw_cursor_t* c, void* frame_pointer_address, const simgrid::mc::AddressSpace* address_space); - -Location resolve(simgrid::dwarf::LocationList const& locations, simgrid::mc::ObjectInformation* object_info, - unw_cursor_t* c, void* frame_pointer_address, const simgrid::mc::AddressSpace* address_space); - -XBT_PRIVATE -simgrid::dwarf::LocationList location_list(const simgrid::mc::ObjectInformation& info, Dwarf_Attribute& attr); - -} // namespace simgrid::dwarf - -#endif diff --git a/src/mc/inspect/ObjectInformation.cpp b/src/mc/inspect/ObjectInformation.cpp deleted file mode 100644 index 479dd7f6a5..0000000000 --- a/src/mc/inspect/ObjectInformation.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* Copyright (c) 2014-2023. 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 // PROT_READ and friends -#include - -#include "src/mc/inspect/Frame.hpp" -#include "src/mc/inspect/ObjectInformation.hpp" -#include "src/mc/inspect/Variable.hpp" -#include "src/mc/mc_private.hpp" -#include "xbt/file.hpp" - -namespace simgrid::mc { - -/* For an executable object, addresses are virtual address (there is no offset) i.e. - * \f$\text{virtual address} = \{dwarf address}\f$ - * - * For a shared object, the addresses are offset from the beginning of the shared object (the base address of the - * mapped shared object must be used as offset - * i.e. \f$\text{virtual address} = \text{shared object base address} - * + \text{dwarf address}\f$. - */ -void* ObjectInformation::base_address() const -{ - // For an executable (more precisely for an ET_EXEC) the base it 0: - if (this->executable()) - return nullptr; - - // For an a shared-object (ET_DYN, including position-independent executables) the base address is its lowest address: - void* result = this->start_exec; - if (this->start_rw != nullptr && result > (void*)this->start_rw) - result = this->start_rw; - if (this->start_ro != nullptr && result > (void*)this->start_ro) - result = this->start_ro; - return result; -} - -Frame* ObjectInformation::find_function(const void* ip) -{ - ensure_dwarf_loaded(); - - /* This is implemented by binary search on a sorted array. - * - * We do quite a lot of those so we want this to be cache efficient. - * We pack the only information we need in the index entries in order - * to successfully do the binary search. We do not need the high_pc - * during the binary search (only at the end) so it is not included - * in the index entry. We could use parallel arrays as well. - * - * Note the usage of reverse iterators to match the correct interval. - */ - auto pos = std::lower_bound(this->functions_index.rbegin(), this->functions_index.rend(), ip, - [](auto const& func, auto const* addr) { return func.low_pc > addr; }); - - /* At this point, the search is over. - * Either we have found the correct function or we do not know - * any function corresponding to this instruction address. - * Only at the point do we dereference the function pointer. */ - return (pos != this->functions_index.rend() && reinterpret_cast(ip) < pos->function->range.end()) - ? pos->function - : nullptr; -} - -const Variable* ObjectInformation::find_variable(const char* var_name) -{ - ensure_dwarf_loaded(); - - auto pos = std::lower_bound(this->global_variables.begin(), this->global_variables.end(), var_name, - [](auto const& var, const char* name) { return var.name < name; }); - return (pos != this->global_variables.end() && pos->name == var_name) ? &(*pos) : nullptr; -} - -void ObjectInformation::remove_global_variable(const char* var_name) -{ - // Binary search: - auto pos1 = std::lower_bound(this->global_variables.begin(), this->global_variables.end(), var_name, - [](auto const& var, const char* name) { return var.name < name; }); - // Find the whole range: - auto pos2 = std::upper_bound(pos1, this->global_variables.end(), var_name, - [](const char* name, auto const& var) { return name < var.name; }); - // Remove the whole range: - this->global_variables.erase(pos1, pos2); -} - -/** Ignore a local variable in a scope - * - * Ignore all instances of variables with a given name in any (possibly inlined) subprogram with a given namespaced - * name. - * - * @param var_name Name of the local variable to ignore - * @param subprogram_name Name of the subprogram to ignore (nullptr for any) - * @param subprogram (possibly inlined) Subprogram of the scope current scope - * @param scope Current scope - */ -static void remove_local_variable(Frame& scope, const char* var_name, const char* subprogram_name, - Frame const& subprogram) -{ - // If the current subprogram matches the given name: - if (subprogram_name == nullptr || (not subprogram.name.empty() && subprogram.name == subprogram_name)) { - // Try to find the variable and remove it: - - // Binary search: - auto pos = std::lower_bound(scope.variables.begin(), scope.variables.end(), var_name, - [](auto const& var, const char* name) { return var.name < name; }); - if (pos != scope.variables.end() && pos->name == var_name) { - // Variable found, remove it: - scope.variables.erase(pos); - } - } - - // And recursive processing in nested scopes: - for (Frame& nested_scope : scope.scopes) { - // The new scope may be an inlined subroutine, in this case we want to use its - // namespaced name in recursive calls: - Frame const& nested_subprogram = nested_scope.tag == DW_TAG_inlined_subroutine ? nested_scope : subprogram; - remove_local_variable(nested_scope, var_name, subprogram_name, nested_subprogram); - } -} - -void ObjectInformation::remove_local_variable(const char* var_name, const char* subprogram_name) -{ - for (auto& [_, entry] : this->subprograms) - mc::remove_local_variable(entry, var_name, subprogram_name, entry); -} - -/** @brief Fills the position of the segments (executable, read-only, read/write) */ -// TODO, use the ELF segment information for more robustness -void find_object_address(std::vector const& maps, ObjectInformation* result) -{ - const int PROT_RW = PROT_READ | PROT_WRITE; - const int PROT_RX = PROT_READ | PROT_EXEC; - - std::string name = xbt::Path(result->file_name).get_base_name(); - - for (size_t i = 0; i < maps.size(); ++i) { - simgrid::xbt::VmMap const& reg = maps[i]; - if (reg.pathname.empty() || name != simgrid::xbt::Path(reg.pathname).get_base_name()) - continue; - - // This is the non-GNU_RELRO-part of the data segment: - if (reg.prot == PROT_RW) { - xbt_assert(not result->start_rw, "Multiple read-write segments for %s, not supported", maps[i].pathname.c_str()); - result->start_rw = (char*)reg.start_addr; - result->end_rw = (char*)reg.end_addr; - - // The next VMA might be end of the data segment: - if (i + 1 < maps.size() && maps[i + 1].pathname.empty() && maps[i + 1].prot == PROT_RW && - maps[i + 1].start_addr == reg.end_addr) - result->end_rw = (char*)maps[i + 1].end_addr; - } - - // This is the text segment: - else if (reg.prot == PROT_RX) { - xbt_assert(not result->start_exec, "Multiple executable segments for %s, not supported", - maps[i].pathname.c_str()); - result->start_exec = (char*)reg.start_addr; - result->end_exec = (char*)reg.end_addr; - - // The next VMA might be end of the data segment: - if (i + 1 < maps.size() && maps[i + 1].pathname.empty() && maps[i + 1].prot == PROT_RW && - maps[i + 1].start_addr == reg.end_addr) { - result->start_rw = (char*)maps[i + 1].start_addr; - result->end_rw = (char*)maps[i + 1].end_addr; - } - } - - // This is the GNU_RELRO-part of the data segment: - else if (reg.prot == PROT_READ) { - xbt_assert(not result->start_ro, - "Multiple read-only segments for %s, not supported. Compiling with the following may help: " - "-g -Wl,-znorelro -Wl,-znoseparate-code", - maps[i].pathname.c_str()); - result->start_ro = (char*)reg.start_addr; - result->end_ro = (char*)reg.end_addr; - } - } - - result->start = result->start_rw; - if ((const void*)result->start_ro < result->start) - result->start = result->start_ro; - if ((const void*)result->start_exec < result->start) - result->start = result->start_exec; - - result->end = result->end_rw; - if (result->end_ro && (const void*)result->end_ro > result->end) - result->end = result->end_ro; - if (result->end_exec && (const void*)result->end_exec > result->end) - result->end = result->end_exec; - - xbt_assert(result->start_exec || result->start_rw || result->start_ro); -} - -} // namespace simgrid::mc diff --git a/src/mc/inspect/ObjectInformation.hpp b/src/mc/inspect/ObjectInformation.hpp deleted file mode 100644 index 7d1dfa11dc..0000000000 --- a/src/mc/inspect/ObjectInformation.hpp +++ /dev/null @@ -1,170 +0,0 @@ -/* Copyright (c) 2007-2023. 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 SIMGRID_MC_OBJECT_INFORMATION_HPP -#define SIMGRID_MC_OBJECT_INFORMATION_HPP - -#include -#include -#include -#include - -#include "src/mc/inspect/Frame.hpp" -#include "src/mc/inspect/Type.hpp" -#include "src/mc/mc_forward.hpp" -#include "src/xbt/memory_map.hpp" - -#include "src/smpi/include/private.hpp" - -namespace simgrid::mc { - -/** An entry in the functions index - * - * See the code of ObjectInformation::find_function. - */ -struct FunctionIndexEntry { - void* low_pc; - simgrid::mc::Frame* function; -}; - -/** Information about an ELF module (executable or shared object) - * - * This contains all the information we need about an executable or - * shared-object in the model-checked process: - * - * - where it is located in the virtual address space; - * - * - where are located its different memory mappings in the the - * virtual address space; - * - * - all the debugging (DWARF) information - * - types, - * - location of the functions and their local variables, - * - global variables, - * - * - etc. - */ -class ObjectInformation { - bool dwarf_loaded = false; // Lazily loads the dwarf info - -public: - void ensure_dwarf_loaded(); // Used by functions that need the dwarf - ObjectInformation() = default; - - // Not copiable: - ObjectInformation(ObjectInformation const&) = delete; - ObjectInformation& operator=(ObjectInformation const&) = delete; - - // Flag: - static const int Executable = 1; - - /** Bitfield of flags */ - int flags = 0; - std::string file_name; - const void* start = nullptr; - const void* end = nullptr; - // Location of its text segment: - char* start_exec = nullptr; - char* end_exec = nullptr; - // Location of the read-only part of its data segment: - char* start_rw = nullptr; - char* end_rw = nullptr; - // Location of the read/write part of its data segment: - char* start_ro = nullptr; - char* end_ro = nullptr; - - /** All of its subprograms indexed by their address */ - std::unordered_map subprograms; - - /** Index of functions by instruction address - * - * We need to efficiently find the function from any given instruction - * address inside its range. This index is sorted by low_pc - * - * The entries are sorted by low_pc and a binary search can be used to look - * them up. In order to have a better cache locality, we only keep the - * information we need for the lookup in this vector. We could probably - * replace subprograms by an ordered vector of Frame and replace this one b - * a parallel `std::vector`. - */ - std::vector functions_index; - - std::vector global_variables; - - /** Types indexed by DWARF ID */ - std::unordered_map types; - - /** Types indexed by name - * - * Different compilation units have their separate type definitions - * (for the same type). When we find an opaque type in one compilation unit, - * we use this in order to try to find its definition in another compilation - * unit. - */ - std::unordered_map full_types_by_name; - - /** Whether this module is an executable - * - * More precisely we check if this is an ET_EXE ELF. These ELF files - * use fixed addresses instead of base-address relative addresses. - * Position independent executables are in fact ET_DYN. - */ - bool executable() const { return this->flags & simgrid::mc::ObjectInformation::Executable; } - - /** Base address of the module - * - * All the location information in ELF and DWARF are expressed as an offsets - * from this base address: - * - * - location of the functions and global variables - * - * - the DWARF instruction `OP_addr` pushes this on the DWARF stack. - **/ - void* base_address() const; - - /** Find a function by instruction address - * - * Loads the dwarf information on need. - * - * @param ip instruction address - * @return corresponding function (if any) or nullptr - */ - simgrid::mc::Frame* find_function(const void* ip); - - /** Find a global variable by name - * - * Loads the dwarf information on need. - * - * This is used to ignore global variables and to find well-known variables - * (`__mmalloc_default_mdp`). - * - * @param name scopes name of the global variable (`myproject::Foo::count`) - * @return corresponding variable (if any) or nullptr - */ - const simgrid::mc::Variable* find_variable(const char* name); - - /** Remove a global variable (in order to ignore it) - * - * This is used to ignore a global variable for the snapshot comparison. - */ - void remove_global_variable(const char* name); - - /** Remove a local variables (in order to ignore it) - * - * @param name Name of the local variable - * @param scope scopes name name of the function (myproject::Foo::count) or null for all functions - */ - void remove_local_variable(const char* name, const char* scope); -}; - -XBT_PRIVATE std::shared_ptr createObjectInformation(std::vector const& maps, - const char* name); - -/** Augment the current module with information about the other ones */ -XBT_PRIVATE void postProcessObjectInformation(const simgrid::mc::RemoteProcessMemory* process, - simgrid::mc::ObjectInformation* info); -} // namespace simgrid::mc - -#endif diff --git a/src/mc/inspect/Type.hpp b/src/mc/inspect/Type.hpp deleted file mode 100644 index 3c225a1be9..0000000000 --- a/src/mc/inspect/Type.hpp +++ /dev/null @@ -1,106 +0,0 @@ -/* Copyright (c) 2007-2023. 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 SIMGRID_MC_TYPE_HPP -#define SIMGRID_MC_TYPE_HPP - -#include - -#include -#include - -#include - -#include "xbt/asserts.h" -#include "xbt/base.h" - -#include "src/mc/inspect/LocationList.hpp" -#include "src/mc/mc_forward.hpp" - -namespace simgrid::mc { - -/** A member of a structure, union - * - * Inheritance is seen as a special member as well. - */ -class Member { -public: - using flags_type = int; - static constexpr flags_type INHERITANCE_FLAG = 1; - static constexpr flags_type VIRTUAL_POINTER_FLAG = 2; - - Member() = default; - - /** Whether this member represent some inherited part of the object */ - flags_type flags = 0; - - /** Name of the member (if any) */ - std::string name; - - /** DWARF location expression for locating the location of the member */ - simgrid::dwarf::DwarfExpression location_expression; - - std::size_t byte_size = 0; // Do we really need this? - - unsigned type_id = 0; - simgrid::mc::Type* type = nullptr; - - bool isInheritance() const { return this->flags & INHERITANCE_FLAG; } - bool isVirtualPointer() const { return this->flags & VIRTUAL_POINTER_FLAG; } - - /** Whether the member is at a fixed offset from the base address */ - bool has_offset_location() const - { - // Recognize the expression `DW_OP_plus_uconst(offset)`: - return location_expression.size() == 1 && location_expression[0].atom == DW_OP_plus_uconst; - } - - /** Get the offset of the member - * - * This is only valid is the member is at a fixed offset from the base. - * This is often the case (for C types, C++ type without virtual - * inheritance). - * - * If the location is more complex, the location expression has - * to be evaluated (which might need accessing the memory). - */ - int offset() const - { - xbt_assert(this->has_offset_location()); - return this->location_expression[0].number; - } - - /** Set the location of the member as a fixed offset */ - void offset(int new_offset) - { - // Set the expression to be `DW_OP_plus_uconst(offset)`: - Dwarf_Op op; - op.atom = DW_OP_plus_uconst; - op.number = new_offset; - this->location_expression = {op}; - } -}; - -/** A type in the model-checked program */ -class Type { -public: - Type() = default; - - /** The DWARF TAG of the type (e.g. DW_TAG_array_type) */ - int type = 0; - unsigned id = 0; /* Offset in the section (in hexadecimal form) */ - std::string name; /* Name of the type */ - int byte_size = 0; /* Size in bytes */ - int element_count = 0; /* Number of elements for array type */ - unsigned type_id = 0; /* DW_AT_type id */ - std::vector members; /* if DW_TAG_structure_type, DW_TAG_class_type, DW_TAG_union_type*/ - - simgrid::mc::Type* subtype = nullptr; // DW_AT_type - simgrid::mc::Type* full_type = nullptr; // The same (but more complete) type -}; - -} // namespace simgrid::mc - -#endif diff --git a/src/mc/inspect/Variable.hpp b/src/mc/inspect/Variable.hpp deleted file mode 100644 index f2cae32cae..0000000000 --- a/src/mc/inspect/Variable.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (c) 2007-2023. 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 SIMGRID_MC_VARIABLE_HPP -#define SIMGRID_MC_VARIABLE_HPP - -#include - -#include - -#include "src/mc/inspect/LocationList.hpp" -#include "src/mc/mc_forward.hpp" - -namespace simgrid::mc { - -/** A variable (global or local) in the model-checked program */ -class Variable { -public: - Variable() = default; - std::uint32_t id = 0; - bool global = false; - std::string name; - unsigned type_id = 0; - simgrid::mc::Type* type = nullptr; - - /** Address of the variable (if it is fixed) */ - void* address = nullptr; - - /** Description of the location of the variable (if it's not fixed) */ - simgrid::dwarf::LocationList location_list; - - /** Offset of validity of the variable (DW_AT_start_scope) - * - * This is an offset from the variable scope beginning. This variable - * is only valid starting from this offset. - */ - std::size_t start_scope = 0; - - simgrid::mc::ObjectInformation* object_info = nullptr; -}; - -} // namespace simgrid::mc - -#endif diff --git a/src/mc/inspect/mc_dwarf.cpp b/src/mc/inspect/mc_dwarf.cpp deleted file mode 100644 index 094635da76..0000000000 --- a/src/mc/inspect/mc_dwarf.cpp +++ /dev/null @@ -1,1207 +0,0 @@ -/* Copyright (c) 2008-2023. 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 "src/simgrid/util.hpp" -#include "xbt/log.h" -#include "xbt/string.hpp" -#include "xbt/sysdep.h" -#include - -#include "src/mc/inspect/ObjectInformation.hpp" -#include "src/mc/inspect/Variable.hpp" -#include "src/mc/inspect/mc_dwarf.hpp" -#include "src/mc/mc_private.hpp" -#include "src/mc/sosp/RemoteProcessMemory.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dwarf, mc, "DWARF processing"); - -/** @brief The default DW_TAG_lower_bound for a given DW_AT_language. - * - * The default for a given language is defined in the DWARF spec. - * - * @param language constant as defined by the DWARf spec - */ -static uint64_t MC_dwarf_default_lower_bound(int lang); - -/** @brief Computes the the element_count of a DW_TAG_enumeration_type DIE - * - * This is the number of elements in a given array dimension. - * - * A reference of the compilation unit (DW_TAG_compile_unit) is - * needed because the default lower bound (when there is no DW_AT_lower_bound) - * depends of the language of the compilation unit (DW_AT_language). - * - * @param die DIE for the DW_TAG_enumeration_type or DW_TAG_subrange_type - * @param unit DIE of the DW_TAG_compile_unit - */ -static uint64_t MC_dwarf_subrange_element_count(Dwarf_Die* die, Dwarf_Die* unit); - -/** @brief Computes the number of elements of a given DW_TAG_array_type. - * - * @param die DIE for the DW_TAG_array_type - */ -static uint64_t MC_dwarf_array_element_count(Dwarf_Die* die, Dwarf_Die* unit); - -/** @brief Process a DIE - * - * @param info the resulting object for the library/binary file (output) - * @param die the current DIE - * @param unit the DIE of the compile unit of the current DIE - * @param frame containing frame if any - */ -static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit, - simgrid::mc::Frame* frame, const char* ns); - -/** @brief Process a type DIE - */ -static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit, - simgrid::mc::Frame* frame, const char* ns); - -/** @brief Calls MC_dwarf_handle_die on all children of the given die - * - * @param info the resulting object for the library/binary file (output) - * @param die the current DIE - * @param unit the DIE of the compile unit of the current DIE - * @param frame containing frame if any - */ -static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit, - simgrid::mc::Frame* frame, const char* ns); - -/** @brief Handle a variable (DW_TAG_variable or other) - * - * @param info the resulting object for the library/binary file (output) - * @param die the current DIE - * @param unit the DIE of the compile unit of the current DIE - * @param frame containing frame if any - */ -static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, const Dwarf_Die* unit, - simgrid::mc::Frame* frame, const char* ns); - -/** @brief Get the DW_TAG_type of the DIE - * - * @param die DIE - * @return DW_TAG_type attribute as a new string (nullptr if none) - */ -static std::uint64_t MC_dwarf_at_type(Dwarf_Die* die); - -namespace simgrid::dwarf { - -enum class TagClass { Unknown, Type, Subprogram, Variable, Scope, Namespace }; - -/*** Class of forms defined in the DWARF standard */ -enum class FormClass { - Unknown, - Address, // Location in the program's address space - Block, // Arbitrary block of bytes - Constant, - String, - Flag, // Boolean value - Reference, // Reference to another DIE - ExprLoc, // DWARF expression/location description - LinePtr, - LocListPtr, - MacPtr, - RangeListPtr -}; - -static TagClass classify_tag(int tag) -{ - static const std::unordered_map map = { - {DW_TAG_array_type, TagClass::Type}, {DW_TAG_class_type, TagClass::Type}, - {DW_TAG_enumeration_type, TagClass::Type}, {DW_TAG_typedef, TagClass::Type}, - {DW_TAG_pointer_type, TagClass::Type}, {DW_TAG_reference_type, TagClass::Type}, - {DW_TAG_rvalue_reference_type, TagClass::Type}, {DW_TAG_string_type, TagClass::Type}, - {DW_TAG_structure_type, TagClass::Type}, {DW_TAG_subroutine_type, TagClass::Type}, - {DW_TAG_union_type, TagClass::Type}, {DW_TAG_ptr_to_member_type, TagClass::Type}, - {DW_TAG_set_type, TagClass::Type}, {DW_TAG_subrange_type, TagClass::Type}, - {DW_TAG_base_type, TagClass::Type}, {DW_TAG_const_type, TagClass::Type}, - {DW_TAG_file_type, TagClass::Type}, {DW_TAG_packed_type, TagClass::Type}, - {DW_TAG_volatile_type, TagClass::Type}, {DW_TAG_restrict_type, TagClass::Type}, - {DW_TAG_interface_type, TagClass::Type}, {DW_TAG_unspecified_type, TagClass::Type}, - {DW_TAG_shared_type, TagClass::Type}, - - {DW_TAG_subprogram, TagClass::Subprogram}, - - {DW_TAG_variable, TagClass::Variable}, {DW_TAG_formal_parameter, TagClass::Variable}, - - {DW_TAG_lexical_block, TagClass::Scope}, {DW_TAG_try_block, TagClass::Scope}, - {DW_TAG_catch_block, TagClass::Scope}, {DW_TAG_inlined_subroutine, TagClass::Scope}, - {DW_TAG_with_stmt, TagClass::Scope}, - - {DW_TAG_namespace, TagClass::Namespace}}; - - auto res = map.find(tag); - return res != map.end() ? res->second : TagClass::Unknown; -} - -/** @brief Find the DWARF data class for a given DWARF data form - * - * This mapping is defined in the DWARF spec. - * - * @param form The form (values taken from the DWARF spec) - * @return An internal representation for the corresponding class - * */ -static FormClass classify_form(int form) -{ - static const std::unordered_map map = { - {DW_FORM_addr, FormClass::Address}, - - {DW_FORM_block2, FormClass::Block}, {DW_FORM_block4, FormClass::Block}, - {DW_FORM_block, FormClass::Block}, {DW_FORM_block1, FormClass::Block}, - - {DW_FORM_data1, FormClass::Constant}, {DW_FORM_data2, FormClass::Constant}, - {DW_FORM_data4, FormClass::Constant}, {DW_FORM_data8, FormClass::Constant}, - {DW_FORM_udata, FormClass::Constant}, {DW_FORM_sdata, FormClass::Constant}, -#if _ELFUTILS_PREREQ(0, 171) - {DW_FORM_implicit_const, FormClass::Constant}, -#endif - - {DW_FORM_string, FormClass::String}, {DW_FORM_strp, FormClass::String}, - - {DW_FORM_ref_addr, FormClass::Reference}, {DW_FORM_ref1, FormClass::Reference}, - {DW_FORM_ref2, FormClass::Reference}, {DW_FORM_ref4, FormClass::Reference}, - {DW_FORM_ref8, FormClass::Reference}, {DW_FORM_ref_udata, FormClass::Reference}, - - {DW_FORM_flag, FormClass::Flag}, {DW_FORM_flag_present, FormClass::Flag}, - - {DW_FORM_exprloc, FormClass::ExprLoc} - - // TODO sec offset - // TODO indirect - }; - - auto res = map.find(form); - return res != map.end() ? res->second : FormClass::Unknown; -} - -/** @brief Get the name of the tag of a given DIE - * - * @param die DIE - * @return name of the tag of this DIE - */ -inline XBT_PRIVATE const char* tagname(Dwarf_Die* die) -{ - return tagname(dwarf_tag(die)); -} - -} // namespace simgrid::dwarf - -// ***** Attributes - -/** @brief Get an attribute of a given DIE as a string - * - * @param die the DIE - * @param attribute attribute - * @return value of the given attribute of the given DIE - */ -static const char* MC_dwarf_attr_integrate_string(Dwarf_Die* die, int attribute) -{ - Dwarf_Attribute attr; - if (not dwarf_attr_integrate(die, attribute, &attr)) - return nullptr; - else - return dwarf_formstring(&attr); -} - -static Dwarf_Off MC_dwarf_attr_integrate_dieoffset(Dwarf_Die* die, int attribute) -{ - Dwarf_Attribute attr; - if (dwarf_hasattr_integrate(die, attribute) == 0) - return 0; - dwarf_attr_integrate(die, attribute, &attr); - Dwarf_Die subtype_die; - xbt_assert(dwarf_formref_die(&attr, &subtype_die) != nullptr, "Could not find DIE"); - return dwarf_dieoffset(&subtype_die); -} - -/** @brief Find the type/subtype (DW_AT_type) for a DIE - * - * @param die the DIE - * @return DW_AT_type reference as a global offset in hexadecimal (or nullptr) - */ -static std::uint64_t MC_dwarf_at_type(Dwarf_Die* die) -{ - return MC_dwarf_attr_integrate_dieoffset(die, DW_AT_type); -} - -static uint64_t MC_dwarf_attr_integrate_addr(Dwarf_Die* die, int attribute) -{ - Dwarf_Attribute attr; - if (dwarf_attr_integrate(die, attribute, &attr) == nullptr) - return 0; - Dwarf_Addr value; - if (dwarf_formaddr(&attr, &value) == 0) - return (uint64_t)value; - else - return 0; -} - -static uint64_t MC_dwarf_attr_integrate_uint(Dwarf_Die* die, int attribute, uint64_t default_value) -{ - Dwarf_Attribute attr; - if (dwarf_attr_integrate(die, attribute, &attr) == nullptr) - return default_value; - Dwarf_Word value; - return dwarf_formudata(dwarf_attr_integrate(die, attribute, &attr), &value) == 0 ? (uint64_t)value : default_value; -} - -static bool MC_dwarf_attr_flag(Dwarf_Die* die, int attribute, bool integrate) -{ - Dwarf_Attribute attr; - if ((integrate ? dwarf_attr_integrate(die, attribute, &attr) : dwarf_attr(die, attribute, &attr)) == nullptr) - return false; - - bool result; - xbt_assert(not dwarf_formflag(&attr, &result), "Unexpected form for attribute %s", - simgrid::dwarf::attrname(attribute)); - return result; -} - -/** @brief Find the default lower bound for a given language - * - * The default lower bound of an array (when DW_TAG_lower_bound - * is missing) depends on the language of the compilation unit. - * - * @param lang Language of the compilation unit (values defined in the DWARF spec) - * @return Default lower bound of an array in this compilation unit - * */ -static uint64_t MC_dwarf_default_lower_bound(int lang) -{ - const std::unordered_map map = { - {DW_LANG_C, 0}, {DW_LANG_C89, 0}, {DW_LANG_C99, 0}, {DW_LANG_C11, 0}, - {DW_LANG_C_plus_plus, 0}, {DW_LANG_C_plus_plus_11, 0}, {DW_LANG_C_plus_plus_14, 0}, {DW_LANG_D, 0}, - {DW_LANG_Java, 0}, {DW_LANG_ObjC, 0}, {DW_LANG_ObjC_plus_plus, 0}, {DW_LANG_Python, 0}, - {DW_LANG_UPC, 0}, - - {DW_LANG_Ada83, 1}, {DW_LANG_Ada95, 1}, {DW_LANG_Fortran77, 1}, {DW_LANG_Fortran90, 1}, - {DW_LANG_Fortran95, 1}, {DW_LANG_Fortran03, 1}, {DW_LANG_Fortran08, 1}, {DW_LANG_Modula2, 1}, - {DW_LANG_Pascal83, 1}, {DW_LANG_PL1, 1}, {DW_LANG_Cobol74, 1}, {DW_LANG_Cobol85, 1}}; - - auto res = map.find(lang); - xbt_assert(res != map.end(), "No default DW_TAG_lower_bound for language %i and none given", lang); - return res->second; -} - -/** @brief Finds the number of elements in a DW_TAG_subrange_type or DW_TAG_enumeration_type DIE - * - * @param die the DIE - * @param unit DIE of the compilation unit - * @return number of elements in the range - * */ -static uint64_t MC_dwarf_subrange_element_count(Dwarf_Die* die, Dwarf_Die* unit) -{ - xbt_assert(dwarf_tag(die) == DW_TAG_enumeration_type || dwarf_tag(die) == DW_TAG_subrange_type, - "MC_dwarf_subrange_element_count called with DIE of type %s", simgrid::dwarf::tagname(die)); - - // Use DW_TAG_count if present: - if (dwarf_hasattr_integrate(die, DW_AT_count)) - return MC_dwarf_attr_integrate_uint(die, DW_AT_count, 0); - // Otherwise compute DW_TAG_upper_bound-DW_TAG_lower_bound + 1: - - if (not dwarf_hasattr_integrate(die, DW_AT_upper_bound)) - // This is not really 0, but the code expects this (we do not know): - return 0; - - uint64_t upper_bound = MC_dwarf_attr_integrate_uint(die, DW_AT_upper_bound, static_cast(-1)); - - uint64_t lower_bound = 0; - if (dwarf_hasattr_integrate(die, DW_AT_lower_bound)) - lower_bound = MC_dwarf_attr_integrate_uint(die, DW_AT_lower_bound, static_cast(-1)); - else - lower_bound = MC_dwarf_default_lower_bound(dwarf_srclang(unit)); - return upper_bound - lower_bound + 1; -} - -/** @brief Finds the number of elements in an array type (DW_TAG_array_type) - * - * The compilation unit might be needed because the default lower - * bound depends on the language of the compilation unit. - * - * @param die the DIE of the DW_TAG_array_type - * @param unit the DIE of the compilation unit - * @return number of elements in this array type - * */ -static uint64_t MC_dwarf_array_element_count(Dwarf_Die* die, Dwarf_Die* unit) -{ - xbt_assert(dwarf_tag(die) == DW_TAG_array_type, "MC_dwarf_array_element_count called with DIE of type %s", - simgrid::dwarf::tagname(die)); - - int result = 1; - Dwarf_Die child; - for (int res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child)) { - int child_tag = dwarf_tag(&child); - if (child_tag == DW_TAG_subrange_type || child_tag == DW_TAG_enumeration_type) - result *= MC_dwarf_subrange_element_count(&child, unit); - } - return result; -} - -// ***** Variable - -/** Sort the variable by name and address. - * - * We could use boost::container::flat_set instead. - */ -static bool MC_compare_variable(simgrid::mc::Variable const& a, simgrid::mc::Variable const& b) -{ - int cmp = a.name.compare(b.name); - if (cmp < 0) - return true; - else if (cmp > 0) - return false; - else - return a.address < b.address; -} - -// ***** simgrid::mc::Type* - -/** @brief Initialize the location of a member of a type - * (DW_AT_data_member_location of a DW_TAG_member). - * - * @param type a type (struct, class) - * @param member the member of the type - * @param child DIE of the member (DW_TAG_member) - */ -static void MC_dwarf_fill_member_location(const simgrid::mc::Type* type, simgrid::mc::Member* member, Dwarf_Die* child) -{ - xbt_assert(not dwarf_hasattr(child, DW_AT_data_bit_offset), "Can't groke DW_AT_data_bit_offset."); - - if (not dwarf_hasattr_integrate(child, DW_AT_data_member_location)) { - xbt_assert(type->type == DW_TAG_union_type, - "Missing DW_AT_data_member_location field in DW_TAG_member %s of type <%" PRIx64 ">%s", - member->name.c_str(), (uint64_t)type->id, type->name.c_str()); - return; - } - - Dwarf_Attribute attr; - dwarf_attr_integrate(child, DW_AT_data_member_location, &attr); - int form = dwarf_whatform(&attr); - simgrid::dwarf::FormClass form_class = simgrid::dwarf::classify_form(form); - switch (form_class) { - case simgrid::dwarf::FormClass::ExprLoc: - case simgrid::dwarf::FormClass::Block: - // Location expression: - { - Dwarf_Op* expr; - size_t len; - xbt_assert(not dwarf_getlocation(&attr, &expr, &len), - "Could not read location expression DW_AT_data_member_location in DW_TAG_member %s of type <%" PRIx64 - ">%s", - MC_dwarf_attr_integrate_string(child, DW_AT_name), (uint64_t)type->id, type->name.c_str()); - member->location_expression = simgrid::dwarf::DwarfExpression(expr, expr + len); - break; - } - case simgrid::dwarf::FormClass::Constant: - // Offset from the base address of the object: - { - Dwarf_Word offset; - xbt_assert(not dwarf_formudata(&attr, &offset), "Cannot get %s location <%" PRIx64 ">%s", - MC_dwarf_attr_integrate_string(child, DW_AT_name), (uint64_t)type->id, type->name.c_str()); - member->offset(offset); - break; - } - - default: - // includes FormClass::LocListPtr (reference to a location list: TODO) and FormClass::Reference (it's supposed to - // be possible in DWARF2 but I couldn't find its semantic in the spec) - xbt_die("Can't handle form class (%d) / form 0x%x as DW_AT_member_location", (int)form_class, (unsigned)form); - } -} - -/** @brief Populate the list of members of a type - * - * @param info ELF object containing the type DIE - * @param die DIE of the type - * @param unit DIE of the compilation unit containing the type DIE - * @param type the type - */ -static void MC_dwarf_add_members(const simgrid::mc::ObjectInformation* /*info*/, Dwarf_Die* die, - const Dwarf_Die* /*unit*/, simgrid::mc::Type* type) -{ - Dwarf_Die child; - xbt_assert(type->members.empty()); - for (int res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child)) { - int tag = dwarf_tag(&child); - if (tag == DW_TAG_member || tag == DW_TAG_inheritance) { - // Skip declarations: - if (MC_dwarf_attr_flag(&child, DW_AT_declaration, false)) - continue; - - // Skip compile time constants: - if (dwarf_hasattr(&child, DW_AT_const_value)) - continue; - - // TODO, we should use another type (because is is not a type but a member) - simgrid::mc::Member member; - if (tag == DW_TAG_inheritance) - member.flags |= simgrid::mc::Member::INHERITANCE_FLAG; - - const char* name = MC_dwarf_attr_integrate_string(&child, DW_AT_name); - if (name) - member.name = name; - // Those base names are used by GCC and clang for virtual table pointers - // respectively ("__vptr$ClassName", "__vptr.ClassName"): - if (member.name.rfind("__vptr$", 0) == 0 || member.name.rfind("__vptr.", 0) == 0) - member.flags |= simgrid::mc::Member::VIRTUAL_POINTER_FLAG; - // A cleaner solution would be to check against the type: - // --- - // tag: DW_TAG_member - // name: "_vptr$Foo" - // type: - // # Type for a pointer to a vtable - // tag: DW_TAG_pointer_type - // type: - // # Type for a vtable: - // tag: DW_TAG_pointer_type - // name: "__vtbl_ptr_type" - // type: - // tag: DW_TAG_subroutine_type - // type: - // tag: DW_TAG_base_type - // name: "int" - // --- - - member.byte_size = MC_dwarf_attr_integrate_uint(&child, DW_AT_byte_size, 0); - member.type_id = MC_dwarf_at_type(&child); - - if (dwarf_hasattr(&child, DW_AT_data_bit_offset)) { - XBT_WARN("Can't groke DW_AT_data_bit_offset for %s", name); - continue; - } - - MC_dwarf_fill_member_location(type, &member, &child); - - xbt_assert(member.type_id, "Missing type for member %s of <%" PRIx64 ">%s", member.name.c_str(), - (uint64_t)type->id, type->name.c_str()); - - type->members.push_back(std::move(member)); - } - } -} - -/** @brief Create a MC type object from a DIE - * - * @param info current object info object - * @param die DIE (for a given type) - * @param unit compilation unit of the current DIE - * @return MC representation of the type - */ -static simgrid::mc::Type MC_dwarf_die_to_type(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit, - simgrid::mc::Frame* frame, const char* ns) -{ - simgrid::mc::Type type; - type.type = dwarf_tag(die); - type.name = ""; - type.element_count = -1; - - // Global Offset - type.id = dwarf_dieoffset(die); - - const char* prefix; - switch (type.type) { - case DW_TAG_structure_type: - prefix = "struct "; - break; - case DW_TAG_union_type: - prefix = "union "; - break; - case DW_TAG_class_type: - prefix = "class "; - break; - default: - prefix = ""; - } - - const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name); - if (name != nullptr) { - if (ns) - type.name = simgrid::xbt::string_printf("%s%s::%s", prefix, ns, name); - else - type.name = simgrid::xbt::string_printf("%s%s", prefix, name); - } - - type.type_id = MC_dwarf_at_type(die); - - // Some compilers do not emit DW_AT_byte_size for pointer_type, - // so we fill this. We currently assume that the model-checked process is in - // the same architecture.. - if (type.type == DW_TAG_pointer_type) - type.byte_size = sizeof(void*); - - // Computation of the byte_size - if (dwarf_hasattr_integrate(die, DW_AT_byte_size)) - type.byte_size = MC_dwarf_attr_integrate_uint(die, DW_AT_byte_size, 0); - else if (type.type == DW_TAG_array_type || type.type == DW_TAG_structure_type || type.type == DW_TAG_class_type) { - Dwarf_Word size; - if (dwarf_aggregate_size(die, &size) == 0) - type.byte_size = size; - } - - switch (type.type) { - case DW_TAG_array_type: - type.element_count = MC_dwarf_array_element_count(die, unit); - // TODO, handle DW_byte_stride and (not) DW_bit_stride - break; - - case DW_TAG_pointer_type: - case DW_TAG_reference_type: - case DW_TAG_rvalue_reference_type: - break; - - case DW_TAG_structure_type: - case DW_TAG_union_type: - case DW_TAG_class_type: - MC_dwarf_add_members(info, die, unit, &type); - MC_dwarf_handle_children(info, die, unit, frame, - ns ? simgrid::xbt::string_printf("%s::%s", ns, name).c_str() : type.name.c_str()); - break; - - default: - XBT_DEBUG("Unhandled type: %d (%s)", type.type, simgrid::dwarf::tagname(type.type)); - break; - } - - return type; -} - -static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit, - simgrid::mc::Frame* frame, const char* ns) -{ - simgrid::mc::Type type = MC_dwarf_die_to_type(info, die, unit, frame, ns); - auto& t = (info->types[type.id] = std::move(type)); - if (not t.name.empty() && type.byte_size != 0) - info->full_types_by_name[t.name] = &t; -} - -static std::unique_ptr MC_die_to_variable(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, - const Dwarf_Die* /*unit*/, - const simgrid::mc::Frame* frame, const char* ns) -{ - // Skip declarations: - if (MC_dwarf_attr_flag(die, DW_AT_declaration, false)) - return nullptr; - - // Skip compile time constants: - if (dwarf_hasattr(die, DW_AT_const_value)) - return nullptr; - - Dwarf_Attribute attr_location; - if (dwarf_attr(die, DW_AT_location, &attr_location) == nullptr) - // No location: do not add it ? - return nullptr; - - auto variable = std::make_unique(); - variable->id = dwarf_dieoffset(die); - variable->global = frame == nullptr; // Can be override base on DW_AT_location - variable->object_info = info; - - const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name); - if (name) - variable->name = name; - variable->type_id = MC_dwarf_at_type(die); - - int form = dwarf_whatform(&attr_location); - simgrid::dwarf::FormClass form_class; - if (form == DW_FORM_sec_offset) - form_class = simgrid::dwarf::FormClass::Constant; - else - form_class = simgrid::dwarf::classify_form(form); - switch (form_class) { - case simgrid::dwarf::FormClass::ExprLoc: - case simgrid::dwarf::FormClass::Block: - // Location expression: - { - Dwarf_Op* expr; - size_t len; - xbt_assert(not dwarf_getlocation(&attr_location, &expr, &len), - "Could not read location expression in DW_AT_location " - "of variable <%" PRIx64 ">%s", - (uint64_t)variable->id, variable->name.c_str()); - - if (len == 1 && expr[0].atom == DW_OP_addr) { - variable->global = true; - auto offset = static_cast(expr[0].number); - auto base = reinterpret_cast(info->base_address()); - variable->address = reinterpret_cast(base + offset); - } else - variable->location_list = { - simgrid::dwarf::LocationListEntry(simgrid::dwarf::DwarfExpression(expr, expr + len))}; - - break; - } - - case simgrid::dwarf::FormClass::LocListPtr: - case simgrid::dwarf::FormClass::Constant: - // Reference to location list: - variable->location_list = simgrid::dwarf::location_list(*info, attr_location); - break; - - default: - xbt_die("Unexpected form 0x%x (%i), class 0x%x (%i) list for location in <%" PRIx64 ">%s", (unsigned)form, form, - (unsigned)form_class, (int)form_class, (uint64_t)variable->id, variable->name.c_str()); - } - - // Handle start_scope: - if (dwarf_hasattr(die, DW_AT_start_scope)) { - Dwarf_Attribute attr; - dwarf_attr(die, DW_AT_start_scope, &attr); - form = dwarf_whatform(&attr); - form_class = simgrid::dwarf::classify_form(form); - if (form_class == simgrid::dwarf::FormClass::Constant) { - Dwarf_Word value; - variable->start_scope = dwarf_formudata(&attr, &value) == 0 ? (size_t)value : 0; - } else { - // TODO: FormClass::RangeListPtr - xbt_die("Unhandled form 0x%x, class 0x%X for DW_AT_start_scope of variable %s", (unsigned)form, - (unsigned)form_class, name == nullptr ? "?" : name); - } - } - - if (ns && variable->global) - variable->name.insert(0, std::string(ns) + "::"); - - // The current code needs a variable name, - // generate a fake one: - static int mc_anonymous_variable_index = 0; - if (variable->name.empty()) { - variable->name = "@anonymous#" + std::to_string(mc_anonymous_variable_index); - mc_anonymous_variable_index++; - } - return variable; -} - -static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, const Dwarf_Die* unit, - simgrid::mc::Frame* frame, const char* ns) -{ - std::unique_ptr variable = MC_die_to_variable(info, die, unit, frame, ns); - if (not variable) - return; - // Those arrays are sorted later: - if (variable->global) - info->global_variables.push_back(std::move(*variable)); - else if (frame != nullptr) - frame->variables.push_back(std::move(*variable)); - else - xbt_die("No frame for this local variable"); -} - -static void MC_dwarf_handle_scope_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit, - simgrid::mc::Frame* parent_frame, const char* ns) -{ - // TODO, handle DW_TAG_type/DW_TAG_location for DW_TAG_with_stmt - int tag = dwarf_tag(die); - simgrid::dwarf::TagClass klass = simgrid::dwarf::classify_tag(tag); - - // (Template) Subprogram declaration: - if (klass == simgrid::dwarf::TagClass::Subprogram && MC_dwarf_attr_flag(die, DW_AT_declaration, false)) - return; - - if (klass == simgrid::dwarf::TagClass::Scope) - xbt_assert(parent_frame, "No parent scope for this scope"); - - simgrid::mc::Frame frame; - frame.tag = tag; - frame.id = dwarf_dieoffset(die); - frame.object_info = info; - - if (klass == simgrid::dwarf::TagClass::Subprogram) { - const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name); - if (name && ns) - frame.name = std::string(ns) + "::" + name; - else if (name) - frame.name = name; - } - - frame.abstract_origin_id = MC_dwarf_attr_integrate_dieoffset(die, DW_AT_abstract_origin); - - // This is the base address for DWARF addresses. - // Relocated addresses are offset from this base address. - // See DWARF4 spec 7.5 - auto base = reinterpret_cast(info->base_address()); - - // TODO, support DW_AT_ranges - uint64_t low_pc = MC_dwarf_attr_integrate_addr(die, DW_AT_low_pc); - frame.range.begin() = low_pc ? base + low_pc : 0; - if (low_pc) { - // DW_AT_high_pc: - Dwarf_Attribute attr; - xbt_assert(dwarf_attr_integrate(die, DW_AT_high_pc, &attr), "Missing DW_AT_high_pc matching with DW_AT_low_pc"); - - Dwarf_Sword offset; - Dwarf_Addr high_pc; - - switch (simgrid::dwarf::classify_form(dwarf_whatform(&attr))) { - // DW_AT_high_pc if an offset from the low_pc: - case simgrid::dwarf::FormClass::Constant: - - xbt_assert(dwarf_formsdata(&attr, &offset) == 0, "Could not read constant"); - frame.range.end() = frame.range.begin() + offset; - break; - - // DW_AT_high_pc is a relocatable address: - case simgrid::dwarf::FormClass::Address: - xbt_assert(dwarf_formaddr(&attr, &high_pc) == 0, "Could not read address"); - frame.range.end() = base + high_pc; - break; - - default: - xbt_die("Unexpected class for DW_AT_high_pc"); - } - } - - if (klass == simgrid::dwarf::TagClass::Subprogram) { - Dwarf_Attribute attr_frame_base; - if (dwarf_attr_integrate(die, DW_AT_frame_base, &attr_frame_base)) - frame.frame_base_location = simgrid::dwarf::location_list(*info, attr_frame_base); - } - - // Handle children: - MC_dwarf_handle_children(info, die, unit, &frame, ns); - - // We sort them in order to have an (somewhat) efficient by name - // lookup: - boost::range::sort(frame.variables, MC_compare_variable); - - // Register it: - if (klass == simgrid::dwarf::TagClass::Subprogram) - info->subprograms[frame.id] = std::move(frame); - else if (klass == simgrid::dwarf::TagClass::Scope) - parent_frame->scopes.push_back(std::move(frame)); -} - -static void mc_dwarf_handle_namespace_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit, - simgrid::mc::Frame* frame, const char* ns) -{ - const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name); - xbt_assert(not frame, "Unexpected namespace in a subprogram"); - char* new_ns = ns == nullptr ? xbt_strdup(name) : bprintf("%s::%s", ns, name); - MC_dwarf_handle_children(info, die, unit, frame, new_ns); - xbt_free(new_ns); -} - -static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit, - simgrid::mc::Frame* frame, const char* ns) -{ - // For each child DIE: - Dwarf_Die child; - for (int res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child)) - MC_dwarf_handle_die(info, &child, unit, frame, ns); -} - -static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit, - simgrid::mc::Frame* frame, const char* ns) -{ - int tag = dwarf_tag(die); - simgrid::dwarf::TagClass klass = simgrid::dwarf::classify_tag(tag); - switch (klass) { - // Type: - case simgrid::dwarf::TagClass::Type: - MC_dwarf_handle_type_die(info, die, unit, frame, ns); - break; - - // Subprogram or scope: - case simgrid::dwarf::TagClass::Subprogram: - case simgrid::dwarf::TagClass::Scope: - MC_dwarf_handle_scope_die(info, die, unit, frame, ns); - return; - - // Variable: - case simgrid::dwarf::TagClass::Variable: - MC_dwarf_handle_variable_die(info, die, unit, frame, ns); - break; - - case simgrid::dwarf::TagClass::Namespace: - mc_dwarf_handle_namespace_die(info, die, unit, frame, ns); - break; - - default: - break; - } -} - -static Elf64_Half get_type(Elf* elf) -{ - if (const Elf64_Ehdr* ehdr64 = elf64_getehdr(elf)) - return ehdr64->e_type; - if (const Elf32_Ehdr* ehdr32 = elf32_getehdr(elf)) - return ehdr32->e_type; - xbt_die("Could not get ELF heeader"); -} - -static void read_dwarf_info(simgrid::mc::ObjectInformation* info, Dwarf* dwarf) -{ - // For each compilation unit: - Dwarf_Off offset = 0; - Dwarf_Off next_offset = 0; - size_t length; - - while (dwarf_nextcu(dwarf, offset, &next_offset, &length, nullptr, nullptr, nullptr) == 0) { - if (Dwarf_Die unit_die; dwarf_offdie(dwarf, offset + length, &unit_die) != nullptr) - MC_dwarf_handle_children(info, &unit_die, &unit_die, nullptr, nullptr); - offset = next_offset; - } -} - -/** Get the build-id (NT_GNU_BUILD_ID) from the ELF file - * - * This build-id may is used to locate an external debug (DWARF) file - * for this ELF file. - * - * @param elf libelf handle for an ELF file - * @return build-id for this ELF file (or an empty vector if none is found) - */ -static std::vector get_build_id(Elf* elf) -{ -#ifdef __linux - // Summary: the GNU build ID is stored in a ("GNU, NT_GNU_BUILD_ID) note - // found in a PT_NOTE entry in the program header table. - - size_t phnum; - xbt_assert(elf_getphdrnum(elf, &phnum) == 0, "Could not read program headers"); - - // Iterate over the program headers and find the PT_NOTE ones: - for (size_t i = 0; i < phnum; ++i) { - GElf_Phdr phdr_temp; - const GElf_Phdr* phdr = gelf_getphdr(elf, i, &phdr_temp); - if (phdr->p_type != PT_NOTE) - continue; - - Elf_Data* data = elf_getdata_rawchunk(elf, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR); - - // Iterate over the notes and find the NT_GNU_BUILD_ID one: - size_t pos = 0; - while (pos < data->d_size) { - GElf_Nhdr nhdr; - // Location of the name within Elf_Data: - size_t name_pos; - size_t desc_pos; - pos = gelf_getnote(data, pos, &nhdr, &name_pos, &desc_pos); - // A build ID note is identified by the pair ("GNU", NT_GNU_BUILD_ID) - // (a namespace and a type within this namespace): - if (nhdr.n_type == NT_GNU_BUILD_ID && nhdr.n_namesz == sizeof("GNU") && - memcmp(static_cast(data->d_buf) + name_pos, "GNU", sizeof("GNU")) == 0) { - XBT_DEBUG("Found GNU/NT_GNU_BUILD_ID note"); - std::byte* start = static_cast(data->d_buf) + desc_pos; - std::byte* end = start + nhdr.n_descsz; - return std::vector(start, end); - } - } - } -#endif - return std::vector(); -} - -/** Binary data to hexadecimal */ -static inline std::array to_hex(std::byte byte) -{ - constexpr std::array hexdigits{ - {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}}; - return {hexdigits[std::to_integer(byte >> 4)], hexdigits[std::to_integer(byte & std::byte{0xF})]}; -} - -/** Binary data to hexadecimal */ -static std::string to_hex(const std::byte* data, std::size_t count) -{ - std::string res; - res.resize(2 * count); - for (std::size_t i = 0; i < count; i++) - std::copy_n(cbegin(to_hex(data[i])), 2, &res[2 * i]); - return res; -} - -/** Binary data to hexadecimal */ -static std::string to_hex(std::vector const& data) -{ - return to_hex(data.data(), data.size()); -} - -/** Base directories for external debug files */ -static constexpr auto debug_paths = { - "/usr/lib/debug/", - "/usr/local/lib/debug/", -}; - -/** Locate an external debug file from the NT_GNU_BUILD_ID - * - * This is one of the mechanisms used for - * [separate debug files](https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html). - */ -// Example: -// /usr/lib/debug/.build-id/0b/dc77f1c29aea2b14ff5acd9a19ab3175ffdeae.debug -static int find_by_build_id(std::vector id) -{ - std::string filename; - std::string hex = to_hex(id); - for (const char* const& debug_path : debug_paths) { - // Example: - filename = std::string(debug_path) + ".build-id/" + to_hex(id.data(), 1) + '/' + - to_hex(id.data() + 1, id.size() - 1) + ".debug"; - XBT_DEBUG("Checking debug file: %s", filename.c_str()); - if (int fd = open(filename.c_str(), O_RDONLY); fd != -1) { - XBT_DEBUG("Found debug file: %s\n", hex.c_str()); - return fd; - } - xbt_assert(errno != ENOENT, "Could not open file: %s", strerror(errno)); - } - XBT_DEBUG("No debug info found for build ID %s\n", hex.data()); - return -1; -} - -/** @brief Populate the debugging information of the given ELF object - * - * Read the DWARF information of the ELF object and populate the - * lists of types, variables, functions. - */ -static void MC_load_dwarf(simgrid::mc::ObjectInformation* info) -{ - xbt_assert(elf_version(EV_CURRENT) != EV_NONE, "libelf initialization error"); - - // Open the ELF file: - int fd = open(info->file_name.c_str(), O_RDONLY); - xbt_assert(fd >= 0, "Could not open file %s", info->file_name.c_str()); - Elf* elf = elf_begin(fd, ELF_C_READ, nullptr); - xbt_assert(elf != nullptr && elf_kind(elf) == ELF_K_ELF, "%s is not an ELF file", info->file_name.c_str()); - - // Remember if this is a `ET_EXEC` (fixed location) or `ET_DYN`: - if (get_type(elf) == ET_EXEC) - info->flags |= simgrid::mc::ObjectInformation::Executable; - - // Read DWARF debug information in the file: - if (Dwarf* dwarf = dwarf_begin_elf(elf, DWARF_C_READ, nullptr)) { - read_dwarf_info(info, dwarf); - dwarf_end(dwarf); - elf_end(elf); - close(fd); - return; - } - - // If there was no DWARF in the file, try to find it in a separate file. - // Different methods might be used to store the DWARF information: - // * GNU NT_GNU_BUILD_ID - // * .gnu_debuglink - // See https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html - // for reference of what we are doing. - - // Try with NT_GNU_BUILD_ID: we find the build ID in the ELF file and then - // use this ID to find the file in some known locations in the filesystem. - if (std::vector build_id = get_build_id(elf); not build_id.empty()) { - elf_end(elf); - close(fd); - - // Find the debug file using the build id: - fd = find_by_build_id(build_id); - xbt_assert(fd != -1, - "Missing debug info for %s with build-id %s\n" - "You might want to install the suitable debugging package.\n", - info->file_name.c_str(), to_hex(build_id).c_str()); - - // Load the DWARF info from this file: - XBT_DEBUG("Load DWARF for %s", info->file_name.c_str()); - Dwarf* dwarf = dwarf_begin(fd, DWARF_C_READ); - xbt_assert(dwarf != nullptr, "No DWARF info for %s", info->file_name.c_str()); - read_dwarf_info(info, dwarf); - dwarf_end(dwarf); - close(fd); - return; - } - - // TODO, try to find DWARF info using .gnu_debuglink. - - elf_end(elf); - close(fd); - xbt_die("Debugging information not found for %s\n" - "Try recompiling with -g\n", - info->file_name.c_str()); -} - -// ***** Functions index - -static void MC_make_functions_index(simgrid::mc::ObjectInformation* info) -{ - info->functions_index.clear(); - - for (auto& [_, e] : info->subprograms) { - if (e.range.begin() == 0) - continue; - simgrid::mc::FunctionIndexEntry entry; - entry.low_pc = (void*)e.range.begin(); - entry.function = &e; - info->functions_index.push_back(entry); - } - - info->functions_index.shrink_to_fit(); - - // Sort the array by low_pc: - boost::range::sort(info->functions_index, - [](simgrid::mc::FunctionIndexEntry const& a, simgrid::mc::FunctionIndexEntry const& b) { - return a.low_pc < b.low_pc; - }); -} - -static void MC_post_process_variables(simgrid::mc::ObjectInformation* info) -{ - // Someone needs this to be sorted but who? - boost::range::sort(info->global_variables, MC_compare_variable); - - for (simgrid::mc::Variable& variable : info->global_variables) - if (variable.type_id) - variable.type = simgrid::util::find_map_ptr(info->types, variable.type_id); -} - -static void mc_post_process_scope(simgrid::mc::ObjectInformation* info, simgrid::mc::Frame* scope) -{ - if (scope->tag == DW_TAG_inlined_subroutine) { - // Attach correct namespaced name in inlined subroutine: - auto i = info->subprograms.find(scope->abstract_origin_id); - xbt_assert(i != info->subprograms.end(), "Could not lookup abstract origin %" PRIx64, - (std::uint64_t)scope->abstract_origin_id); - scope->name = i->second.name; - } - - // Direct: - for (simgrid::mc::Variable& variable : scope->variables) - if (variable.type_id) - variable.type = simgrid::util::find_map_ptr(info->types, variable.type_id); - - // Recursive post-processing of nested-scopes: - for (simgrid::mc::Frame& nested_scope : scope->scopes) - mc_post_process_scope(info, &nested_scope); -} - -static simgrid::mc::Type* MC_resolve_type(simgrid::mc::ObjectInformation* info, unsigned type_id) -{ - if (not type_id) - return nullptr; - simgrid::mc::Type* type = simgrid::util::find_map_ptr(info->types, type_id); - if (type == nullptr) - return nullptr; - - // We already have the information on the type: - if (type->byte_size != 0) - return type; - - // Don't have a name, we can't find a more complete version: - if (type->name.empty()) - return type; - - // Try to find a more complete description of the type: - // We need to fix in order to support C++. - if (simgrid::mc::Type** subtype = simgrid::util::find_map_ptr(info->full_types_by_name, type->name)) - type = *subtype; - return type; -} - -static void MC_post_process_types(simgrid::mc::ObjectInformation* info) -{ - // Lookup "subtype" field: - for (auto& [_, i] : info->types) { - i.subtype = MC_resolve_type(info, i.type_id); - for (simgrid::mc::Member& member : i.members) - member.type = MC_resolve_type(info, member.type_id); - } -} - -namespace simgrid::mc { - -void ObjectInformation::ensure_dwarf_loaded() -{ - if (dwarf_loaded) - return; - dwarf_loaded = true; - - MC_load_dwarf(this); - MC_post_process_variables(this); - MC_post_process_types(this); - for (auto& [_, entry] : this->subprograms) - mc_post_process_scope(this, &entry); - MC_make_functions_index(this); -} - -/** @brief Finds information about a given shared object/executable */ -std::shared_ptr createObjectInformation(std::vector const& maps, const char* name) -{ - auto result = std::make_shared(); - result->file_name = name; - simgrid::mc::find_object_address(maps, result.get()); - return result; -} - -/*************************************************************************/ - -void postProcessObjectInformation(const RemoteProcessMemory* process, ObjectInformation* info) -{ - for (auto& [_, t] : info->types) { - Type* type = &t; - Type* subtype = type; - while (subtype->type == DW_TAG_typedef || subtype->type == DW_TAG_volatile_type || - subtype->type == DW_TAG_const_type) - if (subtype->subtype) - subtype = subtype->subtype; - else - break; - - // Resolve full_type: - if (not subtype->name.empty() && subtype->byte_size == 0) - for (auto const& object_info : process->object_infos) { - auto i = object_info->full_types_by_name.find(subtype->name); - if (i != object_info->full_types_by_name.end() && not i->second->name.empty() && i->second->byte_size) { - type->full_type = i->second; - break; - } - } - else - type->full_type = subtype; - } -} - -} // namespace simgrid::mc - -namespace simgrid::dwarf { - -/** Convert a DWARF register into a libunwind register - * - * DWARF and libunwind does not use the same convention for numbering the - * registers on some architectures. The function makes the necessary - * conversion. - */ -int dwarf_register_to_libunwind(int dwarf_register) -{ -#if defined(__x86_64__) || defined(__aarch64__) - // It seems for this arch, DWARF and libunwind agree in the numbering: - return dwarf_register; -#elif defined(__i386__) - // Couldn't find the authoritative source of information for this. - // This is inspired from http://source.winehq.org/source/dlls/dbghelp/cpu_i386.c#L517. - constexpr std::array regs{ - {/* 0 */ UNW_X86_EAX, /* 1 */ UNW_X86_ECX, /* 2 */ UNW_X86_EDX, /* 3 */ UNW_X86_EBX, - /* 4 */ UNW_X86_ESP, /* 5 */ UNW_X86_EBP, /* 6 */ UNW_X86_ESI, /* 7 */ UNW_X86_EDI, - /* 8 */ UNW_X86_EIP, /* 9 */ UNW_X86_EFLAGS, /* 10 */ UNW_X86_CS, /* 11 */ UNW_X86_SS, - /* 12 */ UNW_X86_DS, /* 13 */ UNW_X86_ES, /* 14 */ UNW_X86_FS, /* 15 */ UNW_X86_GS, - /* 16 */ UNW_X86_ST0, /* 17 */ UNW_X86_ST1, /* 18 */ UNW_X86_ST2, /* 19 */ UNW_X86_ST3, - /* 20 */ UNW_X86_ST4, /* 21 */ UNW_X86_ST5, /* 22 */ UNW_X86_ST6, /* 23 */ UNW_X86_ST7}}; - return regs.at(dwarf_register); -#else -#error This architecture is not supported yet for DWARF expression evaluation. -#endif -} - -} // namespace simgrid::dwarf diff --git a/src/mc/inspect/mc_dwarf.hpp b/src/mc/inspect/mc_dwarf.hpp deleted file mode 100644 index 7575e1de85..0000000000 --- a/src/mc/inspect/mc_dwarf.hpp +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (c) 2008-2023. 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 SIMGRID_MC_DWARF_HPP -#define SIMGRID_MC_DWARF_HPP - -#include "xbt/base.h" - -#include "src/mc/mc_forward.hpp" - -namespace simgrid::dwarf { - -XBT_PRIVATE const char* attrname(int attr); -XBT_PRIVATE const char* tagname(int tag); - -XBT_PRIVATE void* resolve_member(const void* base, const simgrid::mc::Type* type, const simgrid::mc::Member* member, - const simgrid::mc::AddressSpace* snapshot); - -XBT_PRIVATE -int dwarf_register_to_libunwind(int dwarf_register); - -} // namespace simgrid::dwarf - -#endif diff --git a/src/mc/inspect/mc_dwarf_attrnames.cpp b/src/mc/inspect/mc_dwarf_attrnames.cpp deleted file mode 100644 index e050f4699d..0000000000 --- a/src/mc/inspect/mc_dwarf_attrnames.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (c) 2014-2023. 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. */ - -/* Warning: autogenerated, do not edit! */ - -#include "src/mc/inspect/mc_dwarf.hpp" - -#include -#include - -namespace { -const std::unordered_map attrname_map = { - {0x01, "DW_AT_sibling"}, - {0x02, "DW_AT_location"}, - {0x03, "DW_AT_name"}, - {0x09, "DW_AT_ordering"}, - {0x0a, "DW_AT_subscr_data"}, - {0x0b, "DW_AT_byte_size"}, - {0x0c, "DW_AT_bit_offset"}, - {0x0d, "DW_AT_bit_size"}, - {0x0f, "DW_AT_element_list"}, - {0x10, "DW_AT_stmt_list"}, - {0x11, "DW_AT_low_pc"}, - {0x12, "DW_AT_high_pc"}, - {0x13, "DW_AT_language"}, - {0x14, "DW_AT_member"}, - {0x15, "DW_AT_discr"}, - {0x16, "DW_AT_discr_value"}, - {0x17, "DW_AT_visibility"}, - {0x18, "DW_AT_import"}, - {0x19, "DW_AT_string_length"}, - {0x1a, "DW_AT_common_reference"}, - {0x1b, "DW_AT_comp_dir"}, - {0x1c, "DW_AT_const_value"}, - {0x1d, "DW_AT_containing_type"}, - {0x1e, "DW_AT_default_value"}, - {0x20, "DW_AT_inline"}, - {0x21, "DW_AT_is_optional"}, - {0x22, "DW_AT_lower_bound"}, - {0x25, "DW_AT_producer"}, - {0x27, "DW_AT_prototyped"}, - {0x2a, "DW_AT_return_addr"}, - {0x2c, "DW_AT_start_scope"}, - {0x2e, "DW_AT_bit_stride"}, - {0x2f, "DW_AT_upper_bound"}, - {0x31, "DW_AT_abstract_origin"}, - {0x32, "DW_AT_accessibility"}, - {0x33, "DW_AT_address_class"}, - {0x34, "DW_AT_artificial"}, - {0x35, "DW_AT_base_types"}, - {0x36, "DW_AT_calling_convention"}, - {0x37, "DW_AT_count"}, - {0x38, "DW_AT_data_member_location"}, - {0x39, "DW_AT_decl_column"}, - {0x3a, "DW_AT_decl_file"}, - {0x3b, "DW_AT_decl_line"}, - {0x3c, "DW_AT_declaration"}, - {0x3d, "DW_AT_discr_list"}, - {0x3e, "DW_AT_encoding"}, - {0x3f, "DW_AT_external"}, - {0x40, "DW_AT_frame_base"}, - {0x41, "DW_AT_friend"}, - {0x42, "DW_AT_identifier_case"}, - {0x43, "DW_AT_macro_info"}, - {0x44, "DW_AT_namelist_item"}, - {0x45, "DW_AT_priority"}, - {0x46, "DW_AT_segment"}, - {0x47, "DW_AT_specification"}, - {0x48, "DW_AT_static_link"}, - {0x49, "DW_AT_type"}, - {0x4a, "DW_AT_use_location"}, - {0x4b, "DW_AT_variable_parameter"}, - {0x4c, "DW_AT_virtuality"}, - {0x4d, "DW_AT_vtable_elem_location"}, - {0x4e, "DW_AT_allocated"}, - {0x4f, "DW_AT_associated"}, - {0x50, "DW_AT_data_location"}, - {0x51, "DW_AT_byte_stride"}, - {0x52, "DW_AT_entry_pc"}, - {0x53, "DW_AT_use_UTF8"}, - {0x54, "DW_AT_extension"}, - {0x55, "DW_AT_ranges"}, - {0x56, "DW_AT_trampoline"}, - {0x57, "DW_AT_call_column"}, - {0x58, "DW_AT_call_file"}, - {0x59, "DW_AT_call_line"}, - {0x5a, "DW_AT_description"}, - {0x5b, "DW_AT_binary_scale"}, - {0x5c, "DW_AT_decimal_scale"}, - {0x5d, "DW_AT_small"}, - {0x5e, "DW_AT_decimal_sign"}, - {0x5f, "DW_AT_digit_count"}, - {0x60, "DW_AT_picture_string"}, - {0x61, "DW_AT_mutable"}, - {0x62, "DW_AT_threads_scaled"}, - {0x63, "DW_AT_explicit"}, - {0x64, "DW_AT_object_pointer"}, - {0x65, "DW_AT_endianity"}, - {0x66, "DW_AT_elemental"}, - {0x67, "DW_AT_pure"}, - {0x68, "DW_AT_recursive"}, - {0x69, "DW_AT_signature"}, - {0x6a, "DW_AT_main_subprogram"}, - {0x6b, "DW_AT_data_bit_offset"}, - {0x6c, "DW_AT_const_expr"}, - {0x6d, "DW_AT_enum_class"}, - {0x6e, "DW_AT_linkage_name"}, - {0x87, "DW_AT_noreturn"}, - {0x2000, "DW_AT_lo_user"}, - {0x2001, "DW_AT_MIPS_fde"}, - {0x2002, "DW_AT_MIPS_loop_begin"}, - {0x2003, "DW_AT_MIPS_tail_loop_begin"}, - {0x2004, "DW_AT_MIPS_epilog_begin"}, - {0x2005, "DW_AT_MIPS_loop_unroll_factor"}, - {0x2006, "DW_AT_MIPS_software_pipeline_depth"}, - {0x2007, "DW_AT_MIPS_linkage_name"}, - {0x2008, "DW_AT_MIPS_stride"}, - {0x2009, "DW_AT_MIPS_abstract_name"}, - {0x200a, "DW_AT_MIPS_clone_origin"}, - {0x200b, "DW_AT_MIPS_has_inlines"}, - {0x200c, "DW_AT_MIPS_stride_byte"}, - {0x200d, "DW_AT_MIPS_stride_elem"}, - {0x200e, "DW_AT_MIPS_ptr_dopetype"}, - {0x200f, "DW_AT_MIPS_allocatable_dopetype"}, - {0x2010, "DW_AT_MIPS_assumed_shape_dopetype"}, - {0x2011, "DW_AT_MIPS_assumed_size"}, - {0x2101, "DW_AT_sf_names"}, - {0x2102, "DW_AT_src_info"}, - {0x2103, "DW_AT_mac_info"}, - {0x2104, "DW_AT_src_coords"}, - {0x2105, "DW_AT_body_begin"}, - {0x2106, "DW_AT_body_end"}, - {0x2107, "DW_AT_GNU_vector"}, - {0x2108, "DW_AT_GNU_guarded_by"}, - {0x2109, "DW_AT_GNU_pt_guarded_by"}, - {0x210a, "DW_AT_GNU_guarded"}, - {0x210b, "DW_AT_GNU_pt_guarded"}, - {0x210c, "DW_AT_GNU_locks_excluded"}, - {0x210d, "DW_AT_GNU_exclusive_locks_required"}, - {0x210e, "DW_AT_GNU_shared_locks_required"}, - {0x210f, "DW_AT_GNU_odr_signature"}, - {0x2110, "DW_AT_GNU_template_name"}, - {0x2111, "DW_AT_GNU_call_site_value"}, - {0x2112, "DW_AT_GNU_call_site_data_value"}, - {0x2113, "DW_AT_GNU_call_site_target"}, - {0x2114, "DW_AT_GNU_call_site_target_clobbered"}, - {0x2115, "DW_AT_GNU_tail_call"}, - {0x2116, "DW_AT_GNU_all_tail_call_sites"}, - {0x2117, "DW_AT_GNU_all_call_sites"}, - {0x2118, "DW_AT_GNU_all_source_call_sites"}, - {0x2119, "DW_AT_GNU_macros"}, - {0x211a, "DW_AT_GNU_deleted"}, - {0x3fff, "DW_AT_hi_user"}, -}; -} - -namespace simgrid::dwarf { - -/** @brief Get the name of an attribute (DW_AT_*) from its code - * - * @param attr attribute code (see the DWARF specification) - * @return name of the attribute - */ -XBT_PRIVATE -const char* attrname(int attr) -{ - auto name = attrname_map.find(attr); - return name == attrname_map.end() ? "DW_AT_unknown" : name->second; -} - -} // namespace simgrid::dwarf diff --git a/src/mc/inspect/mc_dwarf_tagnames.cpp b/src/mc/inspect/mc_dwarf_tagnames.cpp deleted file mode 100644 index 0fcd49f62d..0000000000 --- a/src/mc/inspect/mc_dwarf_tagnames.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright (c) 2014-2023. 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. */ - -/* Warning: autogenerated, do not edit! */ - -#include "src/mc/inspect/mc_dwarf.hpp" - -#include -#include - -namespace { -const std::unordered_map tagname_map = { - {0x00, "DW_TAG_invalid"}, - {0x01, "DW_TAG_array_type"}, - {0x02, "DW_TAG_class_type"}, - {0x03, "DW_TAG_entry_point"}, - {0x04, "DW_TAG_enumeration_type"}, - {0x05, "DW_TAG_formal_parameter"}, - {0x08, "DW_TAG_imported_declaration"}, - {0x0a, "DW_TAG_label"}, - {0x0b, "DW_TAG_lexical_block"}, - {0x0d, "DW_TAG_member"}, - {0x0f, "DW_TAG_pointer_type"}, - {0x10, "DW_TAG_reference_type"}, - {0x11, "DW_TAG_compile_unit"}, - {0x12, "DW_TAG_string_type"}, - {0x13, "DW_TAG_structure_type"}, - {0x15, "DW_TAG_subroutine_type"}, - {0x16, "DW_TAG_typedef"}, - {0x17, "DW_TAG_union_type"}, - {0x18, "DW_TAG_unspecified_parameters"}, - {0x19, "DW_TAG_variant"}, - {0x1a, "DW_TAG_common_block"}, - {0x1b, "DW_TAG_common_inclusion"}, - {0x1c, "DW_TAG_inheritance"}, - {0x1d, "DW_TAG_inlined_subroutine"}, - {0x1e, "DW_TAG_module"}, - {0x1f, "DW_TAG_ptr_to_member_type"}, - {0x20, "DW_TAG_set_type"}, - {0x21, "DW_TAG_subrange_type"}, - {0x22, "DW_TAG_with_stmt"}, - {0x23, "DW_TAG_access_declaration"}, - {0x24, "DW_TAG_base_type"}, - {0x25, "DW_TAG_catch_block"}, - {0x26, "DW_TAG_const_type"}, - {0x27, "DW_TAG_constant"}, - {0x28, "DW_TAG_enumerator"}, - {0x29, "DW_TAG_file_type"}, - {0x2a, "DW_TAG_friend"}, - {0x2b, "DW_TAG_namelist"}, - {0x2c, "DW_TAG_namelist_item"}, - {0x2d, "DW_TAG_packed_type"}, - {0x2e, "DW_TAG_subprogram"}, - {0x2f, "DW_TAG_template_type_parameter"}, - {0x30, "DW_TAG_template_value_parameter"}, - {0x31, "DW_TAG_thrown_type"}, - {0x32, "DW_TAG_try_block"}, - {0x33, "DW_TAG_variant_part"}, - {0x34, "DW_TAG_variable"}, - {0x35, "DW_TAG_volatile_type"}, - {0x36, "DW_TAG_dwarf_procedure"}, - {0x37, "DW_TAG_restrict_type"}, - {0x38, "DW_TAG_interface_type"}, - {0x39, "DW_TAG_namespace"}, - {0x3a, "DW_TAG_imported_module"}, - {0x3b, "DW_TAG_unspecified_type"}, - {0x3c, "DW_TAG_partial_unit"}, - {0x3d, "DW_TAG_imported_unit"}, - {0x3f, "DW_TAG_condition"}, - {0x40, "DW_TAG_shared_type"}, - {0x41, "DW_TAG_type_unit"}, - {0x42, "DW_TAG_rvalue_reference_type"}, - {0x43, "DW_TAG_template_alias"}, - {0x47, "DW_TAG_atomic_type"}, - {0x4080, "DW_TAG_lo_user"}, - {0x4081, "DW_TAG_MIPS_loop"}, - {0x4101, "DW_TAG_format_label"}, - {0x4102, "DW_TAG_function_template"}, - {0x4103, "DW_TAG_class_template"}, - {0x4104, "DW_TAG_GNU_BINCL"}, - {0x4105, "DW_TAG_GNU_EINCL"}, - {0x4106, "DW_TAG_GNU_template_template_param"}, - {0x4107, "DW_TAG_GNU_template_parameter_pack"}, - {0x4108, "DW_TAG_GNU_formal_parameter_pack"}, - {0x4109, "DW_TAG_GNU_call_site"}, - {0x410a, "DW_TAG_GNU_call_site_parameter"}, - {0xffff, "DW_TAG_hi_user"}, -}; -} - -namespace simgrid::dwarf { - -/** @brief Get the name of a dwarf tag (DW_TAG_*) from its code - * - * @param tag tag code (see the DWARF specification) - * @return name of the tag - */ -XBT_PRIVATE -const char* tagname(int tag) -{ - auto name = tagname_map.find(tag); - return name == tagname_map.end() ? "DW_TAG_unknown" : name->second; -} - -} // namespace simgrid::dwarf diff --git a/src/mc/inspect/mc_member.cpp b/src/mc/inspect/mc_member.cpp deleted file mode 100644 index 9e9af73d59..0000000000 --- a/src/mc/inspect/mc_member.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (c) 2014-2023. 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 "src/mc/inspect/Type.hpp" -#include "src/mc/inspect/mc_dwarf.hpp" -#include "src/mc/mc_private.hpp" - -namespace simgrid::dwarf { - -/** Resolve snapshot in the process address space - * - * @param object Process address of the struct/class - * @param type Type of the struct/class - * @param member Member description - * @param snapshot Snapshot (or nullptr) - * @return Process address of the given member of the 'object' struct/class - */ -void* resolve_member(const void* base, const simgrid::mc::Type* /*type*/, const simgrid::mc::Member* member, - const simgrid::mc::AddressSpace* address_space) -{ - ExpressionContext state; - state.address_space = address_space; - - ExpressionStack stack; - stack.push((ExpressionStack::value_type)base); - simgrid::dwarf::execute(member->location_expression, state, stack); - return (void*)stack.top(); -} - -} // namespace simgrid::dwarf diff --git a/src/mc/inspect/mc_unw.cpp b/src/mc/inspect/mc_unw.cpp deleted file mode 100644 index c93f1950fa..0000000000 --- a/src/mc/inspect/mc_unw.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* Copyright (c) 2015-2023. 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. */ - -/** \file Libunwind support for mc_address_space objects. */ - -// We need this for the register indices: -// #define _GNU_SOURCE - -#include "src/mc/inspect/mc_unw.hpp" -#include "src/mc/inspect/Frame.hpp" -#include "src/mc/sosp/RemoteProcessMemory.hpp" - -#include - -// On x86_64, libunwind unw_context_t has the same layout as ucontext_t: -#include -#include -#ifdef __FreeBSD__ -typedef register_t greg_t; -#endif - -#include - -namespace simgrid::mc { - -// ***** Implementation - -/** Get frame unwind information (libunwind method) - * - * Delegates to the local/ptrace implementation. - */ -int UnwindContext::find_proc_info(unw_addr_space_t /*as*/, unw_word_t ip, unw_proc_info_t* pip, int need_unwind_info, - void* arg) noexcept -{ - const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg; - return unw_get_accessors(context->process_->unw_underlying_addr_space) - ->find_proc_info(context->process_->unw_underlying_addr_space, ip, pip, need_unwind_info, - context->process_->unw_underlying_context); -} - -/** Release frame unwind information (libunwind method) - * - * Delegates to the local/ptrace implementation. - */ -void UnwindContext::put_unwind_info(unw_addr_space_t /*as*/, unw_proc_info_t* pip, void* arg) noexcept -{ - const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg; - return unw_get_accessors(context->process_->unw_underlying_addr_space) - ->put_unwind_info(context->process_->unw_underlying_addr_space, pip, context->process_->unw_underlying_context); -} - -/** (libunwind method) - * - * Not implemented. - */ -int UnwindContext::get_dyn_info_list_addr(unw_addr_space_t /*as*/, unw_word_t* dilap, void* arg) noexcept -{ - const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg; - return unw_get_accessors(context->process_->unw_underlying_addr_space) - ->get_dyn_info_list_addr(context->process_->unw_underlying_addr_space, dilap, - context->process_->unw_underlying_context); -} - -/** Read from the target address space memory (libunwind method) - * - * Delegates to the `simgrid::mc::Process*`. - */ -int UnwindContext::access_mem(unw_addr_space_t /*as*/, unw_word_t addr, unw_word_t* valp, int write, void* arg) noexcept -{ - const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg; - if (write) - return -UNW_EREADONLYREG; - context->address_space_->read_bytes(valp, sizeof(unw_word_t), remote(addr)); - return 0; -} - -void* UnwindContext::get_reg(unw_context_t* context, unw_regnum_t regnum) noexcept -{ -#ifdef __x86_64 - mcontext_t* mcontext = &context->uc_mcontext; - switch (regnum) { -#ifdef __linux__ - case UNW_X86_64_RAX: - return &mcontext->gregs[REG_RAX]; - case UNW_X86_64_RDX: - return &mcontext->gregs[REG_RDX]; - case UNW_X86_64_RCX: - return &mcontext->gregs[REG_RCX]; - case UNW_X86_64_RBX: - return &mcontext->gregs[REG_RBX]; - case UNW_X86_64_RSI: - return &mcontext->gregs[REG_RSI]; - case UNW_X86_64_RDI: - return &mcontext->gregs[REG_RDI]; - case UNW_X86_64_RBP: - return &mcontext->gregs[REG_RBP]; - case UNW_X86_64_RSP: - return &mcontext->gregs[REG_RSP]; - case UNW_X86_64_R8: - return &mcontext->gregs[REG_R8]; - case UNW_X86_64_R9: - return &mcontext->gregs[REG_R9]; - case UNW_X86_64_R10: - return &mcontext->gregs[REG_R10]; - case UNW_X86_64_R11: - return &mcontext->gregs[REG_R11]; - case UNW_X86_64_R12: - return &mcontext->gregs[REG_R12]; - case UNW_X86_64_R13: - return &mcontext->gregs[REG_R13]; - case UNW_X86_64_R14: - return &mcontext->gregs[REG_R14]; - case UNW_X86_64_R15: - return &mcontext->gregs[REG_R15]; - case UNW_X86_64_RIP: - return &mcontext->gregs[REG_RIP]; -#elif defined __FreeBSD__ - case UNW_X86_64_RAX: - return &mcontext->mc_rax; - case UNW_X86_64_RDX: - return &mcontext->mc_rdx; - case UNW_X86_64_RCX: - return &mcontext->mc_rcx; - case UNW_X86_64_RBX: - return &mcontext->mc_rbx; - case UNW_X86_64_RSI: - return &mcontext->mc_rsi; - case UNW_X86_64_RDI: - return &mcontext->mc_rdi; - case UNW_X86_64_RBP: - return &mcontext->mc_rbp; - case UNW_X86_64_RSP: - return &mcontext->mc_rsp; - case UNW_X86_64_R8: - return &mcontext->mc_r8; - case UNW_X86_64_R9: - return &mcontext->mc_r9; - case UNW_X86_64_R10: - return &mcontext->mc_r10; - case UNW_X86_64_R11: - return &mcontext->mc_r11; - case UNW_X86_64_R12: - return &mcontext->mc_r12; - case UNW_X86_64_R13: - return &mcontext->mc_r13; - case UNW_X86_64_R14: - return &mcontext->mc_r14; - case UNW_X86_64_R15: - return &mcontext->mc_r15; - case UNW_X86_64_RIP: - return &mcontext->mc_rip; -#else -#error "Unable to get register from ucontext, please add your case" -#endif - default: - return nullptr; - } -#else - return nullptr; -#endif -} - -/** Read a standard register (libunwind method) - */ -int UnwindContext::access_reg(unw_addr_space_t /*as*/, unw_regnum_t regnum, unw_word_t* valp, int write, - void* arg) noexcept -{ - auto* as_context = static_cast(arg); - unw_context_t* context = &as_context->unwind_context_; - if (write) - return -UNW_EREADONLYREG; - const greg_t* preg = (greg_t*)get_reg(context, regnum); - if (not preg) - return -UNW_EBADREG; - *valp = *preg; - return 0; -} - -/** Find information about a function (libunwind method) - */ -int UnwindContext::get_proc_name(unw_addr_space_t /*as*/, unw_word_t addr, char* bufp, size_t buf_len, unw_word_t* offp, - void* arg) noexcept -{ - const simgrid::mc::UnwindContext* context = (simgrid::mc::UnwindContext*)arg; - const simgrid::mc::Frame* frame = context->process_->find_function(remote(addr)); - if (not frame) - return -UNW_ENOINFO; - *offp = (unw_word_t)frame->range.begin() - addr; - - strncpy(bufp, frame->name.c_str(), buf_len); - if (bufp[buf_len - 1]) { - bufp[buf_len - 1] = 0; - return -UNW_ENOMEM; - } - - return 0; -} - -// ***** Init - -unw_addr_space_t UnwindContext::createUnwindAddressSpace() -{ - /** Virtual table for our `libunwind` implementation - * - * Stack unwinding on a `simgrid::mc::Process*` (for memory, unwinding information) - * and `ucontext_t` (for processor registers). - * - * It works with the `simgrid::mc::UnwindContext` context. - * - * Use nullptr as access_fpreg and resume, as we don't need them. - */ - unw_accessors_t accessors = {}; - accessors.find_proc_info = &find_proc_info; - accessors.put_unwind_info = &put_unwind_info; - accessors.get_dyn_info_list_addr = &get_dyn_info_list_addr; - accessors.access_mem = &access_mem; - accessors.access_reg = &access_reg; - accessors.access_fpreg = nullptr; - accessors.resume = nullptr; - accessors.get_proc_name = &get_proc_name; - return unw_create_addr_space(&accessors, BYTE_ORDER); -} - -void UnwindContext::initialize(simgrid::mc::RemoteProcessMemory& process_memory, const unw_context_t* c) -{ - this->address_space_ = &process_memory; - this->process_ = &process_memory; - - // Take a copy of the context for our own purpose: - this->unwind_context_ = *c; -#if SIMGRID_PROCESSOR_x86_64 || SIMGRID_PROCESSOR_i686 -#ifdef __linux__ - // On x86_64, ucontext_t contains a pointer to itself for FP registers. - // We don't really need support for FR registers as they are caller saved - // and probably never use those fields as libunwind-x86_64 does not read - // FP registers from the unw_context_t - // Let's ignore this and see what happens: - this->unwind_context_.uc_mcontext.fpregs = nullptr; -#endif -#elif SIMGRID_PROCESSOR_arm64 -#ifdef __linux__ - // On ARM64, ucontext_t doesn't contain `fpregs` and the FP registers - // are instead held in the `__reserved` field of the struct. It doesn't - // appear anything needs to be done here, although this should be verified -#endif -#else - // Do we need to do any fixup like this? -#error Target CPU type is not handled. -#endif -} - -unw_cursor_t UnwindContext::cursor() -{ - unw_cursor_t cursor; - xbt_assert(process_ != nullptr && address_space_ != nullptr && - unw_init_remote(&cursor, process_->unw_addr_space, this) == 0, - "UnwindContext not initialized"); - return cursor; -} - -} // namespace simgrid::mc diff --git a/src/mc/inspect/mc_unw.hpp b/src/mc/inspect/mc_unw.hpp deleted file mode 100644 index 6291c1ce4d..0000000000 --- a/src/mc/inspect/mc_unw.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (c) 2015-2023. 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 SIMGRID_MC_UNW_HPP -#define SIMGRID_MC_UNW_HPP - -/** @file - * Libunwind implementation for the model-checker - * - * Libunwind provides a pluggable stack unwinding API: the way the current - * registers and memory is accessed, the way unwinding information is found - * is pluggable. - * - * This component implements the libunwind API for he model-checker: - * - * * reading memory from a simgrid::mc::AddressSpace*; - * - * * reading stack registers from a saved snapshot (context). - * - * Parts of the libunwind information fetching is currently handled by the - * standard `libunwind` implementations (either the local one or the ptrace one) - * because parsing `.eh_frame` section is not fun and `libdw` does not help - * much here. - */ - -#include "src/mc/mc_forward.hpp" -#include "xbt/base.h" - -#include -#include - -namespace simgrid::unw { - -XBT_PRIVATE unw_addr_space_t create_addr_space(); -XBT_PRIVATE void* create_context(unw_addr_space_t as, pid_t pid); -} // namespace simgrid::unw - -namespace simgrid::mc { - -class UnwindContext { - simgrid::mc::AddressSpace* address_space_ = nullptr; - simgrid::mc::RemoteProcessMemory* process_ = nullptr; - unw_context_t unwind_context_ = {}; - -public: - void initialize(simgrid::mc::RemoteProcessMemory& process, const unw_context_t* c); - unw_cursor_t cursor(); - -private: // Methods and virtual table for libunwind - static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t* pip, int need_unwind_info, - void* arg) noexcept; - static void put_unwind_info(unw_addr_space_t as, unw_proc_info_t* pip, void* arg) noexcept; - static int get_dyn_info_list_addr(unw_addr_space_t as, unw_word_t* dilap, void* arg) noexcept; - static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t* valp, int write, void* arg) noexcept; - static void* get_reg(unw_context_t* context, unw_regnum_t regnum) noexcept; - static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t* valp, int write, void* arg) noexcept; - static int get_proc_name(unw_addr_space_t as, unw_word_t addr, char* bufp, size_t buf_len, unw_word_t* offp, - void* arg) noexcept; - -public: - // Create a libunwind address space: - static unw_addr_space_t createUnwindAddressSpace(); -}; - -void dumpStack(FILE* file, unw_cursor_t* cursor); -} // namespace simgrid::mc - -#endif diff --git a/src/mc/inspect/mc_unw_vmread.cpp b/src/mc/inspect/mc_unw_vmread.cpp deleted file mode 100644 index 7241da9279..0000000000 --- a/src/mc/inspect/mc_unw_vmread.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/** \file Libunwind namespace implementation using process_vm_readv. */ - -/* Copyright (c) 2015-2023. 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 "src/mc/inspect/mc_unw.hpp" -#include "src/mc/sosp/RemoteProcessMemory.hpp" - -#include -#include - -#include -#include -#include - - -/** Partial structure of libunwind-ptrace context in order to get the PID - * - * HACK, The context type for libunwind-race is an opaque type. - * We need to get the PID which is the first field. This is a hack - * which might break if the libunwind-ptrace structure changes. - */ -struct _UPT_info { - pid_t pid; - // Other things... -}; - -/** Read from the memory, avoid using `ptrace` (libunwind method) */ -static int access_mem(const unw_addr_space_t as, const unw_word_t addr, unw_word_t* const valp, const int write, - void* const arg) -{ - if (write) - return -UNW_EINVAL; - pid_t pid = static_cast<_UPT_info*>(arg)->pid; - size_t size = sizeof(unw_word_t); - -#if HAVE_PROCESS_VM_READV /* linux but not freebsd */ - // process_vm_read implementation. - // This is only available since Linux 3.2. - - struct iovec local = {valp, size}; - struct iovec remote = {(void*)addr, size}; - if (ssize_t s = process_vm_readv(pid, &local, 1, &remote, 1, 0); s >= 0) { - if ((size_t)s != size) - return -UNW_EINVAL; - else - return 0; - } else if (errno != ENOSYS) { - return -UNW_EINVAL; - } -#endif - - // /proc/${pid}/mem implementation. - // On recent kernels, we do not need to ptrace the target process. - // On older kernels, it is necessary to ptrace the target process. - size_t count = size; - auto off = static_cast(addr); - auto* buf = reinterpret_cast(valp); - int fd = simgrid::mc::open_vm(pid, O_RDONLY); - if (fd < 0) - return -UNW_EINVAL; - - while (count > 0) { - ssize_t nread = pread(fd, buf, count, off); - if (nread == 0) { - close(fd); - return -UNW_EINVAL; - } - if (nread == -1) - // ptrace implementation. - // We need to have PTRACE_ATTACH-ed it before. - return _UPT_access_mem(as, addr, valp, write, arg); - - count -= nread; - buf += nread; - off += nread; - } - close(fd); - return 0; -} - -namespace simgrid::unw { - -unw_addr_space_t create_addr_space() -{ - /** Virtual table for our `libunwind-process_vm_readv` implementation. - * - * This implementation reuse most the code of `libunwind-ptrace` but - * does not use ptrace() to read the target process memory by - * `process_vm_readv()` or `/dev/${pid}/mem` if possible. - * - * Does not support any MC-specific behavior (privatization, snapshots) - * and `ucontext_t`. - * - * It works with `void*` contexts allocated with `_UPT_create(pid)`. - */ - // TODO, we could get rid of this if we properly stop the model-checked - // process before reading the memory. - unw_accessors_t accessors = _UPT_accessors; - accessors.access_mem = &access_mem; - return unw_create_addr_space(&accessors, BYTE_ORDER); -} - -void* create_context(unw_addr_space_t /*as*/, pid_t pid) -{ - return _UPT_create(pid); -} - -} // namespace simgrid::unw diff --git a/src/mc/mc_base.cpp b/src/mc/mc_base.cpp index 6e4ecf107b..9791f51e71 100644 --- a/src/mc/mc_base.cpp +++ b/src/mc/mc_base.cpp @@ -13,10 +13,6 @@ #include "src/mc/mc_config.hpp" #include "src/mc/mc_replay.hpp" -#if SIMGRID_HAVE_STATEFUL_MC -#include "src/mc/sosp/RemoteProcessMemory.hpp" -#endif - XBT_LOG_NEW_DEFAULT_CATEGORY(mc, "All MC categories"); bool simgrid_mc_replay_show_backtraces = false; diff --git a/src/mc/mc_client_api.cpp b/src/mc/mc_client_api.cpp index af36677d3e..27e471d662 100644 --- a/src/mc/mc_client_api.cpp +++ b/src/mc/mc_client_api.cpp @@ -53,53 +53,3 @@ int MC_is_active() return get_model_checking_mode() == ModelCheckingMode::APP_SIDE || get_model_checking_mode() == ModelCheckingMode::CHECKER_SIDE; } - -void MC_automaton_new_propositional_symbol_pointer(const char *name, int* value) -{ -#if SIMGRID_HAVE_STATEFUL_MC - xbt_assert(get_model_checking_mode() != ModelCheckingMode::CHECKER_SIDE, - "This should be called from the client side"); - if (MC_is_active()) - AppSide::get()->declare_symbol(name, value); -#endif -} - -void MC_ignore(void* addr, size_t size) -{ -#if SIMGRID_HAVE_STATEFUL_MC - xbt_assert(get_model_checking_mode() != ModelCheckingMode::CHECKER_SIDE, - "This should be called from the client side"); - if (MC_is_active()) - AppSide::get()->ignore_memory(addr, size); -#endif -} - -void MC_unignore(void* addr, size_t size) -{ -#if SIMGRID_HAVE_STATEFUL_MC - xbt_assert(get_model_checking_mode() != ModelCheckingMode::CHECKER_SIDE, - "This should be called from the client side"); - if (MC_is_active()) - AppSide::get()->unignore_memory(addr, size); -#endif -} - -void MC_ignore_heap(void *address, size_t size) -{ -#if SIMGRID_HAVE_STATEFUL_MC - xbt_assert(get_model_checking_mode() != ModelCheckingMode::CHECKER_SIDE, - "This should be called from the client side"); - if (MC_is_active()) - AppSide::get()->ignore_heap(address, size); -#endif -} - -void MC_unignore_heap(void* address, size_t size) -{ -#if SIMGRID_HAVE_STATEFUL_MC - xbt_assert(get_model_checking_mode() != ModelCheckingMode::CHECKER_SIDE, - "This should be called from the client side"); - if (MC_is_active()) - AppSide::get()->unignore_heap(address, size); -#endif -} diff --git a/src/mc/mc_config.cpp b/src/mc/mc_config.cpp index 9253c04f0e..25f3090c76 100644 --- a/src/mc/mc_config.cpp +++ b/src/mc/mc_config.cpp @@ -8,10 +8,6 @@ #include "src/simgrid/sg_config.hpp" #include -#if SIMGRID_HAVE_STATEFUL_MC -#include -#endif - XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_cfg); static simgrid::mc::ModelCheckingMode model_checking_mode = simgrid::mc::ModelCheckingMode::NONE; @@ -52,8 +48,6 @@ simgrid::config::Flag _sg_mc_timeout{ _mc_cfg_cb_check("value to enable/disable timeout for wait requests", not MC_record_replay_is_active()); }}; -int _sg_mc_max_visited_states = 0; - static simgrid::config::Flag cfg_mc_reduction{ "model-check/reduction", "Specify the kind of exploration reduction (either none or DPOR)", "dpor", [](std::string_view value) { @@ -76,26 +70,11 @@ simgrid::config::Flag _sg_mc_random_seed{"model-check/rand-seed", "give a specific random seed to initialize the uniform distribution", 0, [](int) { _mc_cfg_cb_check("Random seed"); }}; -#if SIMGRID_HAVE_STATEFUL_MC -simgrid::config::Flag _sg_mc_checkpoint{ - "model-check/checkpoint", "Specify the amount of steps between checkpoints during stateful model-checking " - "(default: 0 => stateless verification). If value=1, one checkpoint is saved for each " - "step => faster verification, but huge memory consumption; higher values are good " - "compromises between speed and memory consumption.", - 0, [](int) { _mc_cfg_cb_check("checkpointing value"); }}; - -simgrid::config::Flag _sg_mc_property_file{ - "model-check/property", "Name of the file containing the property, as formatted by the ltl2ba program.", "", - [](const std::string&) { _mc_cfg_cb_check("property"); }}; - simgrid::config::Flag _sg_mc_comms_determinism{ - "model-check/communications-determinism", - "Whether to enable the detection of communication determinism", - false, + "model-check/communications-determinism", "Whether to enable the detection of communication determinism", false, [](bool) { _mc_cfg_cb_check("value to enable/disable the detection of determinism in the communications schemes"); }}; - simgrid::config::Flag _sg_mc_send_determinism{ "model-check/send-determinism", "Enable/disable the detection of send-determinism in the communications schemes", @@ -109,7 +88,6 @@ simgrid::config::Flag _sg_mc_unfolding_checker{ "Whether to enable the unfolding-based dynamic partial order reduction to MPI programs", false, [](bool) { _mc_cfg_cb_check("value to to enable/disable the unfolding-based dynamic partial order reduction to MPI programs"); }}; -#endif simgrid::config::Flag _sg_mc_buffering{ "smpi/buffering", @@ -124,29 +102,8 @@ simgrid::config::Flag _sg_mc_max_depth{"model-check/max-depth", 1000, [](int) { _mc_cfg_cb_check("max depth value"); }}; -static simgrid::config::Flag _sg_mc_max_visited_states__{ - "model-check/visited", - "Specify the number of visited state stored for state comparison reduction: any branch leading to a state that is " - "already stored is cut.\n" - "If value=5, the last 5 visited states are stored. If value=0 (the default), no state is stored and this reduction " - "technique is disabled.", - 0, [](int value) { - _mc_cfg_cb_check("number of stored visited states"); - _sg_mc_max_visited_states = value; - }}; - -simgrid::config::Flag _sg_mc_termination{ - "model-check/termination", "Whether to enable non progressive cycle detection", false, - [](bool) { _mc_cfg_cb_check("value to enable/disable the detection of non progressive cycles"); }}; - simgrid::mc::ReductionMode simgrid::mc::get_model_checking_reduction() { - if ((cfg_mc_reduction.get() == "dpor" || cfg_mc_reduction.get() == "sdpor" || cfg_mc_reduction.get() == "odpor") && - _sg_mc_max_visited_states__ > 0) { - XBT_INFO("Disabling DPOR since state-equality reduction is activated with 'model-check/visited'"); - return simgrid::mc::ReductionMode::none; - } - if (cfg_mc_reduction.get() == "none") { return ReductionMode::none; } else if (cfg_mc_reduction.get() == "dpor") { diff --git a/src/mc/mc_config.hpp b/src/mc/mc_config.hpp index b581155e0c..621e06f3c3 100644 --- a/src/mc/mc_config.hpp +++ b/src/mc/mc_config.hpp @@ -26,9 +26,7 @@ extern XBT_PUBLIC simgrid::config::Flag _sg_mc_unfolding_checker; extern XBT_PRIVATE simgrid::config::Flag _sg_mc_timeout; extern XBT_PRIVATE simgrid::config::Flag _sg_mc_max_depth; extern XBT_PRIVATE simgrid::config::Flag _sg_mc_random_seed; -extern "C" XBT_PUBLIC int _sg_mc_max_visited_states; extern XBT_PRIVATE simgrid::config::Flag _sg_mc_dot_output_file; -extern XBT_PRIVATE simgrid::config::Flag _sg_mc_termination; extern XBT_PUBLIC simgrid::config::Flag _sg_mc_strategy; #endif diff --git a/src/mc/mc_environ.h b/src/mc/mc_environ.h index a6e897985d..a8ff230d05 100644 --- a/src/mc/mc_environ.h +++ b/src/mc/mc_environ.h @@ -16,10 +16,6 @@ */ #define MC_ENV_SOCKET_FD "SIMGRID_MC_SOCKET_FD" -/** Environment variable name defined when ptrace(2) is used to control the MCed process. - */ -#define MC_ENV_NEED_PTRACE "SIMGRID_MC_NEED_PTRACE" - /** Environment variable used to request additional system statistics. */ #define MC_ENV_SYSTEM_STATISTICS "SIMGRID_MC_SYSTEM_STATISTICS" diff --git a/src/mc/mc_global.cpp b/src/mc/mc_global.cpp index 262fa72ef3..d7962faca4 100644 --- a/src/mc/mc_global.cpp +++ b/src/mc/mc_global.cpp @@ -6,22 +6,6 @@ #include "src/kernel/actor/ActorImpl.hpp" #include "src/mc/mc.h" -#if SIMGRID_HAVE_STATEFUL_MC -#include "src/mc/api/RemoteApp.hpp" -#include "src/mc/explo/Exploration.hpp" -#include "src/mc/inspect/mc_unw.hpp" -#include "src/mc/mc_config.hpp" -#include "src/mc/mc_private.hpp" -#include "src/mc/remote/AppSide.hpp" -#include "src/mc/sosp/Snapshot.hpp" - -#include -#include -#include -#include -#include -#endif - #include #include #include @@ -34,41 +18,6 @@ std::vector processes_time; } -#if SIMGRID_HAVE_STATEFUL_MC - -namespace simgrid::mc { - -/******************************* Core of MC *******************************/ -/**************************************************************************/ -void dumpStack(FILE* file, unw_cursor_t* cursor) -{ - int nframe = 0; - std::array buffer; - - unw_word_t off; - do { - const char* name = not unw_get_proc_name(cursor, buffer.data(), buffer.size(), &off) ? buffer.data() : "?"; - // Unmangle C++ names: - std::string realname = boost::core::demangle(name); - -#if defined(__x86_64__) - unw_word_t rip = 0; - unw_word_t rsp = 0; - unw_get_reg(cursor, UNW_X86_64_RIP, &rip); - unw_get_reg(cursor, UNW_X86_64_RSP, &rsp); - fprintf(file, " %i: %s (RIP=0x%" PRIx64 " RSP=0x%" PRIx64 ")\n", nframe, realname.c_str(), (std::uint64_t)rip, - (std::uint64_t)rsp); -#else - fprintf(file, " %i: %s\n", nframe, realname.c_str()); -#endif - - ++nframe; - } while (unw_step(cursor)); -} - -} // namespace simgrid::mc -#endif - double MC_process_clock_get(const simgrid::kernel::actor::ActorImpl* process) { if (process) { diff --git a/src/mc/mc_private.hpp b/src/mc/mc_private.hpp index facb90d12b..d4185f0b0a 100644 --- a/src/mc/mc_private.hpp +++ b/src/mc/mc_private.hpp @@ -7,7 +7,6 @@ #define SIMGRID_MC_PRIVATE_HPP #include "src/mc/mc.h" -#include "xbt/automaton.h" #include "src/mc/mc_forward.hpp" #include "src/xbt/memory_map.hpp" diff --git a/src/mc/remote/AppSide.cpp b/src/mc/remote/AppSide.cpp index 5d00307aa9..84769a1dc9 100644 --- a/src/mc/remote/AppSide.cpp +++ b/src/mc/remote/AppSide.cpp @@ -12,9 +12,6 @@ #include "src/mc/mc_base.hpp" #include "src/mc/mc_config.hpp" #include "src/mc/mc_environ.h" -#if SIMGRID_HAVE_STATEFUL_MC -#include "src/mc/sosp/RemoteProcessMemory.hpp" -#endif #if HAVE_SMPI #include "src/smpi/include/private.hpp" #endif @@ -51,7 +48,7 @@ AppSide* AppSide::get() if (std::getenv(MC_ENV_SOCKET_FD) == nullptr) // We are not in MC mode: don't initialize the MC world return nullptr; - XBT_DEBUG("Initialize the MC world. %s=%s", MC_ENV_NEED_PTRACE, std::getenv(MC_ENV_NEED_PTRACE)); + XBT_DEBUG("Initialize the MC world."); simgrid::mc::set_model_checking_mode(ModelCheckingMode::APP_SIDE); @@ -64,21 +61,6 @@ AppSide* AppSide::get() instance_ = std::make_unique(fd); - // Wait for the model-checker: - if (getenv(MC_ENV_NEED_PTRACE) != nullptr) { - errno = 0; -#if defined __linux__ - ptrace(PTRACE_TRACEME, 0, nullptr, nullptr); -#elif defined BSD - ptrace(PT_TRACE_ME, 0, nullptr, 0); -#else - xbt_die("no ptrace equivalent coded for this platform, please don't use the liveness checker here."); -#endif - - xbt_assert(errno == 0 && raise(SIGSTOP) == 0, "Could not wait for the model-checker (errno = %d: %s)", errno, - strerror(errno)); - } - instance_->handle_messages(); return instance_.get(); } @@ -206,18 +188,6 @@ void AppSide::handle_wait_child(const s_mc_message_int_t* msg) answer.value = status; xbt_assert(channel_.send(answer) == 0, "Could not send response to WAIT_CHILD: %s", strerror(errno)); } -void AppSide::handle_need_meminfo() -{ -#if SIMGRID_HAVE_STATEFUL_MC - this->need_memory_info_ = true; - s_mc_message_need_meminfo_reply_t answer = {}; - answer.type = MessageType::NEED_MEMINFO_REPLY; - answer.mmalloc_default_mdp = mmalloc_get_current_heap(); - xbt_assert(channel_.send(answer) == 0, "Could not send response to the request for meminfo: %s", strerror(errno)); -#else - xbt_die("SimGrid was compiled without MC suppport, so liveness and similar features are not available."); -#endif -} void AppSide::handle_actors_status() const { auto const& actor_list = kernel::EngineImpl::get_instance()->get_actor_list(); @@ -225,6 +195,9 @@ void AppSide::handle_actors_status() const std::vector status; for (auto const& [aid, actor] : actor_list) { + xbt_assert(actor); + xbt_assert(actor->simcall_.observer_, "simcall %s in actor %s has no observer.", actor->simcall_.get_cname(), + actor->get_cname()); s_mc_message_actors_status_one_t one = {}; one.type = MessageType::ACTORS_STATUS_REPLY_TRANSITION; one.aid = aid; @@ -336,11 +309,6 @@ void AppSide::handle_messages() handle_wait_child((s_mc_message_int_t*)message_buffer.data()); break; - case MessageType::NEED_MEMINFO: - assert_msg_size("NEED_MEMINFO", s_mc_message_t); - handle_need_meminfo(); - break; - case MessageType::ACTORS_STATUS: assert_msg_size("ACTORS_STATUS", s_mc_message_t); handle_actors_status(); @@ -361,9 +329,6 @@ void AppSide::handle_messages() void AppSide::main_loop() { simgrid::mc::processes_time.resize(simgrid::kernel::actor::ActorImpl::get_maxpid()); - MC_ignore_heap(simgrid::mc::processes_time.data(), - simgrid::mc::processes_time.size() * sizeof(simgrid::mc::processes_time[0])); - kernel::activity::CommImpl::setup_mc(); sthread_disable(); coverage_checkpoint(); @@ -383,131 +348,4 @@ void AppSide::report_assertion_failure() this->handle_messages(); } -void AppSide::ignore_memory(void* addr, std::size_t size) const -{ - if (not MC_is_active() || not need_memory_info_) - return; - -#if SIMGRID_HAVE_STATEFUL_MC - s_mc_message_ignore_memory_t message = {}; - message.type = MessageType::IGNORE_MEMORY; - message.addr = (std::uintptr_t)addr; - message.size = size; - xbt_assert(channel_.send(message) == 0, "Could not send IGNORE_MEMORY message to model-checker: %s", strerror(errno)); -#else - xbt_die("Cannot really call ignore_memory() in non-SIMGRID_MC mode."); -#endif -} - -void AppSide::unignore_memory(void* addr, std::size_t size) const -{ - if (not MC_is_active() || not need_memory_info_) - return; - -#if SIMGRID_HAVE_STATEFUL_MC - s_mc_message_ignore_memory_t message = {}; - message.type = MessageType::UNIGNORE_MEMORY; - message.addr = (std::uintptr_t)addr; - message.size = size; - xbt_assert(channel_.send(message) == 0, "Could not send UNIGNORE_MEMORY message to model-checker: %s", - strerror(errno)); -#else - xbt_die("Cannot really call unignore_memory() in non-SIMGRID_MC mode."); -#endif -} - -void AppSide::ignore_heap(void* address, std::size_t size) const -{ - if (not MC_is_active() || not need_memory_info_) - return; - -#if SIMGRID_HAVE_STATEFUL_MC - const s_xbt_mheap_t* heap = mmalloc_get_current_heap(); - - s_mc_message_ignore_heap_t message = {}; - message.type = MessageType::IGNORE_HEAP; - message.address = address; - message.size = size; - message.block = ((char*)address - (char*)heap->heapbase) / BLOCKSIZE + 1; - if (heap->heapinfo[message.block].type == 0) { - message.fragment = -1; - heap->heapinfo[message.block].busy_block.ignore++; - } else { - message.fragment = (ADDR2UINT(address) % BLOCKSIZE) >> heap->heapinfo[message.block].type; - heap->heapinfo[message.block].busy_frag.ignore[message.fragment]++; - } - - xbt_assert(channel_.send(message) == 0, "Could not send ignored region to MCer: %s", strerror(errno)); -#else - xbt_die("Cannot really call ignore_heap() in non-SIMGRID_MC mode."); -#endif -} - -void AppSide::unignore_heap(void* address, std::size_t size) const -{ - if (not MC_is_active() || not need_memory_info_) - return; - -#if SIMGRID_HAVE_STATEFUL_MC - s_mc_message_ignore_memory_t message = {}; - message.type = MessageType::UNIGNORE_HEAP; - message.addr = (std::uintptr_t)address; - message.size = size; - xbt_assert(channel_.send(message) == 0, "Could not send IGNORE_HEAP message to model-checker: %s", strerror(errno)); -#else - xbt_die("Cannot really call unignore_heap() in non-SIMGRID_MC mode."); -#endif -} - -void AppSide::declare_symbol(const char* name, int* value) const -{ - if (not MC_is_active() || not need_memory_info_) { - XBT_CRITICAL("Ignore AppSide::declare_symbol(%s)", name); - return; - } - -#if SIMGRID_HAVE_STATEFUL_MC - s_mc_message_register_symbol_t message = {}; - message.type = MessageType::REGISTER_SYMBOL; - xbt_assert(strlen(name) + 1 <= message.name.size(), "Symbol is too long"); - strncpy(message.name.data(), name, message.name.size() - 1); - message.callback = nullptr; - message.data = value; - xbt_assert(channel_.send(message) == 0, "Could send REGISTER_SYMBOL message to model-checker: %s", strerror(errno)); -#else - xbt_die("Cannot really call declare_symbol() in non-SIMGRID_MC mode."); -#endif -} - -/** Register a stack in the model checker - * - * The stacks are allocated in the heap. The MC handle them specifically - * when we analyze/compare the content of the heap so it must be told where - * they are with this function. - */ -#if HAVE_UCONTEXT_H /* Apple don't want us to use ucontexts */ -void AppSide::declare_stack(void* stack, size_t size, ucontext_t* context) const -{ - if (not MC_is_active() || not need_memory_info_) - return; - -#if SIMGRID_HAVE_STATEFUL_MC - const s_xbt_mheap_t* heap = mmalloc_get_current_heap(); - - s_stack_region_t region = {}; - region.address = stack; - region.context = context; - region.size = size; - region.block = ((char*)stack - (char*)heap->heapbase) / BLOCKSIZE + 1; - - s_mc_message_stack_region_t message = {}; - message.type = MessageType::STACK_REGION; - message.stack_region = region; - xbt_assert(channel_.send(message) == 0, "Could not send STACK_REGION to model-checker: %s", strerror(errno)); -#else - xbt_die("Cannot really call declare_stack() in non-SIMGRID_MC mode."); -#endif -} -#endif - } // namespace simgrid::mc diff --git a/src/mc/remote/AppSide.hpp b/src/mc/remote/AppSide.hpp index 57189e65f0..03250e901b 100644 --- a/src/mc/remote/AppSide.hpp +++ b/src/mc/remote/AppSide.hpp @@ -22,7 +22,6 @@ class XBT_PUBLIC AppSide { private: Channel channel_; static std::unique_ptr instance_; - bool need_memory_info_ = false; /* by default we don't send memory info, unless we got a NEED_MEMINFO */ std::unordered_map child_statuses_; public: @@ -36,7 +35,6 @@ private: void handle_finalize(const s_mc_message_int_t* msg) const; void handle_fork(const s_mc_message_fork_t* msg); void handle_wait_child(const s_mc_message_int_t* msg); - void handle_need_meminfo(); void handle_actors_status() const; void handle_actors_maxpid() const; @@ -45,14 +43,6 @@ public: Channel& get_channel() { return channel_; } XBT_ATTRIB_NORETURN void main_loop(); void report_assertion_failure(); - void ignore_memory(void* addr, std::size_t size) const; - void unignore_memory(void* addr, std::size_t size) const; - void ignore_heap(void* addr, std::size_t size) const; - void unignore_heap(void* addr, std::size_t size) const; - void declare_symbol(const char* name, int* value) const; -#if HAVE_UCONTEXT_H - void declare_stack(void* stack, size_t size, ucontext_t* context) const; -#endif // TODO, remove the singleton antipattern. static AppSide* get(); diff --git a/src/mc/remote/CheckerSide.cpp b/src/mc/remote/CheckerSide.cpp index f7316ece6d..2ad4f7ed08 100644 --- a/src/mc/remote/CheckerSide.cpp +++ b/src/mc/remote/CheckerSide.cpp @@ -9,11 +9,6 @@ #include "xbt/config.hpp" #include "xbt/system_error.hpp" -#if SIMGRID_HAVE_STATEFUL_MC -#include "src/mc/explo/LivenessChecker.hpp" -#include "src/mc/sosp/RemoteProcessMemory.hpp" -#endif - #ifdef __linux__ #include #endif @@ -41,7 +36,7 @@ static simgrid::config::Flag _sg_mc_setenv{ namespace simgrid::mc { -XBT_ATTRIB_NORETURN static void run_child_process(int socket, const std::vector& args, bool need_ptrace) +XBT_ATTRIB_NORETURN static void run_child_process(int socket, const std::vector& args) { /* On startup, simix_global_init() calls simgrid::mc::Client::initialize(), which checks whether the MC_ENV_SOCKET_FD * env variable is set. If so, MC mode is assumed, and the client is setup from its side @@ -56,8 +51,6 @@ XBT_ATTRIB_NORETURN static void run_child_process(int socket, const std::vector< #endif setenv(MC_ENV_SOCKET_FD, std::to_string(socket).c_str(), 1); - if (need_ptrace) - setenv(MC_ENV_NEED_PTRACE, "1", 1); /* Setup the tokenizer that parses the cfg:model-check/setenv parameter */ using Tokenizer = boost::tokenizer>; @@ -175,9 +168,9 @@ void CheckerSide::setup_events(bool socket_only) } /* When this constructor is called, no other checkerside exists */ -CheckerSide::CheckerSide(const std::vector& args, bool need_memory_info) : running_(true) +CheckerSide::CheckerSide(const std::vector& args) : running_(true) { - XBT_DEBUG("Create a CheckerSide. Needs_meminfo: %s", need_memory_info ? "YES" : "no"); + XBT_DEBUG("Create a CheckerSide."); // Create an AF_UNIX socketpair used for exchanging messages between the model-checker process (ancestor) // and the application process (child) @@ -196,7 +189,7 @@ CheckerSide::CheckerSide(const std::vector& args, bool need_memory_info) if (pid_ == 0) { // Child ::close(sockets[1]); - run_child_process(sockets[0], args, need_memory_info); // We need ptrace if we need the mem info + run_child_process(sockets[0], args); DIE_IMPOSSIBLE; } @@ -205,28 +198,6 @@ CheckerSide::CheckerSide(const std::vector& args, bool need_memory_info) channel_.reset_socket(sockets[1]); setup_events(false); /* we need a signal handler too */ - if (need_memory_info) { -#if SIMGRID_HAVE_STATEFUL_MC - // setup ptrace and sync with the app - wait_application_process(pid_); - - // Request the initial memory on need - channel_.send(MessageType::NEED_MEMINFO); - s_mc_message_need_meminfo_reply_t answer; - ssize_t answer_size = channel_.receive(answer); - xbt_assert(answer_size != -1, "Could not receive message"); - xbt_assert(answer.type == MessageType::NEED_MEMINFO_REPLY, - "The received message is not the NEED_MEMINFO_REPLY I was expecting but of type %s", - to_c_str(answer.type)); - xbt_assert(answer_size == sizeof answer, "Broken message (size=%zd; expected %zu)", answer_size, sizeof answer); - - /* We now have enough info to create the memory address space */ - remote_memory_ = std::make_unique(pid_, answer.mmalloc_default_mdp); -#else - xbt_die("Cannot introspect memory without MC support"); -#endif - } - wait_for_requests(); } @@ -306,97 +277,6 @@ bool CheckerSide::handle_message(const char* buffer, ssize_t size) memcpy(&base_message, buffer, sizeof(base_message)); switch (base_message.type) { - case MessageType::IGNORE_HEAP: { - consumed = sizeof(s_mc_message_ignore_heap_t); -#if SIMGRID_HAVE_STATEFUL_MC - if (remote_memory_ != nullptr) { - s_mc_message_ignore_heap_t message; - xbt_assert(size >= static_cast(sizeof(message)), "Broken message"); - memcpy(&message, buffer, sizeof(message)); - - IgnoredHeapRegion region; - region.block = message.block; - region.fragment = message.fragment; - region.address = message.address; - region.size = message.size; - get_remote_memory()->ignore_heap(region); - } else -#endif - XBT_INFO("Ignoring a IGNORE_HEAP message because we don't need to introspect memory."); - break; - } - - case MessageType::UNIGNORE_HEAP: { - consumed = sizeof(s_mc_message_ignore_memory_t); -#if SIMGRID_HAVE_STATEFUL_MC - if (remote_memory_ != nullptr) { - s_mc_message_ignore_memory_t message; - xbt_assert(size == static_cast(sizeof(message)), "Broken message"); - memcpy(&message, buffer, sizeof(message)); - get_remote_memory()->unignore_heap((void*)message.addr, message.size); - } else -#endif - XBT_INFO("Ignoring an UNIGNORE_HEAP message because we don't need to introspect memory."); - break; - } - - case MessageType::IGNORE_MEMORY: { - consumed = sizeof(s_mc_message_ignore_memory_t); -#if SIMGRID_HAVE_STATEFUL_MC - if (remote_memory_ != nullptr) { - s_mc_message_ignore_memory_t message; - xbt_assert(size >= static_cast(sizeof(message)), "Broken message"); - memcpy(&message, buffer, sizeof(message)); - get_remote_memory()->ignore_region(message.addr, message.size); - } else -#endif - XBT_INFO("Ignoring an IGNORE_MEMORY message because we don't need to introspect memory."); - break; - } - - case MessageType::UNIGNORE_MEMORY: { - consumed = sizeof(s_mc_message_ignore_memory_t); -#if SIMGRID_HAVE_STATEFUL_MC - if (remote_memory_ != nullptr) { - s_mc_message_ignore_memory_t message; - xbt_assert(size >= static_cast(sizeof(message)), "Broken message"); - memcpy(&message, buffer, sizeof(message)); - get_remote_memory()->unignore_region(message.addr, message.size); - } else -#endif - XBT_INFO("Ignoring an UNIGNORE_MEMORY message because we don't need to introspect memory."); - break; - } - - case MessageType::STACK_REGION: { - consumed = sizeof(s_mc_message_stack_region_t); -#if SIMGRID_HAVE_STATEFUL_MC - if (remote_memory_ != nullptr) { - s_mc_message_stack_region_t message; - xbt_assert(size >= static_cast(sizeof(message)), "Broken message"); - memcpy(&message, buffer, sizeof(message)); - get_remote_memory()->stack_areas().push_back(message.stack_region); - } else -#endif - XBT_INFO("Ignoring an STACK_REGION message because we don't need to introspect memory."); - break; - } - - case MessageType::REGISTER_SYMBOL: { - consumed = sizeof(s_mc_message_register_symbol_t); -#if SIMGRID_HAVE_STATEFUL_MC - s_mc_message_register_symbol_t message; - xbt_assert(size >= static_cast(sizeof(message)), "Broken message"); - memcpy(&message, buffer, sizeof(message)); - xbt_assert(not message.callback, "Support for client-side function proposition is not implemented."); - XBT_DEBUG("Received symbol: %s", message.name.data()); - - LivenessChecker::automaton_register_symbol(*get_remote_memory(), message.name.data(), remote((int*)message.data)); -#else - xbt_die("Please don't use liveness properties when MC is compiled out."); -#endif - break; - } case MessageType::WAITING: consumed = sizeof(s_mc_message_t); @@ -430,20 +310,11 @@ void CheckerSide::wait_for_requests() XBT_DEBUG("Resume the application"); if (get_channel().send(MessageType::CONTINUE) != 0) throw xbt::errno_error(); - clear_memory_cache(); if (running()) dispatch_events(); } -void CheckerSide::clear_memory_cache() -{ -#if SIMGRID_HAVE_STATEFUL_MC - if (remote_memory_) - remote_memory_->clear_cache(); -#endif -} - void CheckerSide::handle_dead_child(int status) { // From PTRACE_O_TRACEEXIT: diff --git a/src/mc/remote/CheckerSide.hpp b/src/mc/remote/CheckerSide.hpp index d89f7121f6..f4605e4cd2 100644 --- a/src/mc/remote/CheckerSide.hpp +++ b/src/mc/remote/CheckerSide.hpp @@ -21,9 +21,6 @@ class CheckerSide { event* socket_event_; event* signal_event_; std::unique_ptr base_{nullptr, &event_base_free}; -#if SIMGRID_HAVE_STATEFUL_MC - std::unique_ptr remote_memory_; -#endif Channel channel_; bool running_ = false; @@ -33,13 +30,12 @@ class CheckerSide { CheckerSide* child_checker_ = nullptr; void setup_events(bool socket_only); // Part of the initialization - void clear_memory_cache(); void handle_dead_child(int status); // Launched when the dying child is the PID we follow void handle_waitpid(); // Launched when receiving a sigchild public: explicit CheckerSide(int socket, CheckerSide* child_checker); - explicit CheckerSide(const std::vector& args, bool need_memory_introspection); + explicit CheckerSide(const std::vector& args); ~CheckerSide(); // No copy: @@ -66,9 +62,6 @@ public: pid_t get_pid() const { return pid_; } bool running() const { return running_; } void terminate() { running_ = false; } -#if SIMGRID_HAVE_STATEFUL_MC - RemoteProcessMemory* get_remote_memory() { return remote_memory_.get(); } -#endif }; } // namespace simgrid::mc diff --git a/src/mc/remote/mc_protocol.h b/src/mc/remote/mc_protocol.h index dfe103b06f..0c41b275ea 100644 --- a/src/mc/remote/mc_protocol.h +++ b/src/mc/remote/mc_protocol.h @@ -14,7 +14,6 @@ #include "simgrid/forward.h" // aid_t #include "src/mc/datatypes.h" -#include "src/xbt/mmalloc/mmalloc.h" #include #include @@ -24,12 +23,10 @@ // ***** Messages namespace simgrid::mc { -XBT_DECLARE_ENUM_CLASS(MessageType, NONE, NEED_MEMINFO, NEED_MEMINFO_REPLY, FORK, FORK_REPLY, WAIT_CHILD, - WAIT_CHILD_REPLY, CONTINUE, IGNORE_HEAP, UNIGNORE_HEAP, IGNORE_MEMORY, UNIGNORE_MEMORY, - STACK_REGION, REGISTER_SYMBOL, DEADLOCK_CHECK, DEADLOCK_CHECK_REPLY, WAITING, SIMCALL_EXECUTE, - SIMCALL_EXECUTE_REPLY, ASSERTION_FAILED, ACTORS_STATUS, ACTORS_STATUS_REPLY_COUNT, - ACTORS_STATUS_REPLY_SIMCALL, ACTORS_STATUS_REPLY_TRANSITION, ACTORS_MAXPID, ACTORS_MAXPID_REPLY, - FINALIZE, FINALIZE_REPLY); +XBT_DECLARE_ENUM_CLASS(MessageType, NONE, FORK, FORK_REPLY, WAIT_CHILD, WAIT_CHILD_REPLY, CONTINUE, DEADLOCK_CHECK, + DEADLOCK_CHECK_REPLY, WAITING, SIMCALL_EXECUTE, SIMCALL_EXECUTE_REPLY, ASSERTION_FAILED, + ACTORS_STATUS, ACTORS_STATUS_REPLY_COUNT, ACTORS_STATUS_REPLY_SIMCALL, + ACTORS_STATUS_REPLY_TRANSITION, ACTORS_MAXPID, ACTORS_MAXPID_REPLY, FINALIZE, FINALIZE_REPLY); } // namespace simgrid::mc constexpr unsigned MC_MESSAGE_LENGTH = 512; @@ -57,38 +54,8 @@ struct s_mc_message_int_t { }; /* Client->Server */ -struct s_mc_message_ignore_heap_t { - simgrid::mc::MessageType type; - int block; - int fragment; - void* address; - size_t size; -}; - -struct s_mc_message_ignore_memory_t { - simgrid::mc::MessageType type; - uint64_t addr; - size_t size; -}; - -struct s_mc_message_stack_region_t { - simgrid::mc::MessageType type; - s_stack_region_t stack_region; -}; - -struct s_mc_message_register_symbol_t { - simgrid::mc::MessageType type; - std::array name; - int (*callback)(void*); - void* data; -}; /* Server -> client */ -struct s_mc_message_need_meminfo_reply_t { - simgrid::mc::MessageType type; - xbt_mheap_t mmalloc_default_mdp; -}; - struct s_mc_message_fork_t { simgrid::mc::MessageType type; std::array socket_name; diff --git a/src/mc/sosp/ChunkedData.cpp b/src/mc/sosp/ChunkedData.cpp deleted file mode 100644 index 75c53416d4..0000000000 --- a/src/mc/sosp/ChunkedData.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (c) 2007-2023. 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 "src/mc/AddressSpace.hpp" -#include "src/mc/sosp/ChunkedData.hpp" - -namespace simgrid::mc { - -/** Take a per-page snapshot of a region - * - * @param addr The start of the region (must be at the beginning of a page) - * @param page_count Number of pages of the region - * @return Snapshot page numbers of this new snapshot - */ -ChunkedData::ChunkedData(PageStore& store, const AddressSpace& as, RemotePtr addr, std::size_t page_count) - : store_(&store) -{ - this->pagenos_.resize(page_count); - std::vector buffer(xbt_pagesize); - - for (size_t i = 0; i != page_count; ++i) { - RemotePtr page = remote((void*)simgrid::mc::mmu::join(i, addr.address())); - xbt_assert(simgrid::mc::mmu::split(page.address()).second == 0, "Not at the beginning of a page"); - - /* Adding another copy (and a syscall) will probably slow things a lot. - TODO, optimize this somehow (at least by grouping the syscalls) - if needed. Either: - - reduce the number of syscalls - - let the application snapshot itself - - move the segments in shared memory (this will break `fork` however) - */ - - as.read_bytes(buffer.data(), xbt_pagesize, page); - - pagenos_[i] = store_->store_page(buffer.data()); - } -} - -} // namespace simgrid::mc diff --git a/src/mc/sosp/ChunkedData.hpp b/src/mc/sosp/ChunkedData.hpp deleted file mode 100644 index c4a706ff15..0000000000 --- a/src/mc/sosp/ChunkedData.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright (c) 2014-2023. 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 SIMGRID_MC_CHUNKED_DATA_HPP -#define SIMGRID_MC_CHUNKED_DATA_HPP - -#include - -#include "src/mc/mc_forward.hpp" -#include "src/mc/remote/RemotePtr.hpp" -#include "src/mc/sosp/PageStore.hpp" - -namespace simgrid::mc { - -/** A byte-string represented as a sequence of chunks from a PageStore - * - * In order to save memory when taking memory snapshots, a given byte-string - * is split in fixed-size chunks. Identical chunks (either from the same - * snapshot or more probably from different snapshots) share the same memory - * storage. - * - * Thus a chunked is represented as a sequence of indices of each chunk. - */ -class ChunkedData { - /** This is where we store the chunks */ - PageStore* store_ = nullptr; - /** Indices of the chunks in the `PageStore` */ - std::vector pagenos_; - -public: - ChunkedData() = default; - void clear() - { - for (std::size_t const& pageno : pagenos_) - store_->unref_page(pageno); - pagenos_.clear(); - } - ~ChunkedData() { clear(); } - - // Copy and move - ChunkedData(ChunkedData const& that) : store_(that.store_), pagenos_(that.pagenos_) - { - for (std::size_t const& pageno : pagenos_) - store_->ref_page(pageno); - } - ChunkedData(ChunkedData&& that) noexcept : pagenos_(std::move(that.pagenos_)) - { - std::swap(store_, that.store_); - that.pagenos_.clear(); - } - ChunkedData& operator=(ChunkedData const& that) - { - if (this != &that) { - this->clear(); - store_ = that.store_; - pagenos_ = that.pagenos_; - for (std::size_t const& pageno : pagenos_) - store_->ref_page(pageno); - } - return *this; - } - ChunkedData& operator=(ChunkedData&& that) noexcept - { - if (this != &that) { - this->clear(); - store_ = that.store_; - that.store_ = nullptr; - pagenos_ = std::move(that.pagenos_); - that.pagenos_.clear(); - } - return *this; - } - - /** How many pages are used */ - std::size_t page_count() const { return pagenos_.size(); } - - /** Get a chunk index */ - std::size_t pageno(std::size_t i) const { return pagenos_[i]; } - - /** Get a view of the chunk indices */ - const std::size_t* pagenos() const { return pagenos_.data(); } - - /** Get a pointer to a chunk */ - void* page(std::size_t i) const { return store_->get_page(pagenos_[i]); } - - ChunkedData(PageStore& store, const AddressSpace& as, RemotePtr addr, std::size_t page_count); -}; - -} // namespace simgrid::mc - -#endif diff --git a/src/mc/sosp/PageStore.cpp b/src/mc/sosp/PageStore.cpp deleted file mode 100644 index e2c46f400d..0000000000 --- a/src/mc/sosp/PageStore.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* Copyright (c) 2015-2023. 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 -#ifdef __FreeBSD__ -#define MAP_POPULATE MAP_PREFAULT_READ -#endif - -#include "src/internal_config.h" -#include "xbt/log.h" -#include "xbt/sysdep.h" - -#include "src/3rd-party/xxhash.hpp" -#include "src/mc/mc_mmu.hpp" -#include "src/mc/sosp/PageStore.hpp" - -#include // memcpy, memcmp -#include - -namespace simgrid::mc { - -/** @brief Compute a hash for the given memory page - * - * The page is used before inserting the page in the page store in order to find duplicate of this page in the page - * store. - * - * @param data Memory page - * @return hash off the page - */ -static XBT_ALWAYS_INLINE PageStore::hash_type mc_hash_page(const void* data) -{ - return xxh::xxhash<64>(data, xbt_pagesize); -} - -// ***** snapshot_page_manager - -PageStore::PageStore(std::size_t size) : capacity_(size) -{ - // Using mmap in order to be able to expand the region by relocating it somewhere else in the virtual memory space: - void* memory = - ::mmap(nullptr, size << xbt_pagebits, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); - xbt_assert(memory != MAP_FAILED, "Could not mmap initial snapshot pages."); - - this->top_index_ = 0; - this->memory_ = memory; - this->page_counts_.resize(size); -} - -PageStore::~PageStore() -{ - ::munmap(this->memory_, this->capacity_ << xbt_pagebits); -} - -void PageStore::resize(std::size_t size) -{ - size_t old_bytesize = this->capacity_ << xbt_pagebits; - size_t new_bytesize = size << xbt_pagebits; - void* new_memory; - - // Expand the memory region by moving it into another - // virtual memory address if necessary: -#if HAVE_MREMAP - new_memory = mremap(this->memory_, old_bytesize, new_bytesize, MREMAP_MAYMOVE); - xbt_assert(new_memory != MAP_FAILED, "Could not mremap snapshot pages."); -#else - if (new_bytesize > old_bytesize) { - // Grow: first try to add new space after current map - new_memory = mmap((char*)this->memory_ + old_bytesize, new_bytesize - old_bytesize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); - xbt_assert(new_memory != MAP_FAILED, "Could not mremap snapshot pages."); - // Check if expanding worked - if (new_memory == (char*)this->memory_ + old_bytesize) { - new_memory = this->memory_; - } else { - // New memory segment could not be put at the end of this->memory_, - // so cancel this one and try to relocate everything and copy data - munmap(new_memory, new_bytesize - old_bytesize); - new_memory = - mmap(nullptr, new_bytesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); - xbt_assert(new_memory != MAP_FAILED, "Could not mremap snapshot pages."); - memcpy(new_memory, this->memory_, old_bytesize); - munmap(this->memory_, old_bytesize); - } - } else { - // We don't have functions to shrink a mapping, so leave memory as - // it is for now - new_memory = this->memory_; - } -#endif - - this->capacity_ = size; - this->memory_ = new_memory; - this->page_counts_.resize(size, 0); -} - -/** Allocate a free page - * - * @return index of the free page - */ -std::size_t PageStore::alloc_page() -{ - if (this->free_pages_.empty()) { - // Expand the region: - if (this->top_index_ == this->capacity_) - // All the pages are allocated, we need add more pages: - this->resize(2 * this->capacity_); - - // Use a page from the top: - return this->top_index_++; - } else { - // Use a page from free_pages_ (inside of the region): - size_t res = this->free_pages_[this->free_pages_.size() - 1]; - this->free_pages_.pop_back(); - return res; - } -} - -void PageStore::remove_page(std::size_t pageno) -{ - this->free_pages_.push_back(pageno); - const void* page = this->get_page(pageno); - hash_type hash = mc_hash_page(page); - this->hash_index_[hash].erase(pageno); -} - -/** Store a page in memory */ -std::size_t PageStore::store_page(const void* page) -{ - xbt_assert(top_index_ <= this->capacity_, "top_index is not consistent"); - - // First, we check if a page with the same content is already in the page store: - // 1. compute the hash of the page - // 2. find pages with the same hash using `hash_index_` - // 3. find a page with the same content - hash_type hash = mc_hash_page(page); - - // Try to find a duplicate in set of pages with the same hash: - page_set_type& page_set = this->hash_index_[hash]; - for (size_t const& pageno : page_set) { - const void* snapshot_page = this->get_page(pageno); - if (memcmp(page, snapshot_page, xbt_pagesize) == 0) { - // If a page with the same content is already in the page store it's reused and its refcount is incremented. - page_counts_[pageno]++; - return pageno; - } - } - - // Otherwise, a new page is allocated in the page store and the content of the page is `memcpy()`-ed to this new page. - std::size_t pageno = alloc_page(); - xbt_assert(this->page_counts_[pageno] == 0, "Allocated page is already used"); - void* snapshot_page = this->get_page(pageno); - memcpy(snapshot_page, page, xbt_pagesize); - page_set.insert(pageno); - page_counts_[pageno]++; - return pageno; -} - -} // namespace simgrid::mc diff --git a/src/mc/sosp/PageStore.hpp b/src/mc/sosp/PageStore.hpp deleted file mode 100644 index 034512c121..0000000000 --- a/src/mc/sosp/PageStore.hpp +++ /dev/null @@ -1,193 +0,0 @@ -/* Copyright (c) 2015-2023. 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 SIMGRID_MC_PAGESTORE_HPP -#define SIMGRID_MC_PAGESTORE_HPP - -#include "src/mc/mc_forward.hpp" -#include "src/mc/mc_mmu.hpp" - -#include -#include -#include - -#ifndef XBT_ALWAYS_INLINE -#define XBT_ALWAYS_INLINE inline __attribute__((always_inline)) -#endif - -namespace simgrid::mc { - -/** @brief Storage for snapshot memory pages - * - * The first (lower) layer of the per-page snapshot mechanism is a page store: - * its responsibility is to store immutable shareable reference-counted memory - * pages independently of the snapshotting logic. Snapshot management and - * representation is handled to an higher layer. READMORE - * - * Data structure: - * - * * A pointer (`memory_`) to a (currently anonymous) `mmap()`ed memory - * region holding the memory pages (the address of the first page). - * - * We want to keep this memory region aligned on the memory pages (so - * that we might be able to create non-linear memory mappings on those - * pages in the future) and be able to expand it without copying the - * data (there will be a lot of pages here): we will be able to - * efficiently expand the memory mapping using `mremap()`, moving it - * to another virtual address if necessary. - * - * Because we will move this memory mapping on the virtual address - * space, only the index of the page will be stored in the snapshots - * and the page will always be looked up by going through `memory`: - * - * void* page = (char*) page_store->memory + page_index << pagebits; - * - * * The number of pages mapped in virtual memory (`capacity_`). Once all - * those pages are used, we need to expand the page store with - * `mremap()`. - * - * * A reference count for each memory page `page_counts_`. Each time a - * snapshot references a page, the counter is incremented. If a - * snapshot is freed, the reference count is decremented. When the - * reference count, of a page reaches 0 it is added to a list of available - * pages (`free_pages_`). - * - * * A list of free pages `free_pages_` which can be reused. This avoids having - * to scan the reference count list to find a free page. - * - * * When we are expanding the memory map we do not want to add thousand of page - * to the `free_pages_` list and remove them just afterwards. The `top_index_` - * field is an index after which all pages are free and are not in the `free_pages_` - * list. - * - * * When we are adding a page, we need to check if a page with the same - * content is already in the page store in order to reuse it. For this - * reason, we maintain an index (`hash_index_`) mapping the hash of a - * page to the list of page indices with this hash. - * We use a fast (non cryptographic) hash so there may be conflicts: - * we must be able to store multiple indices for the same hash. - * - */ -class PageStore { -public: // Types - using hash_type = std::uint64_t; - -private: - // Types - // We are using a cheap hash to index a page. - // We should expect collision and we need to associate multiple page indices - // to the same hash. - using page_set_type = std::unordered_set; - using pages_map_type = std::unordered_map; - - // Fields: - /** First page */ - void* memory_; - /** Number of available pages in virtual memory */ - std::size_t capacity_; - /** Top of the used pages (index of the next available page) */ - std::size_t top_index_; - /** Page reference count */ - std::vector page_counts_; - /** Index of available pages before the top */ - std::vector free_pages_; - /** Index from page hash to page index */ - pages_map_type hash_index_; - - // Methods - void resize(std::size_t size); - std::size_t alloc_page(); - void remove_page(std::size_t pageno); - -public: - // Constructors - PageStore(PageStore const&) = delete; - PageStore& operator=(PageStore const&) = delete; - explicit PageStore(std::size_t size); - ~PageStore(); - - // Methods - - /** @brief Decrement the reference count for a given page - * - * Decrement the reference count of this page. Used when a snapshot is destroyed. - * - * If the reference count reaches zero, the page is recycled: - * it is added to the `free_pages_` list and removed from the `hash_index_`. - * - * */ - void unref_page(std::size_t pageno); - - /** @brief Increment the refcount for a given page - * - * This method used to increase a reference count of a page if we know - * that the content of a page is the same as a page already in the page - * store. - * - * This will be the case if a page if soft clean: we know that is has not - * changed since the previous snapshot/restoration and we can avoid - * hashing the page, comparing byte-per-byte to candidates. - * */ - void ref_page(size_t pageno); - - /** @brief Store a page in the page store */ - std::size_t store_page(const void* page); - - /** @brief Get a page from its page number - * - * @param pageno Number of the memory page in the store - * @return Start of the page - */ - void* get_page(std::size_t pageno) const; - - // Debug/test methods - - /** @brief Get the number of references for a page */ - std::size_t get_ref(std::size_t pageno) const; - - /** @brief Get the number of used pages */ - std::size_t size() const; - - /** @brief Get the capacity of the page store - * - * The capacity is expanded by a system call (mremap). - * */ - std::size_t capacity() const; -}; - -XBT_ALWAYS_INLINE void PageStore::unref_page(std::size_t pageno) -{ - if ((--this->page_counts_[pageno]) == 0) - this->remove_page(pageno); -} - -XBT_ALWAYS_INLINE void PageStore::ref_page(size_t pageno) -{ - ++this->page_counts_[pageno]; -} - -XBT_ALWAYS_INLINE void* PageStore::get_page(std::size_t pageno) const -{ - return (void*)simgrid::mc::mmu::join(pageno, (std::uintptr_t)this->memory_); -} - -XBT_ALWAYS_INLINE std::size_t PageStore::get_ref(std::size_t pageno) const -{ - return this->page_counts_[pageno]; -} - -XBT_ALWAYS_INLINE std::size_t PageStore::size() const -{ - return this->top_index_ - this->free_pages_.size(); -} - -XBT_ALWAYS_INLINE std::size_t PageStore::capacity() const -{ - return this->capacity_; -} - -} // namespace simgrid::mc - -#endif diff --git a/src/mc/sosp/PageStore_test.cpp b/src/mc/sosp/PageStore_test.cpp deleted file mode 100644 index 8de5bc98e6..0000000000 --- a/src/mc/sosp/PageStore_test.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (c) 2015-2023. 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 "src/3rd-party/catch.hpp" - -#include -#include -#include -#include - -#include -#include - -#include - -#include "src/mc/sosp/PageStore.hpp" - -/***********************************/ -// a class to hold the variable used in the test cases -class pstore_test_helper { - const size_t pagesize = getpagesize(); - simgrid::mc::PageStore store{50}; - std::byte* data = - static_cast(mmap(nullptr, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); - std::array pageno = {0, 0, 0, 0}; - int value = 0; - - void new_content(std::byte* buf, size_t size); - -public: - // member functions used by the test suite(s) - void init(); - void store_page_once(); - void store_same_page(); - void store_new_page(); - void unref_pages(); - void reallocate_page(); -}; - -void pstore_test_helper::init() -{ - REQUIRE(data != nullptr); - REQUIRE(store.size() == 0); -} - -void pstore_test_helper::store_page_once() -{ - new_content(data, pagesize); - pageno[0] = store.store_page(data); - REQUIRE(store.get_ref(pageno[0]) == 1); - const auto* copy = store.get_page(pageno[0]); - REQUIRE(::memcmp(data, copy, pagesize) == 0); // The page data should be the same - REQUIRE(store.size() == 1); -} - -void pstore_test_helper::store_same_page() -{ - pageno[1] = store.store_page(data); - REQUIRE(pageno[0] == pageno[1]); // Page should be the same - REQUIRE(store.get_ref(pageno[0]) == 2); - REQUIRE(store.size() == 1); -} - -void pstore_test_helper::store_new_page() -{ - new_content(data, pagesize); - pageno[2] = store.store_page(data); - REQUIRE(pageno[0] != pageno[2]); // The new page should be different - REQUIRE(store.size() == 2); -} - -void pstore_test_helper::unref_pages() -{ - store.unref_page(pageno[0]); - REQUIRE(store.get_ref(pageno[0]) == 1); - REQUIRE(store.size() == 2); - - store.unref_page(pageno[1]); - REQUIRE(store.size() == 1); -} - -void pstore_test_helper::reallocate_page() -{ - new_content(data, pagesize); - pageno[3] = store.store_page(data); - REQUIRE(pageno[0] == pageno[3]); // The old page should be reused - REQUIRE(store.get_ref(pageno[3]) == 1); - REQUIRE(store.size() == 2); -} - -void pstore_test_helper::new_content(std::byte* buf, size_t size) -{ - value++; - std::fill_n(buf, size, static_cast(value)); -} - -TEST_CASE("MC page store, used during checkpoint", "MC::PageStore") -{ - pstore_test_helper pstore_test; - pstore_test.init(); - - INFO("Store page once"); - pstore_test.store_page_once(); - - INFO("Store the same page"); - pstore_test.store_same_page(); - - INFO("Store a new page"); - pstore_test.store_new_page(); - - INFO("Unref pages"); - pstore_test.unref_pages(); - - INFO("Reallocate pages"); - pstore_test.reallocate_page(); -} diff --git a/src/mc/sosp/Region.cpp b/src/mc/sosp/Region.cpp deleted file mode 100644 index 2dca797e71..0000000000 --- a/src/mc/sosp/Region.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (c) 2007-2023. 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 "src/mc/sosp/Region.hpp" -#include "src/mc/mc_config.hpp" -#include "src/mc/mc_forward.hpp" -#include "src/mc/sosp/RemoteProcessMemory.hpp" - -#include -#include -#ifdef __FreeBSD__ -#define MAP_POPULATE MAP_PREFAULT_READ -#endif - -namespace simgrid::mc { - -Region::Region(PageStore& store, const RemoteProcessMemory& memory, RegionType region_type, void* start_addr, - size_t size) - : region_type_(region_type), start_addr_(start_addr), size_(size) -{ - xbt_assert((((uintptr_t)start_addr) & (xbt_pagesize - 1)) == 0, "Start address not at the beginning of a page"); - - chunks_ = ChunkedData(store, memory, RemotePtr(start_addr), mmu::chunk_count(size)); -} - -/** @brief Restore a region from a snapshot - * - * @param region Target region - */ -void Region::restore(const RemoteProcessMemory& memory) const -{ - xbt_assert(((start().address()) & (xbt_pagesize - 1)) == 0, "Not at the beginning of a page"); - xbt_assert(simgrid::mc::mmu::chunk_count(size()) == get_chunks().page_count()); - - for (size_t i = 0; i != get_chunks().page_count(); ++i) { - auto* target_page = (void*)simgrid::mc::mmu::join(i, (std::uintptr_t)(void*)start().address()); - const void* source_page = get_chunks().page(i); - memory.write_bytes(source_page, xbt_pagesize, remote(target_page)); - } -} - -static XBT_ALWAYS_INLINE void* mc_translate_address_region(uintptr_t addr, const simgrid::mc::Region* region) -{ - auto [pageno, offset] = simgrid::mc::mmu::split(addr - region->start().address()); - void* snapshot_page = region->get_chunks().page(pageno); - return (char*)snapshot_page + offset; -} - -void* Region::read(void* target, const void* addr, std::size_t size) const -{ - xbt_assert(contain(simgrid::mc::remote(addr)), "Trying to read out of the region boundary."); - - // Last byte of the region: - const void* end_addr = (const char*)addr + size - 1; - if (simgrid::mc::mmu::same_chunk((std::uintptr_t)addr, (std::uintptr_t)end_addr)) { - // The memory is contained in a single page: - return mc_translate_address_region((uintptr_t)addr, this); - } - // Otherwise, the memory spans several pages. Let's copy it all into the provided buffer - xbt_assert(target != nullptr, "Missing destination buffer for fragmented memory access"); - - // TODO, we assume the chunks are aligned to natural chunk boundaries. - // We should remove this assumption. - - // Page of the last byte of the memory area: - size_t page_end = simgrid::mc::mmu::split((std::uintptr_t)end_addr).first; - - void* dest = target; // iterator in the buffer to where we should copy next - - // Read each page: - while (simgrid::mc::mmu::split((std::uintptr_t)addr).first != page_end) { - const void* snapshot_addr = mc_translate_address_region((uintptr_t)addr, this); - auto* next_page = (void*)simgrid::mc::mmu::join(simgrid::mc::mmu::split((std::uintptr_t)addr).first + 1, 0); - size_t readable = (char*)next_page - (const char*)addr; - memcpy(dest, snapshot_addr, readable); - addr = (const char*)addr + readable; - dest = (char*)dest + readable; - size -= readable; - } - - // Read the end: - const void* snapshot_addr = mc_translate_address_region((uintptr_t)addr, this); - memcpy(dest, snapshot_addr, size); - - return target; -} - -} // namespace simgrid::mc - -/** Compare memory between snapshots (with known regions) - * - * @param addr1 Address in the first snapshot - * @param region1 Region of the address in the first snapshot - * @param addr2 Address in the second snapshot - * @param region2 Region of the address in the second snapshot - * @return same semantic as memcmp - */ -int MC_snapshot_region_memcmp(const void* addr1, const simgrid::mc::Region* region1, const void* addr2, - const simgrid::mc::Region* region2, size_t size) -{ - // Using alloca() for large allocations may trigger stack overflow: - // use malloc if the buffer is too big. - bool stack_alloc = size < 64; - void* buffer1a = stack_alloc ? alloca(size) : ::operator new(size); - void* buffer2a = stack_alloc ? alloca(size) : ::operator new(size); - const void* buffer1 = region1->read(buffer1a, addr1, size); - const void* buffer2 = region2->read(buffer2a, addr2, size); - int res; - if (buffer1 == buffer2) - res = 0; - else - res = memcmp(buffer1, buffer2, size); - if (not stack_alloc) { - ::operator delete(buffer1a); - ::operator delete(buffer2a); - } - return res; -} diff --git a/src/mc/sosp/Region.hpp b/src/mc/sosp/Region.hpp deleted file mode 100644 index 7ab26e2de9..0000000000 --- a/src/mc/sosp/Region.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (c) 2007-2023. 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 SIMGRID_MC_SOSP_REGION_HPP -#define SIMGRID_MC_SOSP_REGION_HPP - -#include "src/mc/remote/RemotePtr.hpp" -#include "src/mc/sosp/ChunkedData.hpp" - -#include -#include - -namespace simgrid::mc { - -enum class RegionType { Heap = 1, Data = 2 }; - -/** A copy/snapshot of a given memory region, where identical pages are stored only once */ -class Region { -public: - static const RegionType HeapRegion = RegionType::Heap; - static const RegionType DataRegion = RegionType::Data; - -private: - RegionType region_type_; - simgrid::mc::ObjectInformation* object_info_ = nullptr; - - /** @brief Virtual address of the region in the simulated process */ - void* start_addr_ = nullptr; - - /** @brief Size of the data region in bytes */ - std::size_t size_ = 0; - - ChunkedData chunks_; - -public: - Region(PageStore& store, const RemoteProcessMemory& memory, RegionType type, void* start_addr, size_t size); - Region(Region const&) = delete; - Region& operator=(Region const&) = delete; - Region(Region&& that) = delete; - Region& operator=(Region&& that) = delete; - - // Data - - ChunkedData const& get_chunks() const { return chunks_; } - - simgrid::mc::ObjectInformation* object_info() const { return object_info_; } - void object_info(simgrid::mc::ObjectInformation* info) { object_info_ = info; } - - // Other getters - - RemotePtr start() const { return remote(start_addr_); } - RemotePtr end() const { return remote((char*)start_addr_ + size_); } - std::size_t size() const { return size_; } - RegionType region_type() const { return region_type_; } - - bool contain(RemotePtr p) const { return p >= start() && p < end(); } - - /** @brief Restore a region from a snapshot */ - void restore(const RemoteProcessMemory& memory) const; - - /** @brief Read memory that was snapshotted in this region - * - * @param target Buffer to store contiguously the value if it spans over several pages - * @param addr Process (non-snapshot) address of the data - * @param size Size of the data to read in bytes - * @return Pointer where the data is located (either target buffer or original location) - */ - void* read(void* target, const void* addr, std::size_t size) const; -}; - -} // namespace simgrid::mc - -int MC_snapshot_region_memcmp(const void* addr1, const simgrid::mc::Region* region1, const void* addr2, - const simgrid::mc::Region* region2, std::size_t size); - -static XBT_ALWAYS_INLINE void* MC_region_read_pointer(const simgrid::mc::Region* region, const void* addr) -{ - void* res; - return *(void**)region->read(&res, addr, sizeof(void*)); -} - -#endif diff --git a/src/mc/sosp/RemoteProcessMemory.cpp b/src/mc/sosp/RemoteProcessMemory.cpp deleted file mode 100644 index 1d256c1e82..0000000000 --- a/src/mc/sosp/RemoteProcessMemory.cpp +++ /dev/null @@ -1,469 +0,0 @@ -/* Copyright (c) 2014-2023. 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. */ - -#define _FILE_OFFSET_BITS 64 /* needed for pread_whole to work as expected on 32bits */ - -#include "src/mc/sosp/RemoteProcessMemory.hpp" - -#include "src/mc/explo/Exploration.hpp" -#include "src/mc/explo/LivenessChecker.hpp" -#include "src/mc/sosp/Snapshot.hpp" -#include "xbt/file.hpp" -#include "xbt/log.h" -#include "xbt/system_error.hpp" - -#include -#include -#include // PROT_* - -#include -#include -#include -#include -#include -#include -#include - -XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_process, mc, "MC process information"); - -namespace simgrid::mc { - -// ***** Helper stuff - -static bool is_filtered_lib(std::string_view libname) -{ - return libname != "libsimgrid"; -} - -static std::string get_lib_name(const std::string& pathname) -{ - std::string map_basename = simgrid::xbt::Path(pathname).get_base_name(); - std::string libname; - - if (size_t pos = map_basename.rfind(".so"); pos != std::string::npos) { - // strip the extension (matching regex "\.so.*$") - libname.assign(map_basename, 0, pos); - - // strip the version suffix (matching regex "-[.0-9-]*$") - while (true) { - pos = libname.rfind('-'); - if (pos == std::string::npos || libname.find_first_not_of(".0123456789", pos + 1) != std::string::npos) - break; - libname.erase(pos); - } - } - - return libname; -} - -static ssize_t pread_whole(int fd, void* buf, size_t count, off_t offset) -{ - auto* buffer = static_cast(buf); - ssize_t real_count = count; - while (count) { - ssize_t res = pread(fd, buffer, count, offset); - if (res > 0) { - count -= res; - buffer += res; - offset += res; - } else if (res == 0) - return -1; - else if (errno != EINTR) { - XBT_ERROR("pread_whole: %s", strerror(errno)); - return -1; - } - } - return real_count; -} - -static ssize_t pwrite_whole(int fd, const void* buf, size_t count, off_t offset) -{ - const auto* buffer = static_cast(buf); - ssize_t real_count = count; - while (count) { - ssize_t res = pwrite(fd, buffer, count, offset); - if (res > 0) { - count -= res; - buffer += res; - offset += res; - } else if (res == 0) - return -1; - else if (errno != EINTR) { - XBT_ERROR("pwrite_whole: %s", strerror(errno)); - return -1; - } - } - return real_count; -} - -int open_vm(pid_t pid, int flags) -{ - std::string buffer = "/proc/" + std::to_string(pid) + "/mem"; - return open(buffer.c_str(), flags); -} - -// ***** RemoteProcessMemory - -RemoteProcessMemory::RemoteProcessMemory(pid_t pid, xbt_mheap_t mmalloc_default_mdp) : AddressSpace(this), pid_(pid) -{ - this->heap_address = remote(mmalloc_default_mdp); - - this->memory_map_ = simgrid::xbt::get_memory_map(this->pid_); - this->init_memory_map_info(); - - int fd = open_vm(this->pid_, O_RDWR); - xbt_assert(fd >= 0, "Could not open file for process virtual address space"); - this->memory_file = fd; - - this->unw_addr_space = simgrid::mc::UnwindContext::createUnwindAddressSpace(); - this->unw_underlying_addr_space = simgrid::unw::create_addr_space(); - this->unw_underlying_context = simgrid::unw::create_context(this->unw_underlying_addr_space, this->pid_); - - auto ignored_local_variables = { - std::make_pair("e", "*"), - std::make_pair("_log_ev", "*"), - - /* Ignore local variable about time used for tracing */ - std::make_pair("start_time", "*"), - }; - for (auto const& [var, frame] : ignored_local_variables) - ignore_local_variable(var, frame); - - ignore_global_variable("counter"); // Static variable used for tracing -} - -RemoteProcessMemory::~RemoteProcessMemory() -{ - if (this->memory_file >= 0) - close(this->memory_file); - - if (this->unw_underlying_addr_space != unw_local_addr_space) { - if (this->unw_underlying_addr_space) - unw_destroy_addr_space(this->unw_underlying_addr_space); - if (this->unw_underlying_context) - _UPT_destroy(this->unw_underlying_context); - } - - unw_destroy_addr_space(this->unw_addr_space); -} - -/** Refresh the information about the process - * - * Do not use directly, this is used by the getters when appropriate - * in order to have fresh data. - */ -void RemoteProcessMemory::refresh_heap() -{ - // Read/dereference/refresh the std_heap pointer: - this->read(this->heap.get(), this->heap_address); - this->cache_flags_ |= RemoteProcessMemory::cache_heap; -} - -/** Refresh the information about the process - * - * Do not use directly, this is used by the getters when appropriate - * in order to have fresh data. - * */ -void RemoteProcessMemory::refresh_malloc_info() -{ - // Refresh process->heapinfo: - if (this->cache_flags_ & RemoteProcessMemory::cache_malloc) - return; - size_t count = this->heap->heaplimit + 1; - if (this->heap_info.size() < count) - this->heap_info.resize(count); - this->read_bytes(this->heap_info.data(), count * sizeof(malloc_info), remote(this->heap->heapinfo)); - this->cache_flags_ |= RemoteProcessMemory::cache_malloc; -} -std::size_t RemoteProcessMemory::get_remote_heap_bytes() -{ - return mmalloc_get_bytes_used_remote(get_heap()->heaplimit, get_malloc_info()); -} - -/** @brief Finds the range of the different memory segments and binary paths */ -void RemoteProcessMemory::init_memory_map_info() -{ - XBT_DEBUG("Get debug information ..."); - this->maestro_stack_start_ = nullptr; - this->maestro_stack_end_ = nullptr; - this->object_infos.clear(); - this->binary_info = nullptr; - - std::vector const& maps = this->memory_map_; - - const char* current_name = nullptr; - - for (size_t i = 0; i < maps.size(); i++) { - simgrid::xbt::VmMap const& reg = maps[i]; - const char* pathname = maps[i].pathname.c_str(); - - // Nothing to do - if (maps[i].pathname.empty()) { - current_name = nullptr; - continue; - } - - // [stack], [vvar], [vsyscall], [vdso] ... - if (pathname[0] == '[') { - if ((reg.prot & PROT_WRITE) && not memcmp(pathname, "[stack]", 7)) { - this->maestro_stack_start_ = remote(reg.start_addr); - this->maestro_stack_end_ = remote(reg.end_addr); - } - current_name = nullptr; - continue; - } - - if (current_name && strcmp(current_name, pathname) == 0) - continue; - - current_name = pathname; - if (not(reg.prot & PROT_READ) && (reg.prot & PROT_EXEC)) - continue; - - const bool is_executable = not i; - std::string libname; - if (not is_executable) { - libname = get_lib_name(pathname); - if (is_filtered_lib(libname)) { - continue; - } - } - - std::shared_ptr info = - simgrid::mc::createObjectInformation(this->memory_map_, pathname); - this->object_infos.push_back(info); - if (is_executable) - this->binary_info = info; - } - - xbt_assert(this->maestro_stack_start_, "Did not find maestro_stack_start"); - xbt_assert(this->maestro_stack_end_, "Did not find maestro_stack_end"); - - XBT_DEBUG("Get debug information done !"); -} - -std::shared_ptr RemoteProcessMemory::find_object_info(RemotePtr addr) const -{ - for (auto const& object_info : this->object_infos) - if (addr.address() >= (std::uint64_t)object_info->start && addr.address() <= (std::uint64_t)object_info->end) - return object_info; - return nullptr; -} - -std::shared_ptr RemoteProcessMemory::find_object_info_exec(RemotePtr addr) const -{ - for (std::shared_ptr const& info : this->object_infos) - if (addr.address() >= (std::uint64_t)info->start_exec && addr.address() <= (std::uint64_t)info->end_exec) - return info; - return nullptr; -} - -std::shared_ptr RemoteProcessMemory::find_object_info_rw(RemotePtr addr) const -{ - for (std::shared_ptr const& info : this->object_infos) - if (addr.address() >= (std::uint64_t)info->start_rw && addr.address() <= (std::uint64_t)info->end_rw) - return info; - return nullptr; -} - -simgrid::mc::Frame* RemoteProcessMemory::find_function(RemotePtr ip) const -{ - std::shared_ptr info = this->find_object_info_exec(ip); - return info ? info->find_function((void*)ip.address()) : nullptr; -} - -/** Find (one occurrence of) the named variable definition - */ -const simgrid::mc::Variable* RemoteProcessMemory::find_variable(const char* name) const -{ - // First lookup the variable in the executable shared object. - // A global variable used directly by the executable code from a library - // is reinstantiated in the executable memory .data/.bss. - // We need to look up the variable in the executable first. - if (this->binary_info) { - std::shared_ptr const& info = this->binary_info; - const simgrid::mc::Variable* var = info->find_variable(name); - if (var) - return var; - } - - for (std::shared_ptr const& info : this->object_infos) { - const simgrid::mc::Variable* var = info->find_variable(name); - if (var) - return var; - } - - return nullptr; -} - -void RemoteProcessMemory::read_variable(const char* name, void* target, size_t size) const -{ - const simgrid::mc::Variable* var = this->find_variable(name); - xbt_assert(var, "Variable %s not found", name); - xbt_assert(var->address, "No simple location for this variable"); - - if (not var->type->full_type) // Try to resolve this type. The needed ObjectInfo was maybe (lazily) loaded recently - for (auto const& object_info : this->object_infos) - postProcessObjectInformation(this, object_info.get()); - xbt_assert(var->type->full_type, "Partial type for %s (even after re-resolving types), cannot retrieve its size.", - name); - xbt_assert((size_t)var->type->full_type->byte_size == size, "Unexpected size for %s (expected %zu, received %zu).", - name, size, (size_t)var->type->full_type->byte_size); - this->read_bytes(target, size, remote(var->address)); -} - -std::string RemoteProcessMemory::read_string(RemotePtr address) const -{ - if (not address) - return {}; - - std::vector res(128); - off_t off = 0; - - while (true) { - ssize_t c = pread(this->memory_file, res.data() + off, res.size() - off, (off_t)address.address() + off); - if (c == -1 && errno == EINTR) - continue; - xbt_assert(c > 0, "Could not read string from remote process"); - - if (memchr(res.data() + off, '\0', c)) - return res.data(); - - off += c; - if (off == (off_t)res.size()) - res.resize(res.size() * 2); - } -} - -void* RemoteProcessMemory::read_bytes(void* buffer, std::size_t size, RemotePtr address, - ReadOptions /*options*/) const -{ - xbt_assert(pread_whole(this->memory_file, buffer, size, (size_t)address.address()) != -1, - "Read at %p from process %lli failed", (void*)address.address(), (long long)this->pid_); - return buffer; -} - -/** Write data to a process memory - * - * @param buffer local memory address (source) - * @param len data size - * @param address target process memory address (target) - */ -void RemoteProcessMemory::write_bytes(const void* buffer, size_t len, RemotePtr address) const -{ - xbt_assert(pwrite_whole(this->memory_file, buffer, len, (size_t)address.address()) != -1, - "Write to process %lli failed", (long long)this->pid_); -} - -static void zero_buffer_init(const void** zero_buffer, size_t zero_buffer_size) -{ - int fd = open("/dev/zero", O_RDONLY); - xbt_assert(fd >= 0, "Could not open /dev/zero"); - *zero_buffer = mmap(nullptr, zero_buffer_size, PROT_READ, MAP_SHARED, fd, 0); - xbt_assert(*zero_buffer != MAP_FAILED, "Could not map the zero buffer"); - close(fd); -} - -void RemoteProcessMemory::clear_bytes(RemotePtr address, size_t len) const -{ - static constexpr size_t zero_buffer_size = 10 * 4096; - static const void* zero_buffer; - static std::once_flag zero_buffer_flag; - - std::call_once(zero_buffer_flag, zero_buffer_init, &zero_buffer, zero_buffer_size); - while (len) { - size_t s = len > zero_buffer_size ? zero_buffer_size : len; - this->write_bytes(zero_buffer, s, address); - address = remote((char*)address.address() + s); - len -= s; - } -} - -void RemoteProcessMemory::ignore_region(std::uint64_t addr, std::size_t size) -{ - IgnoredRegion region; - region.addr = addr; - region.size = size; - - auto pos = std::lower_bound(ignored_regions_.begin(), ignored_regions_.end(), region, - [](auto const& reg1, auto const& reg2) { - return reg1.addr < reg2.addr || (reg1.addr == reg2.addr && reg1.size < reg2.size); - }); - if (pos == ignored_regions_.end() || pos->addr != addr || pos->size != size) - ignored_regions_.insert(pos, region); -} - -void RemoteProcessMemory::unignore_region(std::uint64_t addr, std::size_t size) -{ - IgnoredRegion region; - region.addr = addr; - region.size = size; - - auto pos = std::lower_bound(ignored_regions_.begin(), ignored_regions_.end(), region, - [](auto const& reg1, auto const& reg2) { - return reg1.addr < reg2.addr || (reg1.addr == reg2.addr && reg1.size < reg2.size); - }); - if (pos != ignored_regions_.end()) - ignored_regions_.erase(pos); -} - -void RemoteProcessMemory::ignore_heap(IgnoredHeapRegion const& region) -{ - // Binary search the position of insertion: - auto pos = std::lower_bound(ignored_heap_.begin(), ignored_heap_.end(), region.address, - [](auto const& reg, auto const* addr) { return reg.address < addr; }); - if (pos == ignored_heap_.end() || pos->address != region.address) { - // Insert it: - ignored_heap_.insert(pos, region); - } -} - -void RemoteProcessMemory::unignore_heap(void* address, size_t size) -{ - // Binary search: - auto pos = std::lower_bound(ignored_heap_.begin(), ignored_heap_.end(), address, - [](auto const& reg, auto const* addr) { return reg.address < addr; }); - if (pos != ignored_heap_.end() && static_cast(pos->address) <= static_cast(address) + size) - ignored_heap_.erase(pos); -} - -void RemoteProcessMemory::ignore_local_variable(const char* var_name, const char* frame_name) const -{ - if (frame_name != nullptr && strcmp(frame_name, "*") == 0) - frame_name = nullptr; - for (std::shared_ptr const& info : this->object_infos) - info->remove_local_variable(var_name, frame_name); -} - -void RemoteProcessMemory::dump_stack() const -{ - unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, BYTE_ORDER); - if (as == nullptr) { - XBT_ERROR("Could not initialize ptrace address space"); - return; - } - - void* context = _UPT_create(this->pid_); - if (context == nullptr) { - unw_destroy_addr_space(as); - XBT_ERROR("Could not initialize ptrace context"); - return; - } - - unw_cursor_t cursor; - if (unw_init_remote(&cursor, as, context) != 0) { - _UPT_destroy(context); - unw_destroy_addr_space(as); - XBT_ERROR("Could not initialize ptrace cursor"); - return; - } - - simgrid::mc::dumpStack(stderr, &cursor); - - _UPT_destroy(context); - unw_destroy_addr_space(as); -} - -} // namespace simgrid::mc diff --git a/src/mc/sosp/RemoteProcessMemory.hpp b/src/mc/sosp/RemoteProcessMemory.hpp deleted file mode 100644 index 0643a58e4b..0000000000 --- a/src/mc/sosp/RemoteProcessMemory.hpp +++ /dev/null @@ -1,207 +0,0 @@ -/* mc::RemoteClient: representative of the Client memory on the MC side */ - -/* Copyright (c) 2008-2023. 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 SIMGRID_MC_PROCESS_H -#define SIMGRID_MC_PROCESS_H - -#include "src/mc/AddressSpace.hpp" -#include "src/mc/datatypes.h" -#include "src/mc/inspect/ObjectInformation.hpp" -#include "src/mc/remote/RemotePtr.hpp" -#include "src/xbt/memory_map.hpp" -#include "src/xbt/mmalloc/mmprivate.h" - -#include -#include - -namespace simgrid::mc { - -struct IgnoredRegion { - std::uint64_t addr; - std::size_t size; -}; - -struct IgnoredHeapRegion { - int block; - int fragment; - void* address; - std::size_t size; -}; - -/** The Application's process memory, seen from the Checker perspective. This class is not needed if you don't need to - * introspect the application process. - * - * Responsabilities: - * - reading from the process memory (`AddressSpace`); - * - accessing the system state of the process (heap, …); - * - stack unwinding; - * - etc. - */ -class RemoteProcessMemory final : public AddressSpace { -private: - // Those flags are used to track down which cached information - // is still up to date and which information needs to be updated. - static constexpr int cache_none = 0; - static constexpr int cache_heap = 1; - static constexpr int cache_malloc = 2; - -public: - explicit RemoteProcessMemory(pid_t pid, xbt_mheap_t mmalloc_default_mdp); - ~RemoteProcessMemory() override; - - RemoteProcessMemory(RemoteProcessMemory const&) = delete; - RemoteProcessMemory(RemoteProcessMemory&&) = delete; - RemoteProcessMemory& operator=(RemoteProcessMemory const&) = delete; - RemoteProcessMemory& operator=(RemoteProcessMemory&&) = delete; - - /* ************* */ - /* Low-level API */ - /* ************* */ - - // Read memory: - void* read_bytes(void* buffer, std::size_t size, RemotePtr address, - ReadOptions options = ReadOptions::none()) const override; - - void read_variable(const char* name, void* target, size_t size) const; - template void read_variable(const char* name, T* target) const - { - read_variable(name, target, sizeof(*target)); - } - template Remote read_variable(const char* name) const - { - Remote res; - read_variable(name, res.get_buffer(), sizeof(T)); - return res; - } - - std::string read_string(RemotePtr address) const; - using AddressSpace::read_string; - - // Write memory: - void write_bytes(const void* buffer, size_t len, RemotePtr address) const; - void clear_bytes(RemotePtr address, size_t len) const; - - // Debug information: - std::shared_ptr find_object_info(RemotePtr addr) const; - std::shared_ptr find_object_info_exec(RemotePtr addr) const; - std::shared_ptr find_object_info_rw(RemotePtr addr) const; - Frame* find_function(RemotePtr ip) const; - const Variable* find_variable(const char* name) const; - - // Heap access: - xbt_mheap_t get_heap() - { - if (not(cache_flags_ & RemoteProcessMemory::cache_heap)) - refresh_heap(); - return this->heap.get(); - } - const malloc_info* get_malloc_info() - { - if (not(this->cache_flags_ & RemoteProcessMemory::cache_malloc)) - this->refresh_malloc_info(); - return this->heap_info.data(); - } - /* Get the amount of memory mallocated in the remote process (requires mmalloc) */ - std::size_t get_remote_heap_bytes(); - - void clear_cache() { this->cache_flags_ = RemoteProcessMemory::cache_none; } - - std::vector const& ignored_regions() const { return ignored_regions_; } - void ignore_region(std::uint64_t address, std::size_t size); - void unignore_region(std::uint64_t address, std::size_t size); - - bool in_maestro_stack(RemotePtr p) const - { - return p >= this->maestro_stack_start_ && p < this->maestro_stack_end_; - } - - void ignore_global_variable(const char* name) const - { - for (std::shared_ptr const& info : this->object_infos) - info->remove_global_variable(name); - } - - std::vector& stack_areas() { return stack_areas_; } - std::vector const& stack_areas() const { return stack_areas_; } - - std::vector const& ignored_heap() const { return ignored_heap_; } - void ignore_heap(IgnoredHeapRegion const& region); - void unignore_heap(void* address, size_t size); - - void ignore_local_variable(const char* var_name, const char* frame_name) const; - - void dump_stack() const; - -private: - void init_memory_map_info(); - void refresh_heap(); - void refresh_malloc_info(); - - pid_t pid_ = -1; - std::vector memory_map_; - RemotePtr maestro_stack_start_; - RemotePtr maestro_stack_end_; - int memory_file = -1; - std::vector ignored_regions_; - std::vector stack_areas_; - std::vector ignored_heap_; - - /** State of the cache (which variables are up to date) */ - int cache_flags_ = RemoteProcessMemory::cache_none; - -public: - // object info - // TODO, make private (first, objectify simgrid::mc::ObjectInformation*) - std::vector> object_infos; - std::shared_ptr binary_info; - - /** Address of the heap structure in the MCed process. */ - RemotePtr heap_address; - - /** Copy of the heap structure of the process - * - * This is refreshed with the `MC_process_refresh` call. - * This is not used if the process is the current one: - * use `get_heap_info()` in order to use it. - */ - std::unique_ptr heap = std::make_unique(); - - /** Copy of the allocation info structure - * - * This is refreshed with the `MC_process_refresh` call. - * This is not used if the process is the current one: - * use `get_malloc_info()` in order to use it. - */ - std::vector heap_info; - - // Libunwind-data - /** Full-featured MC-aware libunwind address space for the process - * - * This address space is using a simgrid::mc::UnwindContext* - * (with simgrid::mc::Process* / simgrid::mc::AddressSpace* - * and unw_context_t). - */ - unw_addr_space_t unw_addr_space = nullptr; - - /** Underlying libunwind address-space - * - * The `find_proc_info`, `put_unwind_info`, `get_dyn_info_list_addr` - * operations of the native MC address space is currently delegated - * to this address space (either the local or a ptrace unwinder). - */ - unw_addr_space_t unw_underlying_addr_space = nullptr; - - /** The corresponding context - */ - void* unw_underlying_context = nullptr; -}; - -/** Open a FD to a remote process memory (`/dev/$pid/mem`) */ -XBT_PRIVATE int open_vm(pid_t pid, int flags); -} // namespace simgrid::mc - -#endif diff --git a/src/mc/sosp/Snapshot.cpp b/src/mc/sosp/Snapshot.cpp deleted file mode 100644 index ee28945420..0000000000 --- a/src/mc/sosp/Snapshot.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/* Copyright (c) 2014-2023. 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 "src/mc/sosp/Snapshot.hpp" -#include "src/mc/mc_config.hpp" - -#include /* std::size_t */ - -XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_snapshot, mc, "Taking and restoring snapshots"); -namespace simgrid::mc { -/************************************* Take Snapshot ************************************/ -/****************************************************************************************/ - -void Snapshot::snapshot_regions(RemoteProcessMemory& memory) -{ - snapshot_regions_.clear(); - - for (auto const& object_info : memory.object_infos) - add_region(RegionType::Data, memory, object_info.get(), object_info->start_rw, - object_info->end_rw - object_info->start_rw); - - const s_xbt_mheap_t* heap = memory.get_heap(); - void* start_heap = heap->base; - void* end_heap = heap->breakval; - - add_region(RegionType::Heap, memory, nullptr, start_heap, (char*)end_heap - (char*)start_heap); - heap_bytes_used_ = mmalloc_get_bytes_used_remote(heap->heaplimit, memory.get_malloc_info()); -} - -/** @brief Checks whether the variable is in scope for a given IP. - * - * A variable may be defined only from a given value of IP. - * - * @param var Variable description - * @param scope Scope description - * @param ip Instruction pointer - * @return true if the variable is valid - * */ -static bool valid_variable(const simgrid::mc::Variable* var, simgrid::mc::Frame* scope, const void* ip) -{ - // The variable is not yet valid: - if (scope->range.begin() + var->start_scope > (std::uint64_t)ip) - return false; - else - return true; -} - -static void fill_local_variables_values(mc_stack_frame_t stack_frame, Frame* scope, - std::vector& result, AddressSpace* memory) -{ - if (not scope || not scope->range.contain(stack_frame->ip)) - return; - - for (const Variable& current_variable : scope->variables) { - if (not valid_variable(¤t_variable, scope, (void*)stack_frame->ip)) - continue; - - if (not current_variable.type) { - XBT_VERB("Ignore local variable without type: '%s' [%s]", current_variable.name.c_str(), - stack_frame->frame->name.c_str()); - continue; - } - - s_local_variable_t new_var; - new_var.subprogram = stack_frame->frame; - new_var.ip = stack_frame->ip; - new_var.name = current_variable.name; - new_var.type = current_variable.type; - new_var.address = nullptr; - - if (current_variable.address != nullptr) - new_var.address = current_variable.address; - else if (not current_variable.location_list.empty()) { - dwarf::Location location = - simgrid::dwarf::resolve(current_variable.location_list, current_variable.object_info, - &(stack_frame->unw_cursor), (void*)stack_frame->frame_base, memory); - - xbt_assert(location.in_memory(), "Cannot handle non-address variable"); - new_var.address = location.address(); - } else - xbt_die("No address"); - - result.push_back(std::move(new_var)); - } - - // Recursive processing of nested scopes: - for (Frame& nested_scope : scope->scopes) - fill_local_variables_values(stack_frame, &nested_scope, result, memory); -} - -static std::vector get_local_variables_values(std::vector& stack_frames, - AddressSpace* memory) -{ - std::vector variables; - for (s_mc_stack_frame_t& stack_frame : stack_frames) - fill_local_variables_values(&stack_frame, stack_frame.frame, variables, memory); - return variables; -} - -static std::vector unwind_stack_frames(UnwindContext* stack_context, - const RemoteProcessMemory* process_memory) -{ - std::vector result; - - unw_cursor_t c = stack_context->cursor(); - - // TODO, check condition check (unw_init_local==0 means end of frame) - - while (true) { - s_mc_stack_frame_t stack_frame; - - stack_frame.unw_cursor = c; - - unw_word_t ip; - unw_word_t sp; - - unw_get_reg(&c, UNW_REG_IP, &ip); - unw_get_reg(&c, UNW_REG_SP, &sp); - - stack_frame.ip = ip; - stack_frame.sp = sp; - - // TODO, use real addresses in frame_t instead of fixing it here - - Frame* frame = process_memory->find_function(remote(ip)); - stack_frame.frame = frame; - - if (frame) { - stack_frame.frame_name = frame->name; - stack_frame.frame_base = (unw_word_t)frame->frame_base(c); - } else { - stack_frame.frame_base = 0; - stack_frame.frame_name = ""; - } - - result.push_back(std::move(stack_frame)); - - /* Stop before context switch with maestro */ - if (frame != nullptr && frame->name == "smx_ctx_wrapper") - break; - - int ret = unw_step(&c); - xbt_assert(ret >= 0, "Error while unwinding stack"); - xbt_assert(ret != 0, "Unexpected end of stack."); - } - - xbt_assert(not result.empty(), "unw_init_local failed"); - - return result; -} - -void Snapshot::snapshot_stacks(RemoteProcessMemory& process_memory) -{ - for (auto const& stack : process_memory.stack_areas()) { - s_mc_snapshot_stack_t st; - - // Read the context from remote process memory: - unw_context_t context; - process_memory.read_bytes(&context, sizeof(context), remote(stack.context)); - - st.context.initialize(process_memory, &context); - - st.stack_frames = unwind_stack_frames(&st.context, &process_memory); - st.local_variables = get_local_variables_values(st.stack_frames, &process_memory); - - unw_word_t sp = st.stack_frames[0].sp; - - stacks_.push_back(std::move(st)); - - size_t stack_size = (char*)stack.address + stack.size - (char*)sp; - stack_sizes_.push_back(stack_size); - } -} - -void Snapshot::handle_ignore() -{ - xbt_assert(get_remote_process_memory()); - - // Copy the memory: - for (auto const& region : get_remote_process_memory()->ignored_regions()) { - s_mc_snapshot_ignored_data_t ignored_data; - ignored_data.start = (void*)region.addr; - ignored_data.data.resize(region.size); - get_remote_process_memory()->read_bytes(ignored_data.data.data(), region.size, remote(region.addr)); - ignored_data_.push_back(std::move(ignored_data)); - } - - // Zero the memory: - for (auto const& region : get_remote_process_memory()->ignored_regions()) - get_remote_process_memory()->clear_bytes(remote(region.addr), region.size); -} - -void Snapshot::ignore_restore() const -{ - for (auto const& ignored_data : ignored_data_) - get_remote_process_memory()->write_bytes(ignored_data.data.data(), ignored_data.data.size(), - remote(ignored_data.start)); -} - -Snapshot::Snapshot(long num_state, PageStore& store, RemoteProcessMemory& memory) - : AddressSpace(&memory), page_store_(store), num_state_(num_state) -{ - XBT_DEBUG("Taking snapshot %ld", num_state); - - handle_ignore(); - - /* Save the std heap and the writable mapped pages of libsimgrid and binary */ - snapshot_regions(memory); - - to_ignore_ = memory.ignored_heap(); - - if (_sg_mc_max_visited_states > 0 || not _sg_mc_property_file.get().empty()) { - snapshot_stacks(memory); - hash_ = this->do_hash(); - } - - ignore_restore(); -} - -void Snapshot::add_region(RegionType type, const RemoteProcessMemory& memory, ObjectInformation* object_info, - void* start_addr, std::size_t size) -{ - if (type == RegionType::Data) - xbt_assert(object_info, "Missing object info for object."); - else if (type == RegionType::Heap) - xbt_assert(not object_info, "Unexpected object info for heap region."); - - auto region = std::make_unique(page_store_, memory, type, start_addr, size); - region->object_info(object_info); - snapshot_regions_.push_back(std::move(region)); -} - -void* Snapshot::read_bytes(void* buffer, std::size_t size, RemotePtr address, ReadOptions options) const -{ - const Region* region = this->get_region((void*)address.address()); - if (region) { - void* res = region->read(buffer, (void*)address.address(), size); - if (buffer == res || options & ReadOptions::lazy()) - return res; - else { - memcpy(buffer, res, size); - return buffer; - } - } else - return this->get_remote_process_memory()->read_bytes(buffer, size, address, options); -} -/** @brief Find the snapshotted region from a pointer - * - * @param addr Pointer - * */ -Region* Snapshot::get_region(const void* addr) const -{ - size_t n = snapshot_regions_.size(); - for (size_t i = 0; i != n; ++i) { - Region* region = snapshot_regions_[i].get(); - if (not(region && region->contain(simgrid::mc::remote(addr)))) - continue; - - return region; - } - - return nullptr; -} - -/** @brief Find the snapshotted region from a pointer, with a hinted_region */ -Region* Snapshot::get_region(const void* addr, Region* hinted_region) const -{ - if (hinted_region->contain(simgrid::mc::remote(addr))) - return hinted_region; - else - return get_region(addr); -} - -void Snapshot::restore(RemoteProcessMemory& memory) const -{ - XBT_DEBUG("Restore snapshot %ld", num_state_); - - // Restore regions - for (std::unique_ptr const& region : snapshot_regions_) { - region->restore(memory); - } - - ignore_restore(); - memory.clear_cache(); -} - -/* ----------- Hashing logic -------------- */ -class djb_hash { - hash_type state_ = 5381LL; - -public: - template void update(T& x) { state_ = (state_ << 5) + state_ + x; } - hash_type value() const { return state_; } -}; -hash_type Snapshot::do_hash() const -{ - XBT_DEBUG("START hash %ld", num_state_); - djb_hash hash; - // TODO: - // * nb_processes - // * heap_bytes_used - // * root variables - // * basic stack frame information - // * stack frame local variables - XBT_DEBUG("END hash %ld", num_state_); - return hash.value(); -} - -} // namespace simgrid::mc diff --git a/src/mc/sosp/Snapshot.hpp b/src/mc/sosp/Snapshot.hpp deleted file mode 100644 index 0b9fb57b57..0000000000 --- a/src/mc/sosp/Snapshot.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/* Copyright (c) 2007-2023. 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 SIMGRID_MC_SNAPSHOT_HPP -#define SIMGRID_MC_SNAPSHOT_HPP - -#include "src/mc/inspect/mc_unw.hpp" -#include "src/mc/sosp/Region.hpp" -#include "src/mc/sosp/RemoteProcessMemory.hpp" - -// ***** MC Snapshot - -/** Ignored data - * - * Some parts of the snapshot are ignored by zeroing them out: the real values is stored here. - */ -struct s_mc_snapshot_ignored_data_t { - void* start; - std::vector data; -}; - -/** Information about a given stack frame */ -struct s_mc_stack_frame_t { - /** Instruction pointer */ - unw_word_t ip; - /** Stack pointer */ - unw_word_t sp; - unw_word_t frame_base; - simgrid::mc::Frame* frame; - std::string frame_name; - unw_cursor_t unw_cursor; -}; -using mc_stack_frame_t = s_mc_stack_frame_t*; - -struct s_local_variable_t { - simgrid::mc::Frame* subprogram; - unsigned long ip; - std::string name; - simgrid::mc::Type* type; - void* address; -}; -using local_variable_t = s_local_variable_t*; -using const_local_variable_t = const s_local_variable_t*; - -struct XBT_PRIVATE s_mc_snapshot_stack_t { - std::vector local_variables; - simgrid::mc::UnwindContext context; - std::vector stack_frames; -}; -using mc_snapshot_stack_t = s_mc_snapshot_stack_t*; -using const_mc_snapshot_stack_t = const s_mc_snapshot_stack_t*; - -namespace simgrid::mc { - -using hash_type = std::uint64_t; - -class XBT_PRIVATE Snapshot final : public AddressSpace { - PageStore& page_store_; - -public: - /* Initialization */ - Snapshot(long num_state, PageStore& store, RemoteProcessMemory& memory); - - /* Regular use */ - bool on_heap(const void* address) const - { - const s_xbt_mheap_t* heap = get_remote_process_memory()->get_heap(); - return address >= heap->heapbase && address < heap->breakval; - } - - void* read_bytes(void* buffer, std::size_t size, RemotePtr address, - ReadOptions options = ReadOptions::none()) const override; - Region* get_region(const void* addr) const; - Region* get_region(const void* addr, Region* hinted_region) const; - void restore(RemoteProcessMemory& memory) const; - - bool equals_to(const Snapshot& other, RemoteProcessMemory& memory); - - // To be private - long num_state_; - std::size_t heap_bytes_used_ = 0; - std::vector> snapshot_regions_; - std::vector stack_sizes_; - std::vector stacks_; - std::vector to_ignore_; - std::uint64_t hash_ = 0; - std::vector ignored_data_; - -private: - void add_region(RegionType type, const RemoteProcessMemory& memory, ObjectInformation* object_info, void* start_addr, - std::size_t size); - void snapshot_regions(RemoteProcessMemory& memory); - void snapshot_stacks(RemoteProcessMemory& memory); - void handle_ignore(); - void ignore_restore() const; - hash_type do_hash() const; -}; -} // namespace simgrid::mc - -#endif diff --git a/src/mc/sosp/Snapshot_test.cpp b/src/mc/sosp/Snapshot_test.cpp deleted file mode 100644 index abf1dd03da..0000000000 --- a/src/mc/sosp/Snapshot_test.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* Copyright (c) 2014-2023. 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 "src/3rd-party/catch.hpp" -#include "src/mc/mc_config.hpp" -#include "src/mc/sosp/Snapshot.hpp" - -#include -#include -#include -#include - -class snap_test_helper { - simgrid::mc::PageStore page_store_{500}; - simgrid::mc::RemoteProcessMemory memory_{getpid(), nullptr}; - - struct prologue_return { - size_t size; - std::byte* src; - std::byte* dstn; - std::unique_ptr region0; - std::unique_ptr region; - }; - prologue_return prologue(int n); // common to the below 5 fxs - - static void init_memory(std::byte* mem, size_t size); - -public: - void read_whole_region(); - void read_region_parts(); - void compare_whole_region(); - void compare_region_parts(); - void read_pointer(); - - static void basic_requirements(); -}; - -void snap_test_helper::init_memory(std::byte* mem, size_t size) -{ - std::generate_n(mem, size, []() { return static_cast(simgrid::xbt::random::uniform_int(0, 0xff)); }); -} - -void snap_test_helper::basic_requirements() -{ - REQUIRE(xbt_pagesize == getpagesize()); - REQUIRE(1 << xbt_pagebits == xbt_pagesize); -} - -snap_test_helper::prologue_return snap_test_helper::prologue(int n) -{ - // Store region page(s): - size_t byte_size = n * xbt_pagesize; - auto* source = - static_cast(mmap(nullptr, byte_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); - INFO("Could not allocate source memory"); - REQUIRE(source != MAP_FAILED); - - // Init memory and take snapshots: - init_memory(source, byte_size); - auto region0 = - std::make_unique(page_store_, memory_, simgrid::mc::RegionType::Data, source, byte_size); - for (int i = 0; i < n; i += 2) { - init_memory(source + i * xbt_pagesize, xbt_pagesize); - } - auto region = - std::make_unique(page_store_, memory_, simgrid::mc::RegionType::Data, source, byte_size); - - auto* destination = - static_cast(mmap(nullptr, byte_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); - INFO("Could not allocate destination memory"); - REQUIRE(destination != MAP_FAILED); - - return {.size = byte_size, - .src = source, - .dstn = destination, - .region0 = std::move(region0), - .region = std::move(region)}; -} - -void snap_test_helper::read_whole_region() -{ - for (int n = 1; n != 32; ++n) { - prologue_return ret = prologue(n); - const void* read = ret.region->read(ret.dstn, ret.src, ret.size); - INFO("Mismatch in MC_region_read()"); - REQUIRE(not memcmp(ret.src, read, ret.size)); - - munmap(ret.dstn, ret.size); - munmap(ret.src, ret.size); - } -} - -void snap_test_helper::read_region_parts() -{ - for (int n = 1; n != 32; ++n) { - prologue_return ret = prologue(n); - - for (int j = 0; j != 100; ++j) { - size_t offset = simgrid::xbt::random::uniform_int(0, ret.size - 1); - size_t size = simgrid::xbt::random::uniform_int(0, ret.size - offset - 1); - const void* read = ret.region->read(ret.dstn, (const char*)ret.src + offset, size); - INFO("Mismatch in MC_region_read()"); - REQUIRE(not memcmp((char*)ret.src + offset, read, size)); - } - munmap(ret.dstn, ret.size); - munmap(ret.src, ret.size); - } -} - -void snap_test_helper::compare_whole_region() -{ - for (int n = 1; n != 32; ++n) { - prologue_return ret = prologue(n); - - INFO("Unexpected match in MC_snapshot_region_memcmp() with previous snapshot"); - REQUIRE(MC_snapshot_region_memcmp(ret.src, ret.region0.get(), ret.src, ret.region.get(), ret.size)); - - munmap(ret.dstn, ret.size); - munmap(ret.src, ret.size); - } -} - -void snap_test_helper::compare_region_parts() -{ - for (int n = 1; n != 32; ++n) { - prologue_return ret = prologue(n); - - for (int j = 0; j != 100; ++j) { - size_t offset = simgrid::xbt::random::uniform_int(0, ret.size - 1); - size_t size = simgrid::xbt::random::uniform_int(0, ret.size - offset - 1); - - INFO("Mismatch in MC_snapshot_region_memcmp()"); - REQUIRE(not MC_snapshot_region_memcmp((char*)ret.src + offset, ret.region.get(), (char*)ret.src + offset, - ret.region.get(), size)); - } - munmap(ret.dstn, ret.size); - munmap(ret.src, ret.size); - } -} - -const int some_global_variable = 42; -const void* const some_global_pointer = &some_global_variable; -void snap_test_helper::read_pointer() -{ - prologue_return ret = prologue(1); - memcpy(ret.src, &some_global_pointer, sizeof(void*)); - const simgrid::mc::Region region2(page_store_, memory_, simgrid::mc::RegionType::Data, ret.src, ret.size); - INFO("Mismtach in MC_region_read_pointer()"); - REQUIRE(MC_region_read_pointer(®ion2, ret.src) == some_global_pointer); - - munmap(ret.dstn, ret.size); - munmap(ret.src, ret.size); -} - -/*************** End: class snap_test_helper *****************************/ - -TEST_CASE("MC::Snapshot: A copy/snapshot of a given memory region", "MC::Snapshot") -{ - INFO("Sparse snapshot (using pages)"); - - snap_test_helper::basic_requirements(); - - snap_test_helper snap_test; - - INFO("Read whole region"); - snap_test.read_whole_region(); - - INFO("Read region parts"); - snap_test.read_region_parts(); - - INFO("Compare whole region"); - snap_test.compare_whole_region(); - - INFO("Compare region parts"); - snap_test.compare_region_parts(); - - INFO("Read pointer"); - snap_test.read_pointer(); -} diff --git a/src/mc/transition/Transition.cpp b/src/mc/transition/Transition.cpp index 84ad991fd5..fc3a5e2309 100644 --- a/src/mc/transition/Transition.cpp +++ b/src/mc/transition/Transition.cpp @@ -11,7 +11,7 @@ #if SIMGRID_HAVE_MC #include "src/mc/explo/Exploration.hpp" -#include "src/mc/transition/TransitionActorJoin.hpp" +#include "src/mc/transition/TransitionActor.hpp" #include "src/mc/transition/TransitionAny.hpp" #include "src/mc/transition/TransitionComm.hpp" #include "src/mc/transition/TransitionObjectAccess.hpp" @@ -95,6 +95,8 @@ Transition* deserialize_transition(aid_t issuer, int times_considered, std::stri case Transition::Type::ACTOR_JOIN: return new ActorJoinTransition(issuer, times_considered, stream); + case Transition::Type::ACTOR_SLEEP: + return new ActorSleepTransition(issuer, times_considered, stream); case Transition::Type::OBJECT_ACCESS: return new ObjectAccessTransition(issuer, times_considered, stream); diff --git a/src/mc/transition/Transition.hpp b/src/mc/transition/Transition.hpp index 4bdf7d262b..9a840246c4 100644 --- a/src/mc/transition/Transition.hpp +++ b/src/mc/transition/Transition.hpp @@ -31,14 +31,23 @@ class Transition { public: /* Ordering is important here. depends() implementations only consider subsequent types in this ordering */ - XBT_DECLARE_ENUM_CLASS(Type, RANDOM, ACTOR_JOIN, /* First because indep with anybody including themselves */ - OBJECT_ACCESS, /* high priority because indep with almost everybody */ - TESTANY, WAITANY, /* high priority because they can rewrite themselves to *_WAIT */ - BARRIER_ASYNC_LOCK, BARRIER_WAIT, /* BARRIER transitions sorted alphabetically */ - COMM_ASYNC_RECV, COMM_ASYNC_SEND, COMM_TEST, COMM_WAIT, /* Alphabetical ordering of COMM_* */ - MUTEX_ASYNC_LOCK, MUTEX_TEST, MUTEX_TRYLOCK, MUTEX_UNLOCK, MUTEX_WAIT, /* alphabetical */ - SEM_ASYNC_LOCK, SEM_UNLOCK, SEM_WAIT, /* alphabetical ordering of SEM transitions */ - /* UNKNOWN must be last */ UNKNOWN); + XBT_DECLARE_ENUM_CLASS(Type, + /* First because indep with anybody including themselves */ + RANDOM, ACTOR_JOIN, ACTOR_SLEEP, + /* high priority because indep with almost everybody */ + OBJECT_ACCESS, + /* high priority because they can rewrite themselves to *_WAIT */ + TESTANY, WAITANY, + /* BARRIER transitions sorted alphabetically */ + BARRIER_ASYNC_LOCK, BARRIER_WAIT, + /* Alphabetical ordering of COMM_* */ + COMM_ASYNC_RECV, COMM_ASYNC_SEND, COMM_TEST, COMM_WAIT, + /* alphabetical */ + MUTEX_ASYNC_LOCK, MUTEX_TEST, MUTEX_TRYLOCK, MUTEX_UNLOCK, MUTEX_WAIT, + /* alphabetical ordering of SEM transitions */ + SEM_ASYNC_LOCK, SEM_UNLOCK, SEM_WAIT, + /* UNKNOWN must be last */ + UNKNOWN); Type type_ = Type::UNKNOWN; aid_t aid_ = 0; diff --git a/src/mc/transition/TransitionActorJoin.cpp b/src/mc/transition/TransitionActor.cpp similarity index 68% rename from src/mc/transition/TransitionActorJoin.cpp rename to src/mc/transition/TransitionActor.cpp index 463bfcbc6a..70608f14da 100644 --- a/src/mc/transition/TransitionActorJoin.cpp +++ b/src/mc/transition/TransitionActor.cpp @@ -3,7 +3,7 @@ /* 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 "src/mc/transition/TransitionActorJoin.hpp" +#include "src/mc/transition/TransitionActor.hpp" #include "simgrid/config.h" #include "xbt/asserts.h" #include "xbt/string.hpp" @@ -27,6 +27,10 @@ std::string ActorJoinTransition::to_string(bool verbose) const } bool ActorJoinTransition::depends(const Transition* other) const { + // Actions executed by the same actor are always dependent + if (other->aid_ == aid_) + return true; + // Joining is dependent with any transition whose // actor is that of the `other` action. , Join i if (other->aid_ == target_) { @@ -43,4 +47,23 @@ bool ActorJoinTransition::depends(const Transition* other) const return false; } +ActorSleepTransition::ActorSleepTransition(aid_t issuer, int times_considered, std::stringstream& stream) + : Transition(Type::ACTOR_SLEEP, issuer, times_considered) +{ + XBT_DEBUG("ActorSleepTransition()"); +} +std::string ActorSleepTransition::to_string(bool verbose) const +{ + return xbt::string_printf("ActorSleep()"); +} +bool ActorSleepTransition::depends(const Transition* other) const +{ + // Actions executed by the same actor are always dependent + if (other->aid_ == aid_) + return true; + + // Sleeping is indep with any other transitions: always enabled, not impacted by any transition + return false; +} + } // namespace simgrid::mc diff --git a/src/mc/transition/TransitionActorJoin.hpp b/src/mc/transition/TransitionActor.hpp similarity index 71% rename from src/mc/transition/TransitionActorJoin.hpp rename to src/mc/transition/TransitionActor.hpp index 78bc7659e5..34df4417eb 100644 --- a/src/mc/transition/TransitionActorJoin.hpp +++ b/src/mc/transition/TransitionActor.hpp @@ -3,8 +3,8 @@ /* 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 SIMGRID_MC_TRANSITION_ACTOR_JOIN_HPP -#define SIMGRID_MC_TRANSITION_ACTOR_JOIN_HPP +#ifndef SIMGRID_MC_TRANSITION_ACTOR_HPP +#define SIMGRID_MC_TRANSITION_ACTOR_HPP #include "src/kernel/actor/SimcallObserver.hpp" #include "src/mc/transition/Transition.hpp" @@ -29,6 +29,14 @@ public: aid_t get_target() const { return target_; } }; +class ActorSleepTransition : public Transition { + +public: + ActorSleepTransition(aid_t issuer, int times_considered, std::stringstream& stream); + std::string to_string(bool verbose) const override; + bool depends(const Transition* other) const override; +}; + } // namespace simgrid::mc #endif diff --git a/src/mc/transition/TransitionSynchro.cpp b/src/mc/transition/TransitionSynchro.cpp index 21ea4ec8af..bd5788665a 100644 --- a/src/mc/transition/TransitionSynchro.cpp +++ b/src/mc/transition/TransitionSynchro.cpp @@ -32,7 +32,7 @@ bool BarrierTransition::depends(const Transition* o) const // Actions executed by the same actor are always dependent if (o->aid_ == aid_) return true; - + if (const auto* other = dynamic_cast(o)) { if (bar_ != other->bar_) return false; @@ -128,7 +128,11 @@ bool SemaphoreTransition::depends(const Transition* o) const // Actions executed by the same actor are always dependent if (o->aid_ == aid_) return true; +<<<<<<< HEAD +======= + +>>>>>>> dfafe652e9ae62c35cd0fc084b117fc987b3e8dc if (const auto* other = dynamic_cast(o)) { if (sem_ != other->sem_) return false; diff --git a/src/plugins/battery.cpp b/src/plugins/battery.cpp index 412b69ed0f..9639bf67e5 100644 --- a/src/plugins/battery.cpp +++ b/src/plugins/battery.cpp @@ -6,10 +6,7 @@ #include #include #include -#include #include -#include -#include #include "src/kernel/resource/CpuImpl.hpp" #include "src/simgrid/module.hpp" @@ -84,6 +81,12 @@ You can schedule handlers that will happen at specific SoC of the battery and tr Theses handlers may be recurrent, for instance you may want to always set all loads to zero and deactivate all hosts connections when the battery reaches 20% SoC. +Connector +......... + +A Battery can act as a connector to connect Solar Panels direcly to loads. Such Battery is created without any +parameter, cannot store energy and has a transfer efficiency of 100%. + @endrst */ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(Battery, kernel, "Logging specific to the battery plugin"); @@ -107,6 +110,11 @@ void BatteryModel::update_actions_state(double now, double delta) double BatteryModel::next_occurring_event(double now) { + static bool init = false; + if (!init) { + init = true; + return 0; + } double time_delta = -1; for (auto battery : batteries_) { double time_delta_battery = battery->next_occurring_handler(); @@ -154,12 +162,15 @@ void Battery::update() double consumed_power_w = 0; for (auto const& [host, active] : host_loads_) provided_power_w += active ? sg_host_get_current_consumption(host) : 0; - for (auto const& [name, load] : named_loads_) { - if (load > 0) - provided_power_w += load; + for (auto const& [name, pair] : named_loads_) { + if (not pair.first) + continue; + if (pair.second > 0) + provided_power_w += pair.second; else - consumed_power_w += -load; + consumed_power_w += -pair.second; } + provided_power_w = std::min(provided_power_w, nominal_discharge_power_w_ * discharge_efficiency_); consumed_power_w = std::min(consumed_power_w, -nominal_charge_power_w_); @@ -182,6 +193,14 @@ void Battery::update() // Updating battery energy_provided_j_ += energy_lost_delta_j * discharge_efficiency_; energy_consumed_j_ += energy_gained_delta_j / charge_efficiency_; + + // This battery is a simple connector, we only update energy provided and consumed + if (energy_budget_j_ == 0) { + energy_consumed_j_ = energy_provided_j_; + last_updated_ = now; + return; + } + capacity_wh_ = initial_capacity_wh_ * (1 - (energy_provided_j_ / discharge_efficiency_ + energy_consumed_j_ * charge_efficiency_) / energy_budget_j_); @@ -210,11 +229,13 @@ double Battery::next_occurring_handler() double consumed_power_w = 0; for (auto const& [host, active] : host_loads_) provided_power_w += active ? sg_host_get_current_consumption(host) : 0; - for (auto const& [name, load] : named_loads_) { - if (load > 0) - provided_power_w += load; + for (auto const& [name, pair] : named_loads_) { + if (not pair.first) + continue; + if (pair.second > 0) + provided_power_w += pair.second; else - consumed_power_w += -load; + consumed_power_w += -pair.second; } provided_power_w = std::min(provided_power_w, nominal_discharge_power_w_ * discharge_efficiency_); @@ -224,10 +245,11 @@ double Battery::next_occurring_handler() for (auto& handler : handlers_) { double lost_power_w = provided_power_w / discharge_efficiency_; double gained_power_w = consumed_power_w * charge_efficiency_; - // Handler cannot happen - if ((lost_power_w == gained_power_w) or (handler->state_of_charge_ == energy_stored_j_ / (3600 * capacity_wh_)) or - (lost_power_w > gained_power_w and handler->flow_ == Flow::CHARGE) or - (lost_power_w < gained_power_w and handler->flow_ == Flow::DISCHARGE)) { + if ((lost_power_w == gained_power_w) or (handler->state_of_charge_ == get_state_of_charge()) or + (lost_power_w > gained_power_w and + (handler->flow_ == Flow::CHARGE or handler->state_of_charge_ > get_state_of_charge())) or + (lost_power_w < gained_power_w and + (handler->flow_ == Flow::DISCHARGE or handler->state_of_charge_ < get_state_of_charge()))) { continue; } // Evaluate time until handler happen @@ -250,6 +272,8 @@ double Battery::next_occurring_handler() return time_delta; } +Battery::Battery() {} + Battery::Battery(const std::string& name, double state_of_charge, double nominal_charge_power_w, double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency, double initial_capacity_wh, int cycles) @@ -263,7 +287,7 @@ Battery::Battery(const std::string& name, double state_of_charge, double nominal , capacity_wh_(initial_capacity_wh) , energy_stored_j_(state_of_charge * 3600 * initial_capacity_wh) { - xbt_assert(nominal_charge_power_w <= 0, " : nominal charge power must be non-negative (provided: %f)", + xbt_assert(nominal_charge_power_w <= 0, " : nominal charge power must be <= 0 (provided: %f)", nominal_charge_power_w); xbt_assert(nominal_discharge_power_w >= 0, " : nominal discharge power must be non-negative (provided: %f)", nominal_discharge_power_w); @@ -277,11 +301,29 @@ Battery::Battery(const std::string& name, double state_of_charge, double nominal xbt_assert(cycles > 0, " : cycles should be > 0 (provided: %d)", cycles); } +/** @ingroup plugin_battery + * @brief Init a Battery with this constructor makes it only usable as a connector. + * A connector has no capacity and only delivers as much power as it receives + with a transfer efficiency of 100%. + * @return A BatteryPtr pointing to the new Battery. + */ +BatteryPtr Battery::init() +{ + static bool plugin_inited = false; + if (not plugin_inited) { + init_plugin(); + plugin_inited = true; + } + auto battery = BatteryPtr(new Battery()); + battery_model_->add_battery(battery); + return battery; +} + /** @ingroup plugin_battery * @param name The name of the Battery. * @param state_of_charge The initial state of charge of the Battery [0,1]. - * @param nominal_charge_power_w The maximum power delivered by the Battery in W (<= 0). - * @param nominal_discharge_power_w The maximum power absorbed by the Battery in W (>= 0). + * @param nominal_charge_power_w The maximum power absorbed by the Battery in W (<= 0). + * @param nominal_discharge_power_w The maximum power delivered by the Battery in W (>= 0). * @param charge_efficiency The charge efficiency of the Battery [0,1]. * @param discharge_efficiency The discharge efficiency of the Battery [0,1]. * @param initial_capacity_wh The initial capacity of the Battery in Wh (>0). @@ -309,7 +351,21 @@ BatteryPtr Battery::init(const std::string& name, double state_of_charge, double */ void Battery::set_load(const std::string& name, double power_w) { - named_loads_[name] = power_w; + kernel::actor::simcall_answered([this, &name, &power_w] { + if (named_loads_.find(name) == named_loads_.end()) + named_loads_[name] = std::make_pair(true, power_w); + else + named_loads_[name].second = power_w; + }); +} + +/** @ingroup plugin_battery + * @param name The name of the load + * @param active Status of the load. If false then the load is ignored by the Battery. + */ +void Battery::set_load(const std::string& name, bool active) +{ + kernel::actor::simcall_answered([this, &name, &active] { named_loads_[name].first = active; }); } /** @ingroup plugin_battery @@ -322,7 +378,7 @@ void Battery::set_load(const std::string& name, double power_w) */ void Battery::connect_host(s4u::Host* host, bool active) { - host_loads_[host] = active; + kernel::actor::simcall_answered([this, &host, &active] { host_loads_[host] = active; }); } /** @ingroup plugin_battery diff --git a/src/plugins/chiller.cpp b/src/plugins/chiller.cpp index 501f155865..3cec29d560 100644 --- a/src/plugins/chiller.cpp +++ b/src/plugins/chiller.cpp @@ -34,7 +34,7 @@ from the heat of the other devices, such as lighing, accounted using a factor :m Q_{room} = (1 + \alpha) \times Q_{machines} -This energy heats the input temperature :math:`T_{in}` and gives an output temperature :math:`T_{out}` based on the the +This energy heats the input temperature :math:`T_{in}` and gives an output temperature :math:`T_{out}` based on the mass of air inside the room :math:`m_{air}` and its specific heat :math:`C_{p}`: .. math:: @@ -75,7 +75,12 @@ void ChillerModel::update_actions_state(double now, double delta) double ChillerModel::next_occurring_event(double now) { - return -1; + static bool init = false; + if (not init) { + init = true; + return 0; + } else + return -1; } /* Chiller */ @@ -99,30 +104,20 @@ void Chiller::update() return; double hosts_power_w = 0; - for (auto const& host : hosts_) + for (auto const& host : hosts_) { hosts_power_w += sg_host_get_current_consumption(host); - double heat_generated_j = hosts_power_w * (1 + alpha_) * time_delta_s; - temp_out_c_ = temp_in_c_ + heat_generated_j / (air_mass_kg_ * specific_heat_j_per_kg_per_c_); - double delta_temp_c = temp_out_c_ - goal_temp_c_; - - if (not active_ or delta_temp_c < 0) { - temp_in_c_ = temp_out_c_; - power_w_ = 0; - last_updated_ = now; - return; - } - - double cooling_demand_w = delta_temp_c * air_mass_kg_ * specific_heat_j_per_kg_per_c_ / time_delta_s; - if (cooling_demand_w / cooling_efficiency_ <= max_power_w_) { - power_w_ = cooling_demand_w / cooling_efficiency_; - temp_in_c_ = temp_out_c_ - - (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_); - } else { - power_w_ = max_power_w_; - temp_in_c_ = temp_out_c_ - - (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_); } + double heat_generated_j = hosts_power_w * (1 + alpha_) * time_delta_s; + temp_out_c_ = temp_in_c_ + heat_generated_j / (air_mass_kg_ * specific_heat_j_per_kg_per_c_); + double cooling_demand_w = + std::max(temp_out_c_ - goal_temp_c_, 0.0) * air_mass_kg_ * specific_heat_j_per_kg_per_c_ / time_delta_s; + if (not active_) + power_w_ = 0; + else + power_w_ = std::min(max_power_w_, cooling_demand_w / cooling_efficiency_); + temp_in_c_ = + temp_out_c_ - (power_w_ * time_delta_s * cooling_efficiency_) / (air_mass_kg_ * specific_heat_j_per_kg_per_c_); energy_consumed_j_ += power_w_ * time_delta_s; last_updated_ = now; }); @@ -284,4 +279,26 @@ ChillerPtr Chiller::remove_host(s4u::Host* host) return this; } +/** @ingroup plugin_chiller + * @return The time to reach to goal temp, assuming that the system remain in the same state. + */ +double Chiller::get_time_to_goal_temp() +{ + if (goal_temp_c_ == temp_in_c_) + return 0; + + double heat_power_w = 0; + for (auto const& host : hosts_) + heat_power_w += sg_host_get_current_consumption(host); + heat_power_w = heat_power_w * (1 + alpha_); + + if (temp_in_c_ < goal_temp_c_) + return air_mass_kg_ * (goal_temp_c_ - temp_in_c_) * specific_heat_j_per_kg_per_c_ / heat_power_w; + + if (not active_) + return -1; + else + return air_mass_kg_ * (temp_in_c_ - goal_temp_c_) * specific_heat_j_per_kg_per_c_ / + (power_w_ * cooling_efficiency_ - heat_power_w); +} } // namespace simgrid::plugins diff --git a/src/plugins/solar_panel.cpp b/src/plugins/solar_panel.cpp index 8e44734b82..c6f2581f80 100644 --- a/src/plugins/solar_panel.cpp +++ b/src/plugins/solar_panel.cpp @@ -43,50 +43,24 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(SolarPanel, kernel, "Logging specific to the sol namespace simgrid::plugins { -/* SolarPanelModel */ - -SolarPanelModel::SolarPanelModel() : Model("SolarPanelModel") {} - -void SolarPanelModel::add_solar_panel(SolarPanelPtr b) -{ - solar_panels_.push_back(b); -} - -void SolarPanelModel::update_actions_state(double now, double delta) -{ - for (auto solar_panel : solar_panels_) - solar_panel->update(); -} - -double SolarPanelModel::next_occurring_event(double now) -{ - return -1; -} +xbt::signal SolarPanel::on_power_change; /* SolarPanel */ -std::shared_ptr SolarPanel::solar_panel_model_; - -void SolarPanel::init_plugin() -{ - auto model = std::make_shared(); - simgrid::s4u::Engine::get_instance()->add_model(model); - SolarPanel::solar_panel_model_ = model; -} - void SolarPanel::update() { simgrid::kernel::actor::simcall_answered([this] { - double now = simgrid::s4u::Engine::get_clock(); - if (now <= last_updated_) - return; double power_w = conversion_efficiency_ * area_m2_ * solar_irradiance_w_per_m2_; - if (power_w_ < min_power_w_) + if (power_w < min_power_w_) power_w = 0; - if (power_w_ > max_power_w_) + if (power_w > max_power_w_) power_w = max_power_w_; - power_w_ = power_w; - last_updated_ = now; + auto previous_power_w = power_w_; + power_w_ = power_w; + if (previous_power_w != power_w_) { + on_this_power_change(this); + on_power_change(this); + } }); } @@ -122,14 +96,9 @@ SolarPanel::SolarPanel(std::string name, double area_m2, double conversion_effic SolarPanelPtr SolarPanel::init(const std::string& name, double area_m2, double conversion_efficiency, double solar_irradiance_w_per_m2, double min_power_w, double max_power_w) { - static bool plugin_inited = false; - if (not plugin_inited) { - init_plugin(); - plugin_inited = true; - } auto solar_panel = SolarPanelPtr( new SolarPanel(name, area_m2, conversion_efficiency, solar_irradiance_w_per_m2, min_power_w, max_power_w)); - solar_panel_model_->add_solar_panel(solar_panel); + solar_panel->update(); return solar_panel; } @@ -151,6 +120,7 @@ SolarPanelPtr SolarPanel::set_area(double area_m2) { xbt_assert(area_m2 >= 0, " : area must be > 0 (provided: %f)", area_m2); kernel::actor::simcall_answered([this, area_m2] { area_m2_ = area_m2; }); + update(); return this; } @@ -162,6 +132,7 @@ SolarPanelPtr SolarPanel::set_conversion_efficiency(double e) { xbt_assert(e >= 0 and e <= 1, " : conversion efficiency must be in [0,1] (provided: %f)", e); kernel::actor::simcall_answered([this, e] { conversion_efficiency_ = e; }); + update(); return this; } @@ -175,6 +146,7 @@ SolarPanelPtr SolarPanel::set_solar_irradiance(double solar_irradiance_w_per_m2) solar_irradiance_w_per_m2); kernel::actor::simcall_answered( [this, solar_irradiance_w_per_m2] { solar_irradiance_w_per_m2_ = solar_irradiance_w_per_m2; }); + update(); return this; } @@ -188,6 +160,7 @@ SolarPanelPtr SolarPanel::set_min_power(double power_w) xbt_assert(max_power_w_ > power_w, " : maximal power must be above minimal power (provided: %f, max: %f)", power_w, max_power_w_); kernel::actor::simcall_answered([this, power_w] { min_power_w_ = power_w; }); + update(); return this; } @@ -201,6 +174,7 @@ SolarPanelPtr SolarPanel::set_max_power(double power_w) xbt_assert(min_power_w_ < power_w, " : maximal power must be above minimal power (provided: %f, min: %f)", power_w, min_power_w_); kernel::actor::simcall_answered([this, power_w] { max_power_w_ = power_w; }); + update(); return this; } diff --git a/src/s4u/s4u_Activity.cpp b/src/s4u/s4u_Activity.cpp index 445364f6cb..091b2a12cb 100644 --- a/src/s4u/s4u_Activity.cpp +++ b/src/s4u/s4u_Activity.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "src/kernel/activity/ActivityImpl.hpp" @@ -52,6 +53,8 @@ Activity* Activity::wait_for(double timeout) if (state_ == State::FAILED) { if (dynamic_cast(this)) throw NetworkFailureException(XBT_THROW_POINT, "Cannot wait for a failed comm"); + if (dynamic_cast(this)) + throw NetworkFailureException(XBT_THROW_POINT, "Cannot wait for a failed mess"); if (dynamic_cast(this)) throw HostFailureException(XBT_THROW_POINT, "Cannot wait for a failed exec"); if (dynamic_cast(this)) diff --git a/src/s4u/s4u_Actor.cpp b/src/s4u/s4u_Actor.cpp index e60f73d5fa..573d708555 100644 --- a/src/s4u/s4u_Actor.cpp +++ b/src/s4u/s4u_Actor.cpp @@ -328,18 +328,22 @@ void sleep_for(double duration) } kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self(); + kernel::actor::ActorSleepSimcall observer(issuer); + Actor::on_sleep(*issuer->get_ciface()); issuer->get_ciface()->on_this_sleep(*issuer->get_ciface()); - kernel::actor::simcall_blocking([issuer, duration]() { - if (MC_is_active() || MC_record_replay_is_active()) { - MC_process_clock_add(issuer, duration); - issuer->simcall_answer(); - return; - } - kernel::activity::ActivityImplPtr sync = issuer->sleep(duration); - sync->register_simcall(&issuer->simcall_); - }); + kernel::actor::simcall_blocking( + [issuer, duration]() { + if (MC_is_active() || MC_record_replay_is_active()) { + // MC_process_clock_add(issuer, duration); // BUG: Makes the exploration loop + issuer->simcall_answer(); + } else { + kernel::activity::ActivityImplPtr sync = issuer->sleep(duration); + sync->register_simcall(&issuer->simcall_); + } + }, + &observer); Actor::on_wake_up(*issuer->get_ciface()); issuer->get_ciface()->on_this_wake_up(*issuer->get_ciface()); diff --git a/src/s4u/s4u_Engine.cpp b/src/s4u/s4u_Engine.cpp index dc7e77f5ed..094e8311d1 100644 --- a/src/s4u/s4u_Engine.cpp +++ b/src/s4u/s4u_Engine.cpp @@ -400,6 +400,20 @@ Mailbox* Engine::mailbox_by_name_or_create(const std::string& name) const return mbox->get_iface(); } +MessageQueue* Engine::message_queue_by_name_or_create(const std::string& name) const +{ + /* two actors may have pushed the same mbox_create simcall at the same time */ + kernel::activity::MessageQueueImpl* queue = kernel::actor::simcall_answered([&name, this] { + auto [m, inserted] = pimpl_->mqueues_.try_emplace(name, nullptr); + if (inserted) { + m->second = new kernel::activity::MessageQueueImpl(name); + XBT_DEBUG("Creating a message queue at %p with name %s", m->second, name.c_str()); + } + return m->second; + }); + return queue->get_iface(); +} + /** @brief Returns the amount of links in the platform */ size_t Engine::get_link_count() const { diff --git a/src/s4u/s4u_Io.cpp b/src/s4u/s4u_Io.cpp index a0482b5ca7..e8aa898590 100644 --- a/src/s4u/s4u_Io.cpp +++ b/src/s4u/s4u_Io.cpp @@ -99,7 +99,7 @@ ssize_t Io::deprecated_wait_any_for(const std::vector& ios, double timeou { ActivitySet set; for (const auto& io : ios) - set.push(boost::dynamic_pointer_cast(io)); + set.push(io); auto* ret = set.wait_any_for(timeout).get(); for (size_t i = 0; i < ios.size(); i++) diff --git a/src/s4u/s4u_Mess.cpp b/src/s4u/s4u_Mess.cpp new file mode 100644 index 0000000000..9799ad1eb7 --- /dev/null +++ b/src/s4u/s4u_Mess.cpp @@ -0,0 +1,153 @@ +/* Copyright (c) 2023. 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 +#include +#include + +#include "src/kernel/activity/MessImpl.hpp" +#include "src/kernel/actor/ActorImpl.hpp" +#include "src/kernel/actor/SimcallObserver.hpp" + +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(s4u_mess, s4u_activity, "S4U asynchronous messaging"); + +namespace simgrid::s4u { +xbt::signal Mess::on_send; +xbt::signal Mess::on_recv; + +MessPtr Mess::set_queue(MessageQueue* queue) +{ + queue_ = queue; + return this; +} + +MessPtr Mess::set_payload(void* payload) +{ + payload_ = payload; + return this; +} + +MessPtr Mess::set_dst_data(void** buff, size_t size) +{ + xbt_assert(state_ == State::INITED, "You cannot use %s() once your communication started (not implemented)", + __FUNCTION__); + + dst_buff_ = buff; + dst_buff_size_ = size; + return this; +} + +Actor* Mess::get_sender() const +{ + kernel::actor::ActorImplPtr sender = nullptr; + if (pimpl_) + sender = boost::static_pointer_cast(pimpl_)->src_actor_; + return sender ? sender->get_ciface() : nullptr; +} + +Actor* Mess::get_receiver() const +{ + kernel::actor::ActorImplPtr receiver = nullptr; + if (pimpl_) + receiver = boost::static_pointer_cast(pimpl_)->dst_actor_; + return receiver ? receiver->get_ciface() : nullptr; +} + +Mess* Mess::do_start() +{ + xbt_assert(get_state() == State::INITED || get_state() == State::STARTING, + "You cannot use %s() once your message exchange has started (not implemented)", __FUNCTION__); + + auto myself = kernel::actor::ActorImpl::self(); + if (myself == sender_) { + on_send(*this); + on_this_send(*this); + kernel::actor::MessIputSimcall observer{sender_, queue_->get_impl(), get_payload()}; + pimpl_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::MessImpl::iput(&observer); }, + &observer); + } else if (myself == receiver_) { + on_recv(*this); + on_this_recv(*this); + kernel::actor::MessIgetSimcall observer{receiver_, + queue_->get_impl(), + static_cast(dst_buff_), + &dst_buff_size_, + get_payload()}; + pimpl_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::MessImpl::iget(&observer); }, + &observer); + } else { + xbt_die("Cannot start a message exchange before specifying whether we are the sender or the receiver"); + } + + pimpl_->set_iface(this); + pimpl_->set_actor(sender_); + // Only throw the signal when both sides are here and the status is READY + if (pimpl_->get_state() != kernel::activity::State::WAITING) { + fire_on_start(); + fire_on_this_start(); + } + state_ = State::STARTED; + return this; +} + +Mess* Mess::wait_for(double timeout) +{ + XBT_DEBUG("Calling Mess::wait_for with state %s", get_state_str()); + kernel::actor::ActorImpl* issuer = nullptr; + switch (state_) { + case State::FINISHED: + break; + case State::FAILED: + throw NetworkFailureException(XBT_THROW_POINT, "Cannot wait for a failed communication"); + case State::INITED: + case State::STARTING: + if (get_payload() != nullptr) { + on_send(*this); + on_this_send(*this); + kernel::actor::MessIputSimcall observer{sender_, queue_->get_impl(), get_payload()}; + pimpl_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::MessImpl::iput(&observer); }, + &observer); + } else { // Receiver + on_recv(*this); + on_this_recv(*this); + kernel::actor::MessIgetSimcall observer{receiver_, + queue_->get_impl(), + static_cast(dst_buff_), + &dst_buff_size_, + get_payload()}; + pimpl_ = kernel::actor::simcall_answered([&observer] { return kernel::activity::MessImpl::iget(&observer); }, + &observer); + } + break; + case State::STARTED: + try { + issuer = kernel::actor::ActorImpl::self(); + kernel::actor::ActivityWaitSimcall observer{issuer, pimpl_.get(), timeout, "Wait"}; + if (kernel::actor::simcall_blocking( + [&observer] { observer.get_activity()->wait_for(observer.get_issuer(), observer.get_timeout()); }, + &observer)) { + throw TimeoutException(XBT_THROW_POINT, "Timeouted"); + } + } catch (const NetworkFailureException& e) { + issuer->simcall_.observer_ = nullptr; // Comm failed on network failure, reset the observer to nullptr + complete(State::FAILED); + e.rethrow_nested(XBT_THROW_POINT, boost::core::demangle(typeid(e).name()) + " raised in kernel mode."); + } + break; + + case State::CANCELED: + throw CancelException(XBT_THROW_POINT, "Message canceled"); + + default: + THROW_IMPOSSIBLE; + } + complete(State::FINISHED); + return this; +} + +} // namespace simgrid::s4u diff --git a/src/s4u/s4u_MessageQueue.cpp b/src/s4u/s4u_MessageQueue.cpp new file mode 100644 index 0000000000..8fe34ac8a2 --- /dev/null +++ b/src/s4u/s4u_MessageQueue.cpp @@ -0,0 +1,98 @@ +/* Copyright (c) 2023. 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 "src/kernel/activity/MessageQueueImpl.hpp" + +XBT_LOG_EXTERNAL_CATEGORY(s4u); +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(s4u_mqueue, s4u, "S4U Message Queues"); + +namespace simgrid::s4u { + +const std::string& MessageQueue::get_name() const +{ + return pimpl_->get_name(); +} + +const char* MessageQueue::get_cname() const +{ + return pimpl_->get_cname(); +} + +MessageQueue* MessageQueue::by_name(const std::string& name) +{ + return Engine::get_instance()->message_queue_by_name_or_create(name); +} + +bool MessageQueue::empty() const +{ + return pimpl_->empty(); +} + +size_t MessageQueue::size() const +{ + return pimpl_->size(); +} + +kernel::activity::MessImplPtr MessageQueue::front() const +{ + return pimpl_->empty() ? nullptr : pimpl_->front(); +} + +MessPtr MessageQueue::put_init() +{ + MessPtr res(new Mess()); + res->set_queue(this); + res->sender_ = kernel::actor::ActorImpl::self(); + return res; +} + +MessPtr MessageQueue::put_init(void* payload) +{ + return put_init()->set_payload(payload); +} + +MessPtr MessageQueue::put_async(void* payload) +{ + xbt_assert(payload != nullptr, "You cannot send nullptr"); + MessPtr res = put_init(payload); + res->start(); + return res; +} + +void MessageQueue::put(void* payload) +{ + xbt_assert(payload != nullptr, "You cannot send nullptr"); + + put_async(payload)->wait(); +} + +/** Blocking send with timeout */ +void MessageQueue::put(void* payload, double timeout) +{ + xbt_assert(payload != nullptr, "You cannot send nullptr"); + + put_init()->set_payload(payload)->start()->wait_for(timeout); +} + +MessPtr MessageQueue::get_init() +{ + MessPtr res(new Mess()); + res->set_queue(this); + res->receiver_ = kernel::actor::ActorImpl::self(); + return res; +} + +MessPtr MessageQueue::get_async() +{ + MessPtr res = get_init()->set_payload(nullptr); + res->start(); + return res; +} + +} // namespace simgrid::s4u diff --git a/src/s4u/s4u_Mutex.cpp b/src/s4u/s4u_Mutex.cpp index 051f11c153..12fa915d5b 100644 --- a/src/s4u/s4u_Mutex.cpp +++ b/src/s4u/s4u_Mutex.cpp @@ -55,9 +55,9 @@ bool Mutex::try_lock() * * See @ref s4u_raii. */ -MutexPtr Mutex::create() +MutexPtr Mutex::create(bool recursive) { - auto* mutex = new kernel::activity::MutexImpl(); + auto* mutex = new kernel::activity::MutexImpl(recursive); return MutexPtr(&mutex->mutex(), false); } diff --git a/src/s4u/s4u_Netzone.cpp b/src/s4u/s4u_Netzone.cpp index 48377bbf13..1917f0f658 100644 --- a/src/s4u/s4u_Netzone.cpp +++ b/src/s4u/s4u_Netzone.cpp @@ -96,8 +96,8 @@ void NetZone::add_route(const NetZone* src, const NetZone* dst, const std::vecto pimpl_->add_route(src ? src->get_netpoint() : nullptr, dst ? dst->get_netpoint(): nullptr, src ? src->get_gateway() : nullptr, dst ? dst->get_gateway() : nullptr, links_direct, false); - pimpl_->add_route(src ? src->get_netpoint() : nullptr, dst ? dst->get_netpoint(): nullptr, - src ? src->get_gateway() : nullptr, dst ? dst->get_gateway() : nullptr, + pimpl_->add_route(dst ? dst->get_netpoint(): nullptr, src ? src->get_netpoint() : nullptr, + dst ? dst->get_gateway() : nullptr, src ? src->get_gateway() : nullptr, links_reverse, false); } diff --git a/src/simgrid/sg_config.cpp b/src/simgrid/sg_config.cpp index 98e0648fed..5902d70865 100644 --- a/src/simgrid/sg_config.cpp +++ b/src/simgrid/sg_config.cpp @@ -20,7 +20,6 @@ #include "src/simgrid/module.hpp" #include "src/simgrid/sg_config.hpp" #include "src/smpi/include/smpi_config.hpp" -#include "src/xbt/mmalloc/mmalloc.h" #include @@ -202,15 +201,8 @@ void sg_config_init(int *argc, char **argv) [](int value) { simgrid::kernel::context::Context::guard_size = value * xbt_pagesize; }}; static simgrid::config::Flag cfg_context_nthreads{ - "contexts/nthreads", "Number of parallel threads used to execute user contexts", 1, [](int nthreads) { -#if HAVE_MMALLOC - xbt_assert( - nthreads == 1 || not malloc_use_mmalloc(), - "Parallel simulation is forbidden in the verified program, as there is no protection against race " - "conditions in mmalloc itself. Please don't be so greedy and show some mercy for our implementation."); -#endif - simgrid::kernel::context::Context::set_nthreads(nthreads); - }}; + "contexts/nthreads", "Number of parallel threads used to execute user contexts", 1, + [](int nthreads) { simgrid::kernel::context::Context::set_nthreads(nthreads); }}; /* synchronization mode for parallel user contexts */ #if HAVE_FUTEX_H diff --git a/src/simgrid/sg_config.hpp b/src/simgrid/sg_config.hpp index 10dbe7baa7..25e4a168b2 100644 --- a/src/simgrid/sg_config.hpp +++ b/src/simgrid/sg_config.hpp @@ -10,7 +10,7 @@ /** Config Globals */ -XBT_PUBLIC_DATA int _sg_cfg_init_status; +XBT_PUBLIC_DATA int _sg_cfg_init_status; /* 0: not inited; 1: config module inited; 2: root zone of platform created */ XBT_PUBLIC void sg_config_init(int* argc, char** argv); XBT_PUBLIC void sg_config_finalize(); diff --git a/src/simgrid/sg_version.cpp b/src/simgrid/sg_version.cpp index 1428132895..953f6b1b49 100644 --- a/src/simgrid/sg_version.cpp +++ b/src/simgrid/sg_version.cpp @@ -50,12 +50,6 @@ void sg_version() XBT_HELP("This program was linked against %s (git: %s), found in %s.", SIMGRID_VERSION_STRING, SIMGRID_GIT_VERSION, SIMGRID_INSTALL_PREFIX); -#if SIMGRID_HAVE_STATEFUL_MC - XBT_HELP(" Stateful model-checking support compiled in."); -#else - XBT_HELP(" Stateful model-checking support disabled at compilation."); -#endif - #if SIMGRID_HAVE_NS3 XBT_HELP(" ns-3 support compiled in."); #else diff --git a/src/smpi/bindings/smpi_mpi.cpp b/src/smpi/bindings/smpi_mpi.cpp index 3bd52c78d7..7e62ffac34 100644 --- a/src/smpi/bindings/smpi_mpi.cpp +++ b/src/smpi/bindings/smpi_mpi.cpp @@ -501,3 +501,9 @@ UNIMPLEMENTED_WRAPPED_PMPI_CALL(int,MPI_Unpack_external,(char *datarep, void *in UNIMPLEMENTED_WRAPPED_PMPI_CALL(int,MPI_Unpublish_name,( char *service_name, MPI_Info info, char *port_name),( service_name, info, port_name)) UNIMPLEMENTED_WRAPPED_PMPI_CALL(int,MPI_Win_test,(MPI_Win win, int *flag),(win, flag)) UNIMPLEMENTED_WRAPPED_PMPI_CALL_NOFAIL(int,MPI_Win_sync,(MPI_Win win),(win)) +UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Parrived, (MPI_Request request, int partition, int *flag), (request, partition, flag)) +UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Pready, (int partitions, MPI_Request request), (partitions, request)) +UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Pready_range, (int partition_low, int partition_high, MPI_Request request),(partition_low, partition_high, request)) +UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Pready_list, (int length, int partition_list[], MPI_Request request), (length, partition_list, request)) +UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Precv_init, (void* buf, int partitions, MPI_Count count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Info info, MPI_Request *request), (buf, partitions, count, datatype, source, tag, comm, info, request)) +UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_Psend_init, (const void* buf, int partitions, MPI_Count count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Info info, MPI_Request *request), (buf, partitions, count, datatype, dest, tag, comm, info, request)) diff --git a/src/smpi/bindings/smpi_pmpi_request.cpp b/src/smpi/bindings/smpi_pmpi_request.cpp index 94bb62be2a..8cf9b41312 100644 --- a/src/smpi/bindings/smpi_pmpi_request.cpp +++ b/src/smpi/bindings/smpi_pmpi_request.cpp @@ -381,6 +381,8 @@ int PMPI_Sendrecv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, int CHECK_TYPE(8, recvtype) CHECK_BUFFER(1, sendbuf, sendcount, sendtype) CHECK_BUFFER(6, recvbuf, recvcount, recvtype) + CHECK_ARGS(sendbuf == recvbuf && sendcount > 0 && recvcount > 0, MPI_ERR_BUFFER, + "%s: Invalid parameters 1 and 6: sendbuf and recvbuf must be disjoint", __func__); CHECK_TAG(10, recvtag) CHECK_COMM(11) const SmpiBenchGuard suspend_bench; diff --git a/src/smpi/internals/smpi_actor.cpp b/src/smpi/internals/smpi_actor.cpp index 2cd94c93ef..056cecf48e 100644 --- a/src/smpi/internals/smpi_actor.cpp +++ b/src/smpi/internals/smpi_actor.cpp @@ -32,7 +32,6 @@ ActorExt::ActorExt(s4u::Actor* actor) : actor_(actor) timer_ = xbt_os_timer_new(); state_ = SmpiProcessState::UNINITIALIZED; info_env_ = MPI_INFO_NULL; - MC_ignore_heap(timer_, xbt_os_timer_size()); #if HAVE_PAPI if (not smpi_cfg_papi_events_file().empty()) { diff --git a/src/smpi/internals/smpi_global.cpp b/src/smpi/internals/smpi_global.cpp index 36a3e39101..10203cbca8 100644 --- a/src/smpi/internals/smpi_global.cpp +++ b/src/smpi/internals/smpi_global.cpp @@ -59,51 +59,51 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_kernel, smpi, "Logging specific to SMPI (ke * See https://www.akkadia.org/drepper/dsohowto.pdf * and https://lists.freebsd.org/pipermail/freebsd-current/2016-March/060284.html */ -#if !RTLD_DEEPBIND || HAVE_SANITIZER_ADDRESS || HAVE_SANITIZER_THREAD +#if !defined(RTLD_DEEPBIND) || !RTLD_DEEPBIND || HAVE_SANITIZER_ADDRESS || HAVE_SANITIZER_THREAD #define WANT_RTLD_DEEPBIND 0 #else #define WANT_RTLD_DEEPBIND RTLD_DEEPBIND #endif #if HAVE_PAPI -std::map> units2papi_setup; + std::map> units2papi_setup; #endif -std::unordered_map location2speedup; + std::unordered_map location2speedup; -static int smpi_exit_status = 0; -static xbt_os_timer_t global_timer; -static std::vector privatize_libs_paths; + static int smpi_exit_status = 0; + static xbt_os_timer_t global_timer; + static std::vector privatize_libs_paths; -// No instance gets manually created; check also the smpirun.in script as -// this default name is used there as well (when the tag is generated). -static const std::string smpi_default_instance_name("smpirun"); + // No instance gets manually created; check also the smpirun.in script as + // this default name is used there as well (when the tag is generated). + static const std::string smpi_default_instance_name("smpirun"); -static simgrid::config::Flag - smpi_hostfile("smpi/hostfile", - "Classical MPI hostfile containing list of machines to dispatch " - "the processes, one per line", - ""); + static simgrid::config::Flag + smpi_hostfile("smpi/hostfile", + "Classical MPI hostfile containing list of machines to dispatch " + "the processes, one per line", + ""); -static simgrid::config::Flag smpi_replay("smpi/replay", - "Replay a trace instead of executing the application", ""); + static simgrid::config::Flag smpi_replay("smpi/replay", + "Replay a trace instead of executing the application", ""); -static simgrid::config::Flag smpi_np("smpi/np", "Number of processes to be created", 0); + static simgrid::config::Flag smpi_np("smpi/np", "Number of processes to be created", 0); -static simgrid::config::Flag smpi_map("smpi/map", "Display the mapping between nodes and processes", 0); + static simgrid::config::Flag smpi_map("smpi/map", "Display the mapping between nodes and processes", 0); -std::function smpi_comm_copy_data_callback = - &smpi_comm_copy_buffer_callback; + std::function smpi_comm_copy_data_callback = + &smpi_comm_copy_buffer_callback; -simgrid::smpi::ActorExt* smpi_process() -{ - simgrid::s4u::ActorPtr me = simgrid::s4u::Actor::self(); + simgrid::smpi::ActorExt* smpi_process() + { + simgrid::s4u::ActorPtr me = simgrid::s4u::Actor::self(); - if (me == nullptr) // This happens sometimes (eg, when linking against NS3 because it pulls openMPI...) - return nullptr; + if (me == nullptr) // This happens sometimes (eg, when linking against NS3 because it pulls openMPI...) + return nullptr; - return me->extension(); -} + return me->extension(); + } simgrid::smpi::ActorExt* smpi_process_remote(simgrid::s4u::ActorPtr actor) { diff --git a/src/smpi/mpi/smpi_datatype.cpp b/src/smpi/mpi/smpi_datatype.cpp index 642aa24b22..539e567e25 100644 --- a/src/smpi/mpi/smpi_datatype.cpp +++ b/src/smpi/mpi/smpi_datatype.cpp @@ -116,7 +116,6 @@ Datatype::Datatype(int ident, int size, MPI_Aint lb, MPI_Aint ub, int flags) : D Datatype::Datatype(int size, MPI_Aint lb, MPI_Aint ub, int flags) : size_(size), lb_(lb), ub_(ub), flags_(flags) { this->add_f(); - MC_ignore(&refcount_, sizeof refcount_); } // for predefined types, so refcount_ = 0. @@ -124,7 +123,6 @@ Datatype::Datatype(const char* name, int ident, int size, MPI_Aint lb, MPI_Aint : name_(name), id(std::to_string(ident)), size_(size), lb_(lb), ub_(ub), flags_(flags), refcount_(0) { id2type_lookup.try_emplace(id, this); - MC_ignore(&refcount_, sizeof refcount_); } Datatype::Datatype(Datatype* datatype, int* ret) @@ -205,14 +203,12 @@ int Datatype::clone(MPI_Datatype* type){ void Datatype::ref() { refcount_++; - MC_ignore(&refcount_, sizeof refcount_); } void Datatype::unref(MPI_Datatype datatype) { if (datatype->refcount_ > 0) datatype->refcount_--; - MC_ignore(&datatype->refcount_, sizeof datatype->refcount_); if (datatype->refcount_ == 0 && not(datatype->flags_ & DT_FLAG_PREDEFINED)) delete datatype; diff --git a/src/sthread/ObjectAccess.cpp b/src/sthread/ObjectAccess.cpp index 6e38668af8..25e9b52c32 100644 --- a/src/sthread/ObjectAccess.cpp +++ b/src/sthread/ObjectAccess.cpp @@ -51,6 +51,7 @@ struct ObjectOwner { simgrid::kernel::actor::ActorImpl* owner = nullptr; const char* file = nullptr; int line = -1; + int recursive_depth = 0; explicit ObjectOwner(simgrid::kernel::actor::ActorImpl* o) : owner(o) {} }; @@ -73,7 +74,7 @@ static ObjectOwner* get_owner(void* object) return o; } -int sthread_access_begin(void* objaddr, const char* objname, const char* file, int line) +int sthread_access_begin(void* objaddr, const char* objname, const char* file, int line, const char* func) { sthread_disable(); auto* self = simgrid::kernel::actor::ActorImpl::self(); @@ -83,10 +84,23 @@ int sthread_access_begin(void* objaddr, const char* objname, const char* file, i [self, objaddr, objname, file, line]() -> bool { XBT_INFO("%s takes %s", self->get_cname(), objname); auto* ownership = get_owner(objaddr); - if (ownership->owner != nullptr) { + if (ownership->owner == self) { + ownership->recursive_depth++; + return true; + } else if (ownership->owner != nullptr) { auto msg = std::string("Unprotected concurent access to ") + objname + ": " + ownership->owner->get_name(); - if (not xbt_log_no_loc) + if (not xbt_log_no_loc) { msg += simgrid::xbt::string_printf(" at %s:%d", ownership->file, ownership->line); + if (ownership->recursive_depth > 1) { + msg += simgrid::xbt::string_printf(" (and %d other locations)", ownership->recursive_depth - 1); + if (ownership->recursive_depth != 2) + msg += "s"; + } + } else { + msg += simgrid::xbt::string_printf(" from %d location", ownership->recursive_depth); + if (ownership->recursive_depth != 1) + msg += "s"; + } msg += " vs " + self->get_name(); if (xbt_log_no_loc) msg += std::string(" (locations hidden because of --log=no_loc)."); @@ -98,6 +112,7 @@ int sthread_access_begin(void* objaddr, const char* objname, const char* file, i ownership->owner = self; ownership->file = file; ownership->line = line; + ownership->recursive_depth = 1; return true; }, &observer); @@ -106,7 +121,7 @@ int sthread_access_begin(void* objaddr, const char* objname, const char* file, i sthread_enable(); return true; } -void sthread_access_end(void* objaddr, const char* objname, const char* file, int line) +void sthread_access_end(void* objaddr, const char* objname, const char* file, int line, const char* func) { sthread_disable(); auto* self = simgrid::kernel::actor::ActorImpl::self(); @@ -116,9 +131,12 @@ void sthread_access_end(void* objaddr, const char* objname, const char* file, in [self, objaddr, objname]() -> void { XBT_INFO("%s releases %s", self->get_cname(), objname); auto* ownership = get_owner(objaddr); - xbt_assert(ownership->owner == self, "safety check failed: %s is not owner of the object it's releasing.", - self->get_cname()); - ownership->owner = nullptr; + xbt_assert(ownership->owner == self, + "safety check failed: %s is not owner of the object it's releasing. That object owned by %s.", + self->get_cname(), (ownership->owner == nullptr ? "nobody" : ownership->owner->get_cname())); + ownership->recursive_depth--; + if (ownership->recursive_depth == 0) + ownership->owner = nullptr; }, &observer); sthread_enable(); diff --git a/src/sthread/sthread.c b/src/sthread/sthread.c index ee9e0847ea..2005f297ad 100644 --- a/src/sthread/sthread.c +++ b/src/sthread/sthread.c @@ -28,6 +28,12 @@ static int (*raw_mutex_trylock)(pthread_mutex_t*); static int (*raw_mutex_unlock)(pthread_mutex_t*); static int (*raw_mutex_destroy)(pthread_mutex_t*); +static int (*raw_pthread_mutexattr_init)(pthread_mutexattr_t*); +static int (*raw_pthread_mutexattr_settype)(pthread_mutexattr_t*, int); +static int (*raw_pthread_mutexattr_gettype)(const pthread_mutexattr_t* restrict, int* restrict); +static int (*raw_pthread_mutexattr_getrobust)(const pthread_mutexattr_t*, int*); +static int (*raw_pthread_mutexattr_setrobust)(pthread_mutexattr_t*, int); + static unsigned int (*raw_sleep)(unsigned int); static int (*raw_usleep)(useconds_t); static int (*raw_gettimeofday)(struct timeval*, void*); @@ -50,6 +56,12 @@ static void intercepter_init() raw_mutex_unlock = dlsym(RTLD_NEXT, "pthread_mutex_unlock"); raw_mutex_destroy = dlsym(RTLD_NEXT, "pthread_mutex_destroy"); + raw_pthread_mutexattr_init = dlsym(RTLD_NEXT, "pthread_mutexattr_init"); + raw_pthread_mutexattr_settype = dlsym(RTLD_NEXT, "pthread_mutexattr_settype"); + raw_pthread_mutexattr_gettype = dlsym(RTLD_NEXT, "pthread_mutexattr_gettype"); + raw_pthread_mutexattr_getrobust = dlsym(RTLD_NEXT, "pthread_mutexattr_getrobust"); + raw_pthread_mutexattr_setrobust = dlsym(RTLD_NEXT, "pthread_mutexattr_setrobust"); + raw_sleep = dlsym(RTLD_NEXT, "sleep"); raw_usleep = dlsym(RTLD_NEXT, "usleep"); raw_gettimeofday = dlsym(RTLD_NEXT, "gettimeofday"); @@ -85,6 +97,32 @@ int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_ sthread_enable(); return res; } + +#define _STHREAD_CONCAT(a, b) a##b +#define intercepted_call(name, raw_params, call_params, sim_params) \ + int _STHREAD_CONCAT(pthread_, name) raw_params \ + { \ + if (_STHREAD_CONCAT(raw_pthread_, name) == NULL) \ + intercepter_init(); \ + if (sthread_inside_simgrid) \ + return _STHREAD_CONCAT(raw_pthread_, name) call_params; \ + \ + sthread_disable(); \ + int res = _STHREAD_CONCAT(sthread_, name) sim_params; \ + sthread_enable(); \ + return res; \ + } + +intercepted_call(mutexattr_init, (pthread_mutexattr_t * attr), (attr), ((sthread_mutexattr_t*)attr)); +intercepted_call(mutexattr_settype, (pthread_mutexattr_t * attr, int type), (attr, type), + ((sthread_mutexattr_t*)attr, type)); +intercepted_call(mutexattr_gettype, (const pthread_mutexattr_t* restrict attr, int* type), (attr, type), + ((sthread_mutexattr_t*)attr, type)); +intercepted_call(mutexattr_setrobust, (pthread_mutexattr_t* restrict attr, int robustness), (attr, robustness), + ((sthread_mutexattr_t*)attr, robustness)); +intercepted_call(mutexattr_getrobust, (const pthread_mutexattr_t* restrict attr, int* restrict robustness), + (attr, robustness), ((sthread_mutexattr_t*)attr, robustness)); + int pthread_join(pthread_t thread, void** retval) { if (raw_pthread_join == NULL) @@ -107,7 +145,7 @@ int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr) return raw_mutex_init(mutex, attr); sthread_disable(); - int res = sthread_mutex_init((sthread_mutex_t*)mutex, attr); + int res = sthread_mutex_init((sthread_mutex_t*)mutex, (sthread_mutexattr_t*)attr); sthread_enable(); return res; } diff --git a/src/sthread/sthread.h b/src/sthread/sthread.h index 65279685e6..f0a9117db1 100644 --- a/src/sthread/sthread.h +++ b/src/sthread/sthread.h @@ -31,10 +31,22 @@ typedef unsigned long int sthread_t; int sthread_create(sthread_t* thread, const /*pthread_attr_t*/ void* attr, void* (*start_routine)(void*), void* arg); int sthread_join(sthread_t thread, void** retval); +typedef struct { + unsigned recursive : 1; + unsigned errorcheck : 1; + unsigned robust : 1; +} sthread_mutexattr_t; + +int sthread_mutexattr_init(sthread_mutexattr_t* attr); +int sthread_mutexattr_settype(sthread_mutexattr_t* attr, int type); +int sthread_mutexattr_gettype(const sthread_mutexattr_t* attr, int* type); +int sthread_mutexattr_getrobust(const sthread_mutexattr_t* attr, int* robustness); +int sthread_mutexattr_setrobust(sthread_mutexattr_t* attr, int robustness); + typedef struct { void* mutex; } sthread_mutex_t; -int sthread_mutex_init(sthread_mutex_t* mutex, const /*pthread_mutexattr_t*/ void* attr); +int sthread_mutex_init(sthread_mutex_t* mutex, const sthread_mutexattr_t* attr); int sthread_mutex_lock(sthread_mutex_t* mutex); int sthread_mutex_trylock(sthread_mutex_t* mutex); int sthread_mutex_unlock(sthread_mutex_t* mutex); @@ -53,8 +65,8 @@ int sthread_sem_timedwait(sthread_sem_t* sem, const struct timespec* abs_timeout int sthread_gettimeofday(struct timeval* tv); void sthread_sleep(double seconds); -int sthread_access_begin(void* objaddr, const char* objname, const char* file, int line); -void sthread_access_end(void* objaddr, const char* objname, const char* file, int line); +int sthread_access_begin(void* objaddr, const char* objname, const char* file, int line, const char* function); +void sthread_access_end(void* objaddr, const char* objname, const char* file, int line, const char* function); #if defined(__cplusplus) } diff --git a/src/sthread/sthread_impl.cpp b/src/sthread/sthread_impl.cpp index 45ba730029..9dbf78913e 100644 --- a/src/sthread/sthread_impl.cpp +++ b/src/sthread/sthread_impl.cpp @@ -6,6 +6,9 @@ /* SimGrid's pthread interposer. Actual implementation of the symbols (see the comment in sthread.h) */ #include "smpi/smpi.h" +#include "xbt/asserts.h" +#include "xbt/ex.h" +#include "xbt/log.h" #include "xbt/string.hpp" #include #include @@ -38,14 +41,22 @@ int sthread_main(int argc, char** argv, char** envp, int (*raw_main)(int, char** { /* Do not intercept the main when run from SMPI: it will initialize the simulation properly */ for (int i = 0; envp[i] != nullptr; i++) - if (std::string_view(envp[i]).rfind("SMPI_GLOBAL_SIZE", 0) == 0) + if (std::string_view(envp[i]).rfind("SMPI_GLOBAL_SIZE", 0) == 0) { + printf("sthread refuses to intercept the SMPI application %s directly, as its interception is done otherwise.\n", + argv[0]); return raw_main(argc, argv, envp); + } - /* If not in SMPI, the old main becomes an actor in a newly created simulation */ - std::ostringstream id; - id << std::this_thread::get_id(); + /* Do not intercept valgrind step 1 */ + if (not strcmp(argv[0], "/usr/bin/valgrind.bin") || not strcmp(argv[0], "/bin/sh")) { + printf("sthread refuses to intercept the execution of %s. Running the application unmodified.\n", argv[0]); + fflush(stdout); + return raw_main(argc, argv, envp); + } - XBT_DEBUG("sthread main() is starting in thread %s", id.str().c_str()); + /* If not in SMPI, the old main becomes an actor in a newly created simulation */ + printf("sthread is intercepting the execution of %s\n", argv[0]); + fflush(stdout); sg4::Engine e(&argc, argv); auto* zone = sg4::create_full_zone("world"); @@ -56,7 +67,6 @@ int sthread_main(int argc, char** argv, char** envp, int (*raw_main)(int, char** sthread_enable(); sg4::ActorPtr main_actor = sg4::Actor::create("main thread", lilibeth, raw_main, argc, argv, envp); - XBT_INFO("Starting the simulation."); sg4::Engine::get_instance()->run(); sthread_disable(); XBT_INFO("All threads exited. Terminating the simulation."); @@ -108,9 +118,57 @@ int sthread_join(sthread_t thread, void** /*retval*/) return 0; } -int sthread_mutex_init(sthread_mutex_t* mutex, const void* /*pthread_mutexattr_t* attr*/) +int sthread_mutexattr_init(sthread_mutexattr_t* attr) +{ + memset(attr, 0, sizeof(*attr)); + return 0; +} +int sthread_mutexattr_settype(sthread_mutexattr_t* attr, int type) { - auto m = sg4::Mutex::create(); + switch (type) { + case PTHREAD_MUTEX_NORMAL: + xbt_assert(not attr->recursive, "S4U does not allow to remove the recursivness of a mutex."); + attr->recursive = 0; + break; + case PTHREAD_MUTEX_RECURSIVE: + attr->recursive = 1; + attr->errorcheck = 0; // reset + break; + case PTHREAD_MUTEX_ERRORCHECK: + attr->errorcheck = 1; + THROW_UNIMPLEMENTED; + break; + default: + THROW_IMPOSSIBLE; + } + return 0; +} +int sthread_mutexattr_gettype(const sthread_mutexattr_t* attr, int* type) +{ + if (attr->recursive) + *type = PTHREAD_MUTEX_RECURSIVE; + else if (attr->errorcheck) + *type = PTHREAD_MUTEX_ERRORCHECK; + else + *type = PTHREAD_MUTEX_NORMAL; + return 0; +} +int sthread_mutexattr_getrobust(const sthread_mutexattr_t* attr, int* robustness) +{ + *robustness = attr->robust; + return 0; +} +int sthread_mutexattr_setrobust(sthread_mutexattr_t* attr, int robustness) +{ + attr->robust = robustness; + if (robustness) + THROW_UNIMPLEMENTED; + return 0; +} + +int sthread_mutex_init(sthread_mutex_t* mutex, const sthread_mutexattr_t* attr) +{ + auto m = sg4::Mutex::create(attr != nullptr && attr->recursive); intrusive_ptr_add_ref(m.get()); mutex->mutex = m.get(); @@ -123,6 +181,7 @@ int sthread_mutex_lock(sthread_mutex_t* mutex) if (mutex->mutex == nullptr) sthread_mutex_init(mutex, nullptr); + XBT_DEBUG("%s(%p)", __FUNCTION__, mutex); static_cast(mutex->mutex)->lock(); return 0; } @@ -133,7 +192,10 @@ int sthread_mutex_trylock(sthread_mutex_t* mutex) if (mutex->mutex == nullptr) sthread_mutex_init(mutex, nullptr); - return static_cast(mutex->mutex)->try_lock(); + XBT_DEBUG("%s(%p)", __FUNCTION__, mutex); + if (static_cast(mutex->mutex)->try_lock()) + return 0; + return EBUSY; } int sthread_mutex_unlock(sthread_mutex_t* mutex) @@ -142,6 +204,7 @@ int sthread_mutex_unlock(sthread_mutex_t* mutex) if (mutex->mutex == nullptr) sthread_mutex_init(mutex, nullptr); + XBT_DEBUG("%s(%p)", __FUNCTION__, mutex); static_cast(mutex->mutex)->unlock(); return 0; } @@ -151,6 +214,7 @@ int sthread_mutex_destroy(sthread_mutex_t* mutex) if (mutex->mutex == nullptr) sthread_mutex_init(mutex, nullptr); + XBT_DEBUG("%s(%p)", __FUNCTION__, mutex); intrusive_ptr_release(static_cast(mutex->mutex)); return 0; } @@ -211,6 +275,7 @@ int sthread_gettimeofday(struct timeval* tv) void sthread_sleep(double seconds) { + XBT_DEBUG("sleep(%lf)", seconds); simgrid::s4u::this_actor::sleep_for(seconds); } diff --git a/src/xbt/automaton/automaton.c b/src/xbt/automaton/automaton.c deleted file mode 100644 index f44bf6d455..0000000000 --- a/src/xbt/automaton/automaton.c +++ /dev/null @@ -1,417 +0,0 @@ -/* automaton - representation of büchi automaton */ - -/* Copyright (c) 2011-2023. 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 "xbt/automaton.h" -#include /* printf */ -#include - -struct xbt_automaton_propositional_symbol{ - char* pred; - /** Callback used to evaluate the value of the symbol */ - int (*callback)(void*); - /** Additional data for the callback. - Alternatively it can be used as a pointer to the data. */ - void* data; - /** Optional callback used to free the data field */ - void (*free_function)(void*); -}; - -xbt_automaton_t xbt_automaton_new(void){ - xbt_automaton_t automaton = xbt_new0(struct xbt_automaton, 1); - automaton->states = xbt_dynar_new(sizeof(xbt_automaton_state_t), xbt_automaton_state_free_voidp); - automaton->transitions = xbt_dynar_new(sizeof(xbt_automaton_transition_t), xbt_automaton_transition_free_voidp); - automaton->propositional_symbols = xbt_dynar_new(sizeof(xbt_automaton_propositional_symbol_t), xbt_automaton_propositional_symbol_free_voidp); - return automaton; -} - -xbt_automaton_state_t xbt_automaton_state_new(const_xbt_automaton_t a, int type, const char* id) -{ - xbt_automaton_state_t state = xbt_new0(struct xbt_automaton_state, 1); - state->type = type; - state->id = xbt_strdup(id); - state->in = xbt_dynar_new(sizeof(xbt_automaton_transition_t), NULL); - state->out = xbt_dynar_new(sizeof(xbt_automaton_transition_t), NULL); - xbt_dynar_push(a->states, &state); - return state; -} - -xbt_automaton_transition_t xbt_automaton_transition_new(const_xbt_automaton_t a, xbt_automaton_state_t src, - xbt_automaton_state_t dst, xbt_automaton_exp_label_t label) -{ - xbt_automaton_transition_t transition = xbt_new0(struct xbt_automaton_transition, 1); - if(src != NULL){ - xbt_dynar_push(src->out, &transition); - transition->src = src; - } - if(dst != NULL){ - xbt_dynar_push(dst->in, &transition); - transition->dst = dst; - } - transition->label = label; - xbt_dynar_push(a->transitions, &transition); - return transition; -} - -xbt_automaton_exp_label_t xbt_automaton_exp_label_new_or(xbt_automaton_exp_label_t left, - xbt_automaton_exp_label_t right) -{ - xbt_automaton_exp_label_t label = xbt_new0(struct xbt_automaton_exp_label, 1); - label->type = AUT_OR; - label->u.or_and.left_exp = left; - label->u.or_and.right_exp = right; - return label; -} - -xbt_automaton_exp_label_t xbt_automaton_exp_label_new_and(xbt_automaton_exp_label_t left, - xbt_automaton_exp_label_t right) -{ - xbt_automaton_exp_label_t label = xbt_new0(struct xbt_automaton_exp_label, 1); - label->type = AUT_AND; - label->u.or_and.left_exp = left; - label->u.or_and.right_exp = right; - return label; -} - -xbt_automaton_exp_label_t xbt_automaton_exp_label_new_not(xbt_automaton_exp_label_t exp_not) -{ - xbt_automaton_exp_label_t label = xbt_new0(struct xbt_automaton_exp_label, 1); - label->type = AUT_NOT; - label->u.exp_not = exp_not; - return label; -} - -xbt_automaton_exp_label_t xbt_automaton_exp_label_new_predicat(const char* p) -{ - xbt_automaton_exp_label_t label = xbt_new0(struct xbt_automaton_exp_label, 1); - label->type = AUT_PREDICAT; - label->u.predicat = xbt_strdup(p); - return label; -} - -xbt_automaton_exp_label_t xbt_automaton_exp_label_new_one(void) -{ - xbt_automaton_exp_label_t label = xbt_new0(struct xbt_automaton_exp_label, 1); - label->type = AUT_ONE; - return label; -} - -xbt_dynar_t xbt_automaton_get_states(const_xbt_automaton_t a) -{ - return a->states; -} - -xbt_dynar_t xbt_automaton_get_transitions(const_xbt_automaton_t a) -{ - return a->transitions; -} - -xbt_automaton_transition_t xbt_automaton_get_transition(XBT_ATTRIB_UNUSED const_xbt_automaton_t a, - const_xbt_automaton_state_t src, - const_xbt_automaton_state_t dst) -{ - xbt_automaton_transition_t transition; - unsigned int cursor; - xbt_dynar_foreach(src->out, cursor, transition){ - if((transition->src == src) && (transition->dst == dst)) - return transition; - } - return NULL; -} - -xbt_automaton_state_t xbt_automaton_transition_get_source(const_xbt_automaton_transition_t t) -{ - return t->src; -} - -xbt_automaton_state_t xbt_automaton_transition_get_destination(const_xbt_automaton_transition_t t) -{ - return t->dst; -} - -void xbt_automaton_transition_set_source(xbt_automaton_transition_t t, xbt_automaton_state_t src){ - t->src = src; - xbt_dynar_push(src->out,&t); -} - -void xbt_automaton_transition_set_destination(xbt_automaton_transition_t t, xbt_automaton_state_t dst){ - t->dst = dst; - xbt_dynar_push(dst->in,&t); -} - -xbt_dynar_t xbt_automaton_state_get_out_transitions(const_xbt_automaton_state_t s) -{ - return s->out; -} - -xbt_dynar_t xbt_automaton_state_get_in_transitions(const_xbt_automaton_state_t s) -{ - return s->in; -} - -xbt_automaton_state_t xbt_automaton_state_exists(const_xbt_automaton_t a, const char* id) -{ - xbt_automaton_state_t state = NULL; - unsigned int cursor = 0; - xbt_dynar_foreach(a->states, cursor, state){ - if(strcmp(state->id, id)==0) - return state; - } - return NULL; -} - -void xbt_automaton_display(const_xbt_automaton_t a) -{ - unsigned int cursor; - xbt_automaton_state_t state = NULL; - - printf("\n\nCurrent state: %s\n", a->current_state->id); - - printf("\nStates' List: %lu\n\n", xbt_dynar_length(a->states)); - - xbt_dynar_foreach(a->states, cursor, state) - printf("ID: %s, type: %d\n", state->id, state->type); - - xbt_automaton_transition_t transition; - printf("\nTransitions: %lu\n\n", xbt_dynar_length(a->transitions)); - - xbt_dynar_foreach(a->transitions, cursor, transition){ - printf("label:"); - xbt_automaton_exp_label_display(transition->label); - printf(", %s -> %s\n", transition->src->id, transition->dst->id); - } -} - -void xbt_automaton_exp_label_display(const_xbt_automaton_exp_label_t label) -{ - printf("("); - switch(label->type){ - case 0: - xbt_automaton_exp_label_display(label->u.or_and.left_exp); - printf(" || "); - xbt_automaton_exp_label_display(label->u.or_and.right_exp); - break; - case 1: - xbt_automaton_exp_label_display(label->u.or_and.left_exp); - printf(" && "); - xbt_automaton_exp_label_display(label->u.or_and.right_exp); - break; - case 2: - printf("!"); - xbt_automaton_exp_label_display(label->u.exp_not); - break; - case 3: - printf("%s", label->u.predicat); - break; - case 4: - printf("1"); - break; - default: - break; - } - printf(")"); -} - -xbt_automaton_state_t xbt_automaton_get_current_state(const_xbt_automaton_t a) -{ - return a->current_state; -} - -static int call_simple_function(int function(void) ) -{ - return function(); -} - -xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new(const_xbt_automaton_t a, const char* id, - int (*fct)(void)) -{ - xbt_automaton_propositional_symbol_t prop_symb = xbt_new0(struct xbt_automaton_propositional_symbol, 1); - prop_symb->pred = xbt_strdup(id); - prop_symb->callback = ((int (*)(void *))&call_simple_function); - prop_symb->data = (void*)&fct; - prop_symb->free_function = NULL; - xbt_dynar_push(a->propositional_symbols, &prop_symb); - return prop_symb; -} - -XBT_PUBLIC xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new_pointer(const_xbt_automaton_t a, - const char* id, - int* value) -{ - xbt_automaton_propositional_symbol_t prop_symb = xbt_new0(struct xbt_automaton_propositional_symbol, 1); - prop_symb->pred = xbt_strdup(id); - prop_symb->callback = NULL; - prop_symb->data = value; - prop_symb->free_function = NULL; - xbt_dynar_push(a->propositional_symbols, &prop_symb); - return prop_symb; -} - -XBT_PUBLIC xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new_callback( - const_xbt_automaton_t a, const char* id, xbt_automaton_propositional_symbol_callback_type callback, void* data, - xbt_automaton_propositional_symbol_free_function_type free_function) -{ - xbt_automaton_propositional_symbol_t prop_symb = xbt_new0(struct xbt_automaton_propositional_symbol, 1); - prop_symb->pred = xbt_strdup(id); - prop_symb->callback = callback; - prop_symb->data = data; - prop_symb->free_function = free_function; - xbt_dynar_push(a->propositional_symbols, &prop_symb); - return prop_symb; -} - -XBT_PUBLIC int xbt_automaton_propositional_symbol_evaluate(const_xbt_automaton_propositional_symbol_t symbol) -{ - if (symbol->callback) - return (symbol->callback)(symbol->data); - else - return *(int*) symbol->data; -} - -XBT_PUBLIC xbt_automaton_propositional_symbol_callback_type -xbt_automaton_propositional_symbol_get_callback(const_xbt_automaton_propositional_symbol_t symbol) -{ - return symbol->callback; -} - -XBT_PUBLIC void* xbt_automaton_propositional_symbol_get_data(const_xbt_automaton_propositional_symbol_t symbol) -{ - return symbol->data; -} - -XBT_PUBLIC const char* xbt_automaton_propositional_symbol_get_name(const_xbt_automaton_propositional_symbol_t symbol) -{ - return symbol->pred; -} - -int xbt_automaton_state_compare(const_xbt_automaton_state_t s1, const_xbt_automaton_state_t s2) -{ - /* single id for each state, id and type sufficient for comparison*/ - return (strcmp(s1->id, s2->id) != 0) || (s1->type != s2->type); -} - -int xbt_automaton_transition_compare(const_xbt_automaton_transition_t t1, const_xbt_automaton_transition_t t2) -{ - return xbt_automaton_state_compare(t1->src, t2->src) || xbt_automaton_state_compare(t1->dst, t2->dst) || - xbt_automaton_exp_label_compare(t1->label, t2->label); -} - -int xbt_automaton_exp_label_compare(const_xbt_automaton_exp_label_t l1, const_xbt_automaton_exp_label_t l2) -{ - if(l1->type != l2->type) - return 1; - - int res; - switch(l1->type){ - case 0 : // OR - case 1 : // AND - res = xbt_automaton_exp_label_compare(l1->u.or_and.left_exp, l2->u.or_and.left_exp) || - xbt_automaton_exp_label_compare(l1->u.or_and.right_exp, l2->u.or_and.right_exp); - break; - case 2 : // NOT - res = xbt_automaton_exp_label_compare(l1->u.exp_not, l2->u.exp_not); - break; - case 3 : // predicat - res = strcmp(l1->u.predicat, l2->u.predicat) != 0; - break; - case 4 : // 1 - res = 0; - break; - default : - res = -1; - break; - } - return res; -} - -int xbt_automaton_propositional_symbols_compare_value(const_xbt_dynar_t s1, const_xbt_dynar_t s2) -{ - unsigned long nb_elem = xbt_dynar_length(s1); - - for (unsigned long cursor = 0; cursor < nb_elem; cursor++) { - const int* iptr1 = xbt_dynar_get_ptr(s1, cursor); - const int* iptr2 = xbt_dynar_get_ptr(s2, cursor); - if(*iptr1 != *iptr2) - return 1; - } - - return 0; -} - -static void xbt_automaton_transition_free(xbt_automaton_transition_t t); -static void xbt_automaton_exp_label_free(xbt_automaton_exp_label_t e); -static void xbt_automaton_propositional_symbol_free(xbt_automaton_propositional_symbol_t ps); - -void xbt_automaton_state_free(xbt_automaton_state_t s){ - if (s == NULL) - return; - xbt_free(s->id); - xbt_dynar_free(&(s->in)); - xbt_dynar_free(&(s->out)); - xbt_free(s); -} - -void xbt_automaton_state_free_voidp(void *s){ - xbt_automaton_state_free((xbt_automaton_state_t) * (void **) s); -} - -static void xbt_automaton_transition_free(xbt_automaton_transition_t t){ - if (t == NULL) - return; - xbt_automaton_exp_label_free(t->label); - xbt_free(t); -} - -void xbt_automaton_transition_free_voidp(void *t){ - xbt_automaton_transition_free((xbt_automaton_transition_t) * (void **) t); -} - -static void xbt_automaton_exp_label_free(xbt_automaton_exp_label_t e){ - if (e == NULL) - return; - switch (e->type) { - case AUT_OR: - case AUT_AND: - xbt_automaton_exp_label_free(e->u.or_and.left_exp); - xbt_automaton_exp_label_free(e->u.or_and.right_exp); - break; - case AUT_NOT: - xbt_automaton_exp_label_free(e->u.exp_not); - break; - case AUT_PREDICAT: - xbt_free(e->u.predicat); - break; - default: - break; - } - xbt_free(e); -} - -void xbt_automaton_exp_label_free_voidp(void *e){ - xbt_automaton_exp_label_free((xbt_automaton_exp_label_t) * (void **) e); -} - -static void xbt_automaton_propositional_symbol_free(xbt_automaton_propositional_symbol_t ps){ - if (ps == NULL) - return; - if (ps->free_function) - ps->free_function(ps->data); - xbt_free(ps->pred); - xbt_free(ps); -} - -void xbt_automaton_propositional_symbol_free_voidp(void *ps){ - xbt_automaton_propositional_symbol_free((xbt_automaton_propositional_symbol_t) * (void**)ps); -} - -void xbt_automaton_free(xbt_automaton_t a){ - if (a == NULL) - return; - xbt_dynar_free(&(a->propositional_symbols)); - xbt_dynar_free(&(a->transitions)); - xbt_dynar_free(&(a->states)); - xbt_free(a); -} diff --git a/src/xbt/automaton/automaton_lexer.yy.c b/src/xbt/automaton/automaton_lexer.yy.c deleted file mode 100644 index 2138ba4ce8..0000000000 --- a/src/xbt/automaton/automaton_lexer.yy.c +++ /dev/null @@ -1,2184 +0,0 @@ -#line 2 "automaton_lexer.yy.c" - -#line 4 "automaton_lexer.yy.c" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define yy_create_buffer xbt_automaton_parser__create_buffer -#define yy_delete_buffer xbt_automaton_parser__delete_buffer -#define yy_scan_buffer xbt_automaton_parser__scan_buffer -#define yy_scan_string xbt_automaton_parser__scan_string -#define yy_scan_bytes xbt_automaton_parser__scan_bytes -#define yy_init_buffer xbt_automaton_parser__init_buffer -#define yy_flush_buffer xbt_automaton_parser__flush_buffer -#define yy_load_buffer_state xbt_automaton_parser__load_buffer_state -#define yy_switch_to_buffer xbt_automaton_parser__switch_to_buffer -#define yypush_buffer_state xbt_automaton_parser_push_buffer_state -#define yypop_buffer_state xbt_automaton_parser_pop_buffer_state -#define yyensure_buffer_stack xbt_automaton_parser_ensure_buffer_stack -#define yy_flex_debug xbt_automaton_parser__flex_debug -#define yyin xbt_automaton_parser_in -#define yyleng xbt_automaton_parser_leng -#define yylex xbt_automaton_parser_lex -#define yylineno xbt_automaton_parser_lineno -#define yyout xbt_automaton_parser_out -#define yyrestart xbt_automaton_parser_restart -#define yytext xbt_automaton_parser_text -#define yywrap xbt_automaton_parser_wrap -#define yyalloc xbt_automaton_parser_alloc -#define yyrealloc xbt_automaton_parser_realloc -#define yyfree xbt_automaton_parser_free - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 6 -#define YY_FLEX_SUBMINOR_VERSION 4 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -#ifdef yy_create_buffer -#define xbt_automaton_parser__create_buffer_ALREADY_DEFINED -#else -#define yy_create_buffer xbt_automaton_parser__create_buffer -#endif - -#ifdef yy_delete_buffer -#define xbt_automaton_parser__delete_buffer_ALREADY_DEFINED -#else -#define yy_delete_buffer xbt_automaton_parser__delete_buffer -#endif - -#ifdef yy_scan_buffer -#define xbt_automaton_parser__scan_buffer_ALREADY_DEFINED -#else -#define yy_scan_buffer xbt_automaton_parser__scan_buffer -#endif - -#ifdef yy_scan_string -#define xbt_automaton_parser__scan_string_ALREADY_DEFINED -#else -#define yy_scan_string xbt_automaton_parser__scan_string -#endif - -#ifdef yy_scan_bytes -#define xbt_automaton_parser__scan_bytes_ALREADY_DEFINED -#else -#define yy_scan_bytes xbt_automaton_parser__scan_bytes -#endif - -#ifdef yy_init_buffer -#define xbt_automaton_parser__init_buffer_ALREADY_DEFINED -#else -#define yy_init_buffer xbt_automaton_parser__init_buffer -#endif - -#ifdef yy_flush_buffer -#define xbt_automaton_parser__flush_buffer_ALREADY_DEFINED -#else -#define yy_flush_buffer xbt_automaton_parser__flush_buffer -#endif - -#ifdef yy_load_buffer_state -#define xbt_automaton_parser__load_buffer_state_ALREADY_DEFINED -#else -#define yy_load_buffer_state xbt_automaton_parser__load_buffer_state -#endif - -#ifdef yy_switch_to_buffer -#define xbt_automaton_parser__switch_to_buffer_ALREADY_DEFINED -#else -#define yy_switch_to_buffer xbt_automaton_parser__switch_to_buffer -#endif - -#ifdef yypush_buffer_state -#define xbt_automaton_parser_push_buffer_state_ALREADY_DEFINED -#else -#define yypush_buffer_state xbt_automaton_parser_push_buffer_state -#endif - -#ifdef yypop_buffer_state -#define xbt_automaton_parser_pop_buffer_state_ALREADY_DEFINED -#else -#define yypop_buffer_state xbt_automaton_parser_pop_buffer_state -#endif - -#ifdef yyensure_buffer_stack -#define xbt_automaton_parser_ensure_buffer_stack_ALREADY_DEFINED -#else -#define yyensure_buffer_stack xbt_automaton_parser_ensure_buffer_stack -#endif - -#ifdef yylex -#define xbt_automaton_parser_lex_ALREADY_DEFINED -#else -#define yylex xbt_automaton_parser_lex -#endif - -#ifdef yyrestart -#define xbt_automaton_parser_restart_ALREADY_DEFINED -#else -#define yyrestart xbt_automaton_parser_restart -#endif - -#ifdef yylex_init -#define xbt_automaton_parser_lex_init_ALREADY_DEFINED -#else -#define yylex_init xbt_automaton_parser_lex_init -#endif - -#ifdef yylex_init_extra -#define xbt_automaton_parser_lex_init_extra_ALREADY_DEFINED -#else -#define yylex_init_extra xbt_automaton_parser_lex_init_extra -#endif - -#ifdef yylex_destroy -#define xbt_automaton_parser_lex_destroy_ALREADY_DEFINED -#else -#define yylex_destroy xbt_automaton_parser_lex_destroy -#endif - -#ifdef yyget_debug -#define xbt_automaton_parser_get_debug_ALREADY_DEFINED -#else -#define yyget_debug xbt_automaton_parser_get_debug -#endif - -#ifdef yyset_debug -#define xbt_automaton_parser_set_debug_ALREADY_DEFINED -#else -#define yyset_debug xbt_automaton_parser_set_debug -#endif - -#ifdef yyget_extra -#define xbt_automaton_parser_get_extra_ALREADY_DEFINED -#else -#define yyget_extra xbt_automaton_parser_get_extra -#endif - -#ifdef yyset_extra -#define xbt_automaton_parser_set_extra_ALREADY_DEFINED -#else -#define yyset_extra xbt_automaton_parser_set_extra -#endif - -#ifdef yyget_in -#define xbt_automaton_parser_get_in_ALREADY_DEFINED -#else -#define yyget_in xbt_automaton_parser_get_in -#endif - -#ifdef yyset_in -#define xbt_automaton_parser_set_in_ALREADY_DEFINED -#else -#define yyset_in xbt_automaton_parser_set_in -#endif - -#ifdef yyget_out -#define xbt_automaton_parser_get_out_ALREADY_DEFINED -#else -#define yyget_out xbt_automaton_parser_get_out -#endif - -#ifdef yyset_out -#define xbt_automaton_parser_set_out_ALREADY_DEFINED -#else -#define yyset_out xbt_automaton_parser_set_out -#endif - -#ifdef yyget_leng -#define xbt_automaton_parser_get_leng_ALREADY_DEFINED -#else -#define yyget_leng xbt_automaton_parser_get_leng -#endif - -#ifdef yyget_text -#define xbt_automaton_parser_get_text_ALREADY_DEFINED -#else -#define yyget_text xbt_automaton_parser_get_text -#endif - -#ifdef yyget_lineno -#define xbt_automaton_parser_get_lineno_ALREADY_DEFINED -#else -#define yyget_lineno xbt_automaton_parser_get_lineno -#endif - -#ifdef yyset_lineno -#define xbt_automaton_parser_set_lineno_ALREADY_DEFINED -#else -#define yyset_lineno xbt_automaton_parser_set_lineno -#endif - -#ifdef yywrap -#define xbt_automaton_parser_wrap_ALREADY_DEFINED -#else -#define yywrap xbt_automaton_parser_wrap -#endif - -#ifdef yyalloc -#define xbt_automaton_parser_alloc_ALREADY_DEFINED -#else -#define yyalloc xbt_automaton_parser_alloc -#endif - -#ifdef yyrealloc -#define xbt_automaton_parser_realloc_ALREADY_DEFINED -#else -#define yyrealloc xbt_automaton_parser_realloc -#endif - -#ifdef yyfree -#define xbt_automaton_parser_free_ALREADY_DEFINED -#else -#define yyfree xbt_automaton_parser_free -#endif - -#ifdef yytext -#define xbt_automaton_parser_text_ALREADY_DEFINED -#else -#define yytext xbt_automaton_parser_text -#endif - -#ifdef yyleng -#define xbt_automaton_parser_leng_ALREADY_DEFINED -#else -#define yyleng xbt_automaton_parser_leng -#endif - -#ifdef yyin -#define xbt_automaton_parser_in_ALREADY_DEFINED -#else -#define yyin xbt_automaton_parser_in -#endif - -#ifdef yyout -#define xbt_automaton_parser_out_ALREADY_DEFINED -#else -#define yyout xbt_automaton_parser_out -#endif - -#ifdef yy_flex_debug -#define xbt_automaton_parser__flex_debug_ALREADY_DEFINED -#else -#define yy_flex_debug xbt_automaton_parser__flex_debug -#endif - -#ifdef yylineno -#define xbt_automaton_parser_lineno_ALREADY_DEFINED -#else -#define yylineno xbt_automaton_parser_lineno -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include -#include -#include -#include - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have . Non-C99 systems may or may not. */ - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - -/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. - */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif - -#include -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#ifndef SIZE_MAX -#define SIZE_MAX (~(size_t)0) -#endif - -#endif /* ! C99 */ - -#endif /* ! FLEXINT_H */ - -/* begin standard C++ headers. */ - -/* TODO: this is always defined, so inline it */ -#define yyconst const - -#if defined(__GNUC__) && __GNUC__ >= 3 -#define yynoreturn __attribute__((__noreturn__)) -#else -#define yynoreturn -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an - * integer in range [0..255] for use as an array index. - */ -#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN (yy_start) = 1 + 2 * -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START (((yy_start) - 1) / 2) -#define YYSTATE YY_START -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart( yyin ) -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k. - * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. - * Ditto for the __ia64__ case accordingly. - */ -#define YY_BUF_SIZE 32768 -#else -#define YY_BUF_SIZE 16384 -#endif /* __ia64__ */ -#endif - -/* The state buf must be large enough to hold one state per character in the main buffer. - */ -#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; -#endif - -extern int yyleng; - -extern FILE *yyin, *yyout; - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - - #define YY_LESS_LINENO(n) - #define YY_LINENO_REWIND_TO(ptr) - -/* Return all but the first "n" matched characters back to the input stream. */ -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - *yy_cp = (yy_hold_char); \ - YY_RESTORE_YY_MORE_OFFSET \ - (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) -#define unput(c) yyunput( c, (yytext_ptr) ) - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - int yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -/* Stack of input buffers. */ -static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ -static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ -static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - * - * Returns the top of the stack, or NULL. - */ -#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ - ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ - : NULL) -/* Same as previous macro, but useful when we know that the buffer stack is not - * NULL or when we need an lvalue. For internal use only. - */ -#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] - -/* yy_hold_char holds the character lost when yytext is formed. */ -static char yy_hold_char; -static int yy_n_chars; /* number of characters read into yy_ch_buf */ -int yyleng; - -/* Points to current character in buffer. */ -static char *yy_c_buf_p = NULL; -static int yy_init = 0; /* whether we need to initialize */ -static int yy_start = 0; /* start state number */ - -/* Flag which is used to allow yywrap()'s to do buffer switches - * instead of setting up a fresh yyin. A bit of a hack ... - */ -static int yy_did_buffer_switch_on_eof; - -void yyrestart ( FILE *input_file ); -void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); -YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); -void yy_delete_buffer ( YY_BUFFER_STATE b ); -void yy_flush_buffer ( YY_BUFFER_STATE b ); -void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); -void yypop_buffer_state ( void ); - -static void yyensure_buffer_stack ( void ); -static void yy_load_buffer_state ( void ); -static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); -#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) - -YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); -YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); -YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); - -void *yyalloc ( yy_size_t ); -void *yyrealloc ( void *, yy_size_t ); -void yyfree ( void * ); - -#define yy_new_buffer yy_create_buffer -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! YY_CURRENT_BUFFER ){ \ - yyensure_buffer_stack (); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer( yyin, YY_BUF_SIZE ); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ - } -#define yy_set_bol(at_bol) \ - { \ - if ( ! YY_CURRENT_BUFFER ){\ - yyensure_buffer_stack (); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer( yyin, YY_BUF_SIZE ); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ - } -#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) - -/* Begin user sect3 */ - -#define xbt_automaton_parser_wrap() (/*CONSTCOND*/1) -#define YY_SKIP_YYWRAP -typedef flex_uint8_t YY_CHAR; - -FILE *yyin = NULL, *yyout = NULL; - -typedef int yy_state_type; - -extern int yylineno; -int yylineno = 1; - -extern char *yytext; -#ifdef yytext_ptr -#undef yytext_ptr -#endif -#define yytext_ptr yytext - -static yy_state_type yy_get_previous_state ( void ); -static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); -static int yy_get_next_buffer ( void ); -static void yynoreturn yy_fatal_error ( const char* msg ); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - (yytext_ptr) = yy_bp; \ - yyleng = (int) (yy_cp - yy_bp); \ - (yy_hold_char) = *yy_cp; \ - *yy_cp = '\0'; \ - (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 25 -#define YY_END_OF_BUFFER 26 -/* This struct is not used in this scanner, - but its presence is necessary. */ -struct yy_trans_info - { - flex_int32_t yy_verify; - flex_int32_t yy_nxt; - }; -static const flex_int16_t yy_accept[54] = - { 0, - 0, 0, 26, 24, 18, 23, 8, 24, 24, 9, - 10, 24, 24, 20, 14, 12, 13, 22, 22, 22, - 22, 22, 15, 24, 16, 18, 0, 0, 21, 0, - 6, 4, 0, 0, 20, 11, 22, 3, 22, 2, - 22, 7, 0, 0, 0, 19, 22, 22, 17, 5, - 22, 1, 0 - } ; - -static const YY_CHAR yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 4, 5, 6, 1, 1, 1, 7, 1, 8, - 9, 10, 1, 1, 11, 12, 13, 14, 15, 14, - 14, 14, 14, 14, 14, 14, 14, 16, 17, 1, - 1, 18, 1, 1, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 1, 20, 1, 1, 21, 1, 19, 19, 19, 19, - - 22, 23, 24, 19, 25, 19, 19, 19, 19, 26, - 27, 19, 19, 28, 19, 29, 19, 30, 19, 19, - 19, 19, 31, 32, 33, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - } ; - -static const YY_CHAR yy_meta[34] = - { 0, - 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, - 1, 1, 3, 4, 4, 1, 1, 1, 4, 2, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 1, 1, 1 - } ; - -static const flex_int16_t yy_base[57] = - { 0, - 0, 0, 89, 90, 32, 90, 90, 34, 81, 90, - 90, 69, 76, 27, 31, 69, 90, 0, 59, 56, - 58, 55, 90, 42, 90, 45, 47, 0, 0, 0, - 90, 90, 52, 43, 49, 90, 0, 0, 44, 0, - 42, 90, 56, 65, 52, 56, 25, 26, 90, 0, - 16, 0, 90, 74, 31, 78 - } ; - -static const flex_int16_t yy_def[57] = - { 0, - 53, 1, 53, 53, 53, 53, 53, 54, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 55, 55, 55, - 55, 55, 53, 53, 53, 53, 54, 27, 27, 27, - 53, 53, 56, 53, 53, 53, 55, 55, 55, 55, - 55, 53, 56, 56, 53, 53, 55, 55, 53, 55, - 55, 55, 0, 53, 53, 53 - } ; - -static const flex_int16_t yy_nxt[124] = - { 0, - 4, 5, 6, 5, 7, 8, 9, 10, 11, 4, - 12, 4, 13, 14, 15, 16, 17, 4, 18, 4, - 4, 18, 19, 20, 21, 22, 18, 18, 18, 18, - 23, 24, 25, 26, 37, 26, 27, 28, 34, 29, - 35, 35, 34, 52, 35, 35, 26, 51, 26, 27, - 28, 50, 29, 27, 44, 44, 46, 46, 44, 44, - 34, 45, 35, 35, 49, 45, 27, 44, 44, 46, - 46, 48, 47, 42, 45, 30, 41, 30, 43, 43, - 40, 43, 39, 38, 36, 33, 32, 31, 53, 3, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53 - } ; - -static const flex_int16_t yy_chk[124] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 5, 55, 5, 8, 8, 14, 8, - 14, 14, 15, 51, 15, 15, 26, 48, 26, 27, - 27, 47, 27, 8, 33, 33, 34, 34, 43, 43, - 35, 33, 35, 35, 45, 43, 27, 44, 44, 46, - 46, 41, 39, 24, 44, 54, 22, 54, 56, 56, - 21, 56, 20, 19, 16, 13, 12, 9, 3, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53 - } ; - -static yy_state_type yy_last_accepting_state; -static char *yy_last_accepting_cpos; - -extern int yy_flex_debug; -int yy_flex_debug = 0; - -/* The intent behind this definition is that it'll catch - * any uses of REJECT which flex missed. - */ -#define REJECT reject_used_but_not_detected -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -char *yytext; -#line 1 "parserPromela.lex" -/* Copyright (c) 2012-2023. 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. */ -#line 10 "parserPromela.lex" - -#include "simgrid/config.h" -#if !HAVE_UNISTD_H -#define YY_NO_UNISTD_H /* hello Windows */ -#endif - -#include -#include "parserPromela.tab.hacc" - - extern YYSTYPE yylval; - -#line 764 "automaton_lexer.yy.c" -#line 765 "automaton_lexer.yy.c" - -#define INITIAL 0 - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include -#endif - -#ifndef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#endif - -static int yy_init_globals ( void ); - -/* Accessor methods to globals. - These are made visible to non-reentrant scanners for convenience. */ - -int yylex_destroy ( void ); - -int yyget_debug ( void ); - -void yyset_debug ( int debug_flag ); - -YY_EXTRA_TYPE yyget_extra ( void ); - -void yyset_extra ( YY_EXTRA_TYPE user_defined ); - -FILE *yyget_in ( void ); - -void yyset_in ( FILE * _in_str ); - -FILE *yyget_out ( void ); - -void yyset_out ( FILE * _out_str ); - - int yyget_leng ( void ); - -char *yyget_text ( void ); - -int yyget_lineno ( void ); - -void yyset_lineno ( int _line_number ); - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap ( void ); -#else -extern int yywrap ( void ); -#endif -#endif - -#ifndef YY_NO_UNPUT - - static void yyunput ( int c, char *buf_ptr ); - -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy ( char *, const char *, int ); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen ( const char * ); -#endif - -#ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput ( void ); -#else -static int input ( void ); -#endif - -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k */ -#define YY_READ_BUF_SIZE 16384 -#else -#define YY_READ_BUF_SIZE 8192 -#endif /* __ia64__ */ -#endif - -/* Copy whatever the last rule matched to the standard output. */ -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ - { \ - int c = '*'; \ - int n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else \ - { \ - errno=0; \ - while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ - { \ - if( errno != EINTR) \ - { \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - break; \ - } \ - errno=0; \ - clearerr(yyin); \ - } \ - }\ -\ - -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) -#endif - -/* end tables serialization structures and prototypes */ - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int yylex (void); - -#define YY_DECL int yylex (void) -#endif /* !YY_DECL */ - -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK /*LINTED*/break; -#endif - -#define YY_RULE_SETUP \ - YY_USER_ACTION - -/** The main scanner function which does all the work. - */ -YY_DECL -{ - yy_state_type yy_current_state; - char *yy_cp, *yy_bp; - int yy_act; - - if ( !(yy_init) ) - { - (yy_init) = 1; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! (yy_start) ) - (yy_start) = 1; /* first start state */ - - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! YY_CURRENT_BUFFER ) { - yyensure_buffer_stack (); - YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer( yyin, YY_BUF_SIZE ); - } - - yy_load_buffer_state( ); - } - - { -#line 38 "parserPromela.lex" - - -#line 985 "automaton_lexer.yy.c" - - while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ - { - yy_cp = (yy_c_buf_p); - - /* Support of yytext. */ - *yy_cp = (yy_hold_char); - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = (yy_start); -yy_match: - do - { - YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; - if ( yy_accept[yy_current_state] ) - { - (yy_last_accepting_state) = yy_current_state; - (yy_last_accepting_cpos) = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 54 ) - yy_c = yy_meta[yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - ++yy_cp; - } - while ( yy_base[yy_current_state] != 90 ); - -yy_find_action: - yy_act = yy_accept[yy_current_state]; - if ( yy_act == 0 ) - { /* have to back up */ - yy_cp = (yy_last_accepting_cpos); - yy_current_state = (yy_last_accepting_state); - yy_act = yy_accept[yy_current_state]; - } - - YY_DO_BEFORE_ACTION; - -do_action: /* This label is used only to access EOF actions. */ - - switch ( yy_act ) - { /* beginning of action switch */ - case 0: /* must back up */ - /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = (yy_hold_char); - yy_cp = (yy_last_accepting_cpos); - yy_current_state = (yy_last_accepting_state); - goto yy_find_action; - -case 1: -YY_RULE_SETUP -#line 40 "parserPromela.lex" -{ return (NEVER); } - YY_BREAK -case 2: -YY_RULE_SETUP -#line 41 "parserPromela.lex" -{ return (IF); } - YY_BREAK -case 3: -YY_RULE_SETUP -#line 42 "parserPromela.lex" -{ return (FI); } - YY_BREAK -case 4: -YY_RULE_SETUP -#line 43 "parserPromela.lex" -{ return (IMPLIES); } - YY_BREAK -case 5: -YY_RULE_SETUP -#line 44 "parserPromela.lex" -{ return (GOTO); } - YY_BREAK -case 6: -YY_RULE_SETUP -#line 45 "parserPromela.lex" -{ return (AND); } - YY_BREAK -case 7: -YY_RULE_SETUP -#line 46 "parserPromela.lex" -{ return (OR); } - YY_BREAK -case 8: -YY_RULE_SETUP -#line 47 "parserPromela.lex" -{ return (NOT); } - YY_BREAK -case 9: -YY_RULE_SETUP -#line 48 "parserPromela.lex" -{ return (LEFT_PAR); } - YY_BREAK -case 10: -YY_RULE_SETUP -#line 49 "parserPromela.lex" -{ return (RIGHT_PAR); } - YY_BREAK -case 11: -YY_RULE_SETUP -#line 50 "parserPromela.lex" -{ return (CASE); } - YY_BREAK -case 12: -YY_RULE_SETUP -#line 51 "parserPromela.lex" -{ return (COLON); } - YY_BREAK -case 13: -YY_RULE_SETUP -#line 52 "parserPromela.lex" -{ return (SEMI_COLON); } - YY_BREAK -case 14: -YY_RULE_SETUP -#line 53 "parserPromela.lex" -{ return (CASE_TRUE); } - YY_BREAK -case 15: -YY_RULE_SETUP -#line 54 "parserPromela.lex" -{ return (LEFT_BRACE); } - YY_BREAK -case 16: -YY_RULE_SETUP -#line 55 "parserPromela.lex" -{ return (RIGHT_BRACE); } - YY_BREAK -case 17: -/* rule 17 can match eol */ -YY_RULE_SETUP -#line 58 "parserPromela.lex" -{ } - YY_BREAK -case 18: -YY_RULE_SETUP -#line 60 "parserPromela.lex" -{ } - YY_BREAK -case 19: -YY_RULE_SETUP -#line 63 "parserPromela.lex" -{ sscanf(yytext,"%lf",&yylval.real); - return (LITT_REEL); } - YY_BREAK -case 20: -YY_RULE_SETUP -#line 66 "parserPromela.lex" -{ sscanf(yytext,"%d",&yylval.integer); - return (LITT_ENT); } - YY_BREAK -case 21: -/* rule 21 can match eol */ -YY_RULE_SETUP -#line 69 "parserPromela.lex" -{ yylval.string=(char *)malloc(strlen(yytext)+1); - sscanf(yytext,"%s",yylval.string); - return (LITT_CHAINE); } - YY_BREAK -case 22: -YY_RULE_SETUP -#line 73 "parserPromela.lex" -{ yylval.string=(char *)malloc(strlen(yytext)+1); - sscanf(yytext,"%s",yylval.string); - return (ID); } - YY_BREAK -case 23: -/* rule 23 can match eol */ -YY_RULE_SETUP -#line 77 "parserPromela.lex" -{ } - YY_BREAK -case 24: -YY_RULE_SETUP -#line 79 "parserPromela.lex" -{ } - YY_BREAK -case 25: -YY_RULE_SETUP -#line 81 "parserPromela.lex" -ECHO; - YY_BREAK -#line 1176 "automaton_lexer.yy.c" -case YY_STATE_EOF(INITIAL): - yyterminate(); - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = (yy_hold_char); - YY_RESTORE_YY_MORE_OFFSET - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between YY_CURRENT_BUFFER and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( ); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state ); - - yy_bp = (yytext_ptr) + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++(yy_c_buf_p); - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = (yy_c_buf_p); - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer( ) ) - { - case EOB_ACT_END_OF_FILE: - { - (yy_did_buffer_switch_on_eof) = 0; - - if ( yywrap( ) ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! (yy_did_buffer_switch_on_eof) ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - (yy_c_buf_p) = - (yytext_ptr) + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( ); - - yy_cp = (yy_c_buf_p); - yy_bp = (yytext_ptr) + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - (yy_c_buf_p) = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; - - yy_current_state = yy_get_previous_state( ); - - yy_cp = (yy_c_buf_p); - yy_bp = (yytext_ptr) + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ - } /* end of user's declarations */ -} /* end of yylex */ - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ -static int yy_get_next_buffer (void) -{ - char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - char *source = (yytext_ptr); - int number_to_move, i; - int ret_val; - - if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; - - else - { - int num_to_read = - YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; - - int yy_c_buf_p_offset = - (int) ((yy_c_buf_p) - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - yyrealloc( (void *) b->yy_ch_buf, - (yy_size_t) (b->yy_buf_size + 2) ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = NULL; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - - number_to_move - 1; - - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - (yy_n_chars), num_to_read ); - - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); - } - - if ( (yy_n_chars) == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - yyrestart( yyin ); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { - /* Extend the array by 50%, plus the number we really need. */ - int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( - (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); - if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); - /* "- 2" to take care of EOB's */ - YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); - } - - (yy_n_chars) += number_to_move; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; - - (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; - - return ret_val; -} - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - - static yy_state_type yy_get_previous_state (void) -{ - yy_state_type yy_current_state; - char *yy_cp; - - yy_current_state = (yy_start); - - for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) - { - YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); - if ( yy_accept[yy_current_state] ) - { - (yy_last_accepting_state) = yy_current_state; - (yy_last_accepting_cpos) = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 54 ) - yy_c = yy_meta[yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - } - - return yy_current_state; -} - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) -{ - int yy_is_jam; - char *yy_cp = (yy_c_buf_p); - - YY_CHAR yy_c = 1; - if ( yy_accept[yy_current_state] ) - { - (yy_last_accepting_state) = yy_current_state; - (yy_last_accepting_cpos) = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 54 ) - yy_c = yy_meta[yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 53); - - return yy_is_jam ? 0 : yy_current_state; -} - -#ifndef YY_NO_UNPUT - - static void yyunput (int c, char * yy_bp ) -{ - char *yy_cp; - - yy_cp = (yy_c_buf_p); - - /* undo effects of setting up yytext */ - *yy_cp = (yy_hold_char); - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - int number_to_move = (yy_n_chars) + 2; - char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ - YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; - char *source = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; - - while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = - (yy_n_chars) = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); - } - - *--yy_cp = (char) c; - - (yytext_ptr) = yy_bp; - (yy_hold_char) = *yy_cp; - (yy_c_buf_p) = yy_cp; -} - -#endif - -#ifndef YY_NO_INPUT -#ifdef __cplusplus - static int yyinput (void) -#else - static int input (void) -#endif - -{ - int c; - - *(yy_c_buf_p) = (yy_hold_char); - - if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) - /* This was really a NUL. */ - *(yy_c_buf_p) = '\0'; - - else - { /* need more input */ - int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); - ++(yy_c_buf_p); - - switch ( yy_get_next_buffer( ) ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - yyrestart( yyin ); - - /*FALLTHROUGH*/ - - case EOB_ACT_END_OF_FILE: - { - if ( yywrap( ) ) - return 0; - - if ( ! (yy_did_buffer_switch_on_eof) ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(); -#else - return input(); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - (yy_c_buf_p) = (yytext_ptr) + offset; - break; - } - } - } - - c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ - *(yy_c_buf_p) = '\0'; /* preserve yytext */ - (yy_hold_char) = *++(yy_c_buf_p); - - return c; -} -#endif /* ifndef YY_NO_INPUT */ - -/** Immediately switch to a different input stream. - * @param input_file A readable stream. - * - * @note This function does not reset the start condition to @c INITIAL . - */ - void yyrestart (FILE * input_file ) -{ - - if ( ! YY_CURRENT_BUFFER ){ - yyensure_buffer_stack (); - YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer( yyin, YY_BUF_SIZE ); - } - - yy_init_buffer( YY_CURRENT_BUFFER, input_file ); - yy_load_buffer_state( ); -} - -/** Switch to a different input buffer. - * @param new_buffer The new input buffer. - * - */ - void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) -{ - - /* TODO. We should be able to replace this entire function body - * with - * yypop_buffer_state(); - * yypush_buffer_state(new_buffer); - */ - yyensure_buffer_stack (); - if ( YY_CURRENT_BUFFER == new_buffer ) - return; - - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *(yy_c_buf_p) = (yy_hold_char); - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); - } - - YY_CURRENT_BUFFER_LVALUE = new_buffer; - yy_load_buffer_state( ); - - /* We don't actually know whether we did this switch during - * EOF (yywrap()) processing, but the only time this flag - * is looked at is after yywrap() is called, so it's safe - * to go ahead and always set it. - */ - (yy_did_buffer_switch_on_eof) = 1; -} - -static void yy_load_buffer_state (void) -{ - (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; - yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; - (yy_hold_char) = *(yy_c_buf_p); -} - -/** Allocate and initialize an input buffer state. - * @param file A readable stream. - * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. - * - * @return the allocated buffer state. - */ - YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) -{ - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - yy_init_buffer( b, file ); - - return b; -} - -/** Destroy the buffer. - * @param b a buffer created with yy_create_buffer() - * - */ - void yy_delete_buffer (YY_BUFFER_STATE b ) -{ - - if ( ! b ) - return; - - if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ - YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - yyfree( (void *) b->yy_ch_buf ); - - yyfree( (void *) b ); -} - -/* Initializes or reinitializes a buffer. - * This function is sometimes called more than once on the same buffer, - * such as during a yyrestart() or at EOF. - */ - static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) - -{ - int oerrno = errno; - - yy_flush_buffer( b ); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - - /* If b is the current buffer, then yy_init_buffer was _probably_ - * called from yyrestart() or through yy_get_next_buffer. - * In that case, we don't want to reset the lineno or column. - */ - if (b != YY_CURRENT_BUFFER){ - b->yy_bs_lineno = 1; - b->yy_bs_column = 0; - } - - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; - - errno = oerrno; -} - -/** Discard all buffered characters. On the next scan, YY_INPUT will be called. - * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. - * - */ - void yy_flush_buffer (YY_BUFFER_STATE b ) -{ - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == YY_CURRENT_BUFFER ) - yy_load_buffer_state( ); -} - -/** Pushes the new state onto the stack. The new state becomes - * the current state. This function will allocate the stack - * if necessary. - * @param new_buffer The new state. - * - */ -void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) -{ - if (new_buffer == NULL) - return; - - yyensure_buffer_stack(); - - /* This block is copied from yy_switch_to_buffer. */ - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *(yy_c_buf_p) = (yy_hold_char); - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); - } - - /* Only push if top exists. Otherwise, replace top. */ - if (YY_CURRENT_BUFFER) - (yy_buffer_stack_top)++; - YY_CURRENT_BUFFER_LVALUE = new_buffer; - - /* copied from yy_switch_to_buffer. */ - yy_load_buffer_state( ); - (yy_did_buffer_switch_on_eof) = 1; -} - -/** Removes and deletes the top of the stack, if present. - * The next element becomes the new top. - * - */ -void yypop_buffer_state (void) -{ - if (!YY_CURRENT_BUFFER) - return; - - yy_delete_buffer(YY_CURRENT_BUFFER ); - YY_CURRENT_BUFFER_LVALUE = NULL; - if ((yy_buffer_stack_top) > 0) - --(yy_buffer_stack_top); - - if (YY_CURRENT_BUFFER) { - yy_load_buffer_state( ); - (yy_did_buffer_switch_on_eof) = 1; - } -} - -/* Allocates the stack if it does not exist. - * Guarantees space for at least one push. - */ -static void yyensure_buffer_stack (void) -{ - yy_size_t num_to_alloc; - - if (!(yy_buffer_stack)) { - - /* First allocation is just for 2 elements, since we don't know if this - * scanner will even need a stack. We use 2 instead of 1 to avoid an - * immediate realloc on the next call. - */ - num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ - (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc - (num_to_alloc * sizeof(struct yy_buffer_state*) - ); - if ( ! (yy_buffer_stack) ) - YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - - memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - - (yy_buffer_stack_max) = num_to_alloc; - (yy_buffer_stack_top) = 0; - return; - } - - if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ - - /* Increase the buffer to prepare for a possible push. */ - yy_size_t grow_size = 8 /* arbitrary grow size */; - - num_to_alloc = (yy_buffer_stack_max) + grow_size; - (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc - ((yy_buffer_stack), - num_to_alloc * sizeof(struct yy_buffer_state*) - ); - if ( ! (yy_buffer_stack) ) - YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - - /* zero only the new slots.*/ - memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); - (yy_buffer_stack_max) = num_to_alloc; - } -} - -/** Setup the input buffer state to scan directly from a user-specified character buffer. - * @param base the character buffer - * @param size the size in bytes of the character buffer - * - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) -{ - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return NULL; - - b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); - - b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = NULL; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - yy_switch_to_buffer( b ); - - return b; -} - -/** Setup the input buffer state to scan a string. The next call to yylex() will - * scan from a @e copy of @a str. - * @param yystr a NUL-terminated string to scan - * - * @return the newly allocated buffer state object. - * @note If you want to scan bytes that may contain NUL values, then use - * yy_scan_bytes() instead. - */ -YY_BUFFER_STATE yy_scan_string (const char * yystr ) -{ - - return yy_scan_bytes( yystr, (int) strlen(yystr) ); -} - -/** Setup the input buffer state to scan the given bytes. The next call to yylex() will - * scan from a @e copy of @a bytes. - * @param yybytes the byte buffer to scan - * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. - * - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) -{ - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = (yy_size_t) (_yybytes_len + 2); - buf = (char *) yyalloc( n ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - - for ( i = 0; i < _yybytes_len; ++i ) - buf[i] = yybytes[i]; - - buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; - - b = yy_scan_buffer( buf, n ); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; -} - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -static void yynoreturn yy_fatal_error (const char* msg ) -{ - fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); -} - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - yytext[yyleng] = (yy_hold_char); \ - (yy_c_buf_p) = yytext + yyless_macro_arg; \ - (yy_hold_char) = *(yy_c_buf_p); \ - *(yy_c_buf_p) = '\0'; \ - yyleng = yyless_macro_arg; \ - } \ - while ( 0 ) - -/* Accessor methods (get/set functions) to struct members. */ - -/** Get the current line number. - * - */ -int yyget_lineno (void) -{ - - return yylineno; -} - -/** Get the input stream. - * - */ -FILE *yyget_in (void) -{ - return yyin; -} - -/** Get the output stream. - * - */ -FILE *yyget_out (void) -{ - return yyout; -} - -/** Get the length of the current token. - * - */ -int yyget_leng (void) -{ - return yyleng; -} - -/** Get the current token. - * - */ - -char *yyget_text (void) -{ - return yytext; -} - -/** Set the current line number. - * @param _line_number line number - * - */ -void yyset_lineno (int _line_number ) -{ - - yylineno = _line_number; -} - -/** Set the input stream. This does not discard the current - * input buffer. - * @param _in_str A readable stream. - * - * @see yy_switch_to_buffer - */ -void yyset_in (FILE * _in_str ) -{ - yyin = _in_str ; -} - -void yyset_out (FILE * _out_str ) -{ - yyout = _out_str ; -} - -int yyget_debug (void) -{ - return yy_flex_debug; -} - -void yyset_debug (int _bdebug ) -{ - yy_flex_debug = _bdebug ; -} - -static int yy_init_globals (void) -{ - /* Initialization is the same as for the non-reentrant scanner. - * This function is called from yylex_destroy(), so don't allocate here. - */ - - (yy_buffer_stack) = NULL; - (yy_buffer_stack_top) = 0; - (yy_buffer_stack_max) = 0; - (yy_c_buf_p) = NULL; - (yy_init) = 0; - (yy_start) = 0; - -/* Defined in main.c */ -#ifdef YY_STDINIT - yyin = stdin; - yyout = stdout; -#else - yyin = NULL; - yyout = NULL; -#endif - - /* For future reference: Set errno on error, since we are called by - * yylex_init() - */ - return 0; -} - -/* yylex_destroy is for both reentrant and non-reentrant scanners. */ -int yylex_destroy (void) -{ - - /* Pop the buffer stack, destroying each element. */ - while(YY_CURRENT_BUFFER){ - yy_delete_buffer( YY_CURRENT_BUFFER ); - YY_CURRENT_BUFFER_LVALUE = NULL; - yypop_buffer_state(); - } - - /* Destroy the stack itself. */ - yyfree((yy_buffer_stack) ); - (yy_buffer_stack) = NULL; - - /* Reset the globals. This is important in a non-reentrant scanner so the next time - * yylex() is called, initialization will occur. */ - yy_init_globals( ); - - return 0; -} - -/* - * Internal utility routines. - */ - -#ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, const char * s2, int n ) -{ - - int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; -} -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (const char * s ) -{ - int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; -} -#endif - -void *yyalloc (yy_size_t size ) -{ - return malloc(size); -} - -void *yyrealloc (void * ptr, yy_size_t size ) -{ - - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return realloc(ptr, size); -} - -void yyfree (void * ptr ) -{ - free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ -} - -#define YYTABLES_NAME "yytables" - -#line 81 "parserPromela.lex" - - - - diff --git a/src/xbt/automaton/automatonparse_promela.c b/src/xbt/automaton/automatonparse_promela.c deleted file mode 100644 index 4fad698eb5..0000000000 --- a/src/xbt/automaton/automatonparse_promela.c +++ /dev/null @@ -1,70 +0,0 @@ -/* methods for implementation of automaton from promela description */ - -/* Copyright (c) 2011-2023. 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 "src/internal_config.h" -#include "xbt/automaton.h" -#include -#include /* strerror */ -#if HAVE_UNISTD_H -# include /* isatty */ -#endif -#include - -#include "parserPromela.tab.cacc" - -static xbt_automaton_t parsed_automaton; -char* state_id_src; - -static void new_state(const char* id, int src) -{ - char* saveptr = NULL; // for strtok_r() - char* id_copy = xbt_strdup(id); - const char* first_part = strtok_r(id_copy, "_", &saveptr); - int type = 0 ; // -1=initial state; 0=intermediate state; 1=final state - - if(strcmp(first_part,"accept")==0){ - type = 1; - }else{ - const char* second_part = strtok_r(NULL, "_", &saveptr); - if(strcmp(second_part,"init")==0){ - type = -1; - } - } - xbt_free(id_copy); - - xbt_automaton_state_t state = xbt_automaton_state_exists(parsed_automaton, id); - if(state == NULL){ - state = xbt_automaton_state_new(parsed_automaton, type, id); - } - - if(type==-1) - parsed_automaton->current_state = state; - - if(src) { - xbt_free(state_id_src); - state_id_src = xbt_strdup(id); - } -} - -static void new_transition(const char* id, xbt_automaton_exp_label_t label) -{ - new_state(id, 0); - xbt_automaton_state_t state_dst = xbt_automaton_state_exists(parsed_automaton, id); - xbt_automaton_state_t state_src = xbt_automaton_state_exists(parsed_automaton, state_id_src); - - xbt_automaton_transition_new(parsed_automaton, state_src, state_dst, label); - -} - -void xbt_automaton_load(xbt_automaton_t a, const char *file) -{ - parsed_automaton = a; - xbt_automaton_parser_in = fopen(file, "r"); - xbt_assert(xbt_automaton_parser_in != NULL, "Failed to open automaton file `%s': %s", file, strerror(errno)); - xbt_automaton_parser_parse(); - fclose(xbt_automaton_parser_in); -} diff --git a/src/xbt/automaton/parserPromela.lex b/src/xbt/automaton/parserPromela.lex deleted file mode 100644 index 461c3237c0..0000000000 --- a/src/xbt/automaton/parserPromela.lex +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (c) 2012-2023. 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. */ - -%option noyywrap - -%{ - -#include "simgrid/config.h" -#if !HAVE_UNISTD_H -#define YY_NO_UNISTD_H /* hello Windows */ -#endif - -#include -#include "parserPromela.tab.hacc" - - extern YYSTYPE yylval; - -%} - -blancs [ \t]+ -espace [ ]+ -nouv_ligne [ \n] - -chiffre [0-9] -entier {chiffre}+ -reel {entier}("."{entier}) -caractere [a-zA-Z0-9_] - -numl \n - -chaine \"({caractere}*|\n|\\|\"|{espace}*)*\" - -commentaire "/*"([^\*\/]*{nouv_ligne}*[^\*\/]*)*"*/" - -%% - -"never" { return (NEVER); } -"if" { return (IF); } -"fi" { return (FI); } -"->" { return (IMPLIES); } -"goto" { return (GOTO); } -"&&" { return (AND); } -"||" { return (OR); } -"!" { return (NOT); } -"(" { return (LEFT_PAR); } -")" { return (RIGHT_PAR); } -"::" { return (CASE); } -":" { return (COLON); } -";" { return (SEMI_COLON); } -"1" { return (CASE_TRUE); } -"{" { return (LEFT_BRACE); } -"}" { return (RIGHT_BRACE); } - - -{commentaire} { } - -{blancs} { } - - -{reel} { sscanf(yytext,"%lf",&yylval.real); - return (LITT_REEL); } - -{entier} { sscanf(yytext,"%d",&yylval.integer); - return (LITT_ENT); } - -{chaine} { yylval.string=(char *)malloc(strlen(yytext)+1); - sscanf(yytext,"%s",yylval.string); - return (LITT_CHAINE); } - -[a-zA-Z]{caractere}* { yylval.string=(char *)malloc(strlen(yytext)+1); - sscanf(yytext,"%s",yylval.string); - return (ID); } - -{numl} { } - -. { } - -%% - - diff --git a/src/xbt/automaton/parserPromela.tab.cacc b/src/xbt/automaton/parserPromela.tab.cacc deleted file mode 100644 index 776faa8fe4..0000000000 --- a/src/xbt/automaton/parserPromela.tab.cacc +++ /dev/null @@ -1,1364 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.8.2. */ - -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, - Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, - especially those whose name start with YY_ or yy_. They are - private implementation details that can be changed or removed. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output, and Bison version. */ -#define YYBISON 30802 - -/* Bison version string. */ -#define YYBISON_VERSION "3.8.2" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 0 - -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - - -/* Substitute the variable and function names. */ -#define yyparse xbt_automaton_parser_parse -#define yylex xbt_automaton_parser_lex -#define yyerror xbt_automaton_parser_error -#define yydebug xbt_automaton_parser_debug -#define yynerrs xbt_automaton_parser_nerrs -#define yylval xbt_automaton_parser_lval -#define yychar xbt_automaton_parser_char - -/* First part of user prologue. */ -#line 7 "parserPromela.yacc" - -#include "simgrid/config.h" -#if !HAVE_UNISTD_H -#define YY_NO_UNISTD_H /* hello Windows */ -#endif - -#include "automaton_lexer.yy.c" -#include - -void yyerror(const char *s); - -static void new_state(const char* id, int src); -static void new_transition(const char* id, xbt_automaton_exp_label_t label); - - -#line 94 "parserPromela.tab.cacc" - -# ifndef YY_CAST -# ifdef __cplusplus -# define YY_CAST(Type, Val) static_cast (Val) -# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) -# else -# define YY_CAST(Type, Val) ((Type) (Val)) -# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) -# endif -# endif -# ifndef YY_NULLPTR -# if defined __cplusplus -# if 201103L <= __cplusplus -# define YY_NULLPTR nullptr -# else -# define YY_NULLPTR 0 -# endif -# else -# define YY_NULLPTR ((void*)0) -# endif -# endif - -#include "parserPromela.tab.hacc" -/* Symbol kind. */ -enum yysymbol_kind_t -{ - YYSYMBOL_YYEMPTY = -2, - YYSYMBOL_YYEOF = 0, /* "end of file" */ - YYSYMBOL_YYerror = 1, /* error */ - YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ - YYSYMBOL_NEVER = 3, /* NEVER */ - YYSYMBOL_IF = 4, /* IF */ - YYSYMBOL_FI = 5, /* FI */ - YYSYMBOL_IMPLIES = 6, /* IMPLIES */ - YYSYMBOL_GOTO = 7, /* GOTO */ - YYSYMBOL_AND = 8, /* AND */ - YYSYMBOL_OR = 9, /* OR */ - YYSYMBOL_NOT = 10, /* NOT */ - YYSYMBOL_LEFT_PAR = 11, /* LEFT_PAR */ - YYSYMBOL_RIGHT_PAR = 12, /* RIGHT_PAR */ - YYSYMBOL_CASE = 13, /* CASE */ - YYSYMBOL_COLON = 14, /* COLON */ - YYSYMBOL_SEMI_COLON = 15, /* SEMI_COLON */ - YYSYMBOL_CASE_TRUE = 16, /* CASE_TRUE */ - YYSYMBOL_LEFT_BRACE = 17, /* LEFT_BRACE */ - YYSYMBOL_RIGHT_BRACE = 18, /* RIGHT_BRACE */ - YYSYMBOL_LITT_ENT = 19, /* LITT_ENT */ - YYSYMBOL_LITT_CHAINE = 20, /* LITT_CHAINE */ - YYSYMBOL_LITT_REEL = 21, /* LITT_REEL */ - YYSYMBOL_ID = 22, /* ID */ - YYSYMBOL_YYACCEPT = 23, /* $accept */ - YYSYMBOL_automaton = 24, /* automaton */ - YYSYMBOL_stateseq = 25, /* stateseq */ - YYSYMBOL_26_1 = 26, /* $@1 */ - YYSYMBOL_option = 27, /* option */ - YYSYMBOL_exp = 28 /* exp */ -}; -typedef enum yysymbol_kind_t yysymbol_kind_t; - - - - -#ifdef short -# undef short -#endif - -/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure - and (if available) are included - so that the code can choose integer types of a good width. */ - -#ifndef __PTRDIFF_MAX__ -# include /* INFRINGES ON USER NAME SPACE */ -# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_STDINT_H -# endif -#endif - -/* Narrow types that promote to a signed type and that can represent a - signed or unsigned integer of at least N bits. In tables they can - save space and decrease cache pressure. Promoting to a signed type - helps avoid bugs in integer arithmetic. */ - -#ifdef __INT_LEAST8_MAX__ -typedef __INT_LEAST8_TYPE__ yytype_int8; -#elif defined YY_STDINT_H -typedef int_least8_t yytype_int8; -#else -typedef signed char yytype_int8; -#endif - -#ifdef __INT_LEAST16_MAX__ -typedef __INT_LEAST16_TYPE__ yytype_int16; -#elif defined YY_STDINT_H -typedef int_least16_t yytype_int16; -#else -typedef short yytype_int16; -#endif - -/* Work around bug in HP-UX 11.23, which defines these macros - incorrectly for preprocessor constants. This workaround can likely - be removed in 2023, as HPE has promised support for HP-UX 11.23 - (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of - . */ -#ifdef __hpux -# undef UINT_LEAST8_MAX -# undef UINT_LEAST16_MAX -# define UINT_LEAST8_MAX 255 -# define UINT_LEAST16_MAX 65535 -#endif - -#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ -typedef __UINT_LEAST8_TYPE__ yytype_uint8; -#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ - && UINT_LEAST8_MAX <= INT_MAX) -typedef uint_least8_t yytype_uint8; -#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX -typedef unsigned char yytype_uint8; -#else -typedef short yytype_uint8; -#endif - -#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ -typedef __UINT_LEAST16_TYPE__ yytype_uint16; -#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ - && UINT_LEAST16_MAX <= INT_MAX) -typedef uint_least16_t yytype_uint16; -#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX -typedef unsigned short yytype_uint16; -#else -typedef int yytype_uint16; -#endif - -#ifndef YYPTRDIFF_T -# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ -# define YYPTRDIFF_T __PTRDIFF_TYPE__ -# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ -# elif defined PTRDIFF_MAX -# ifndef ptrdiff_t -# include /* INFRINGES ON USER NAME SPACE */ -# endif -# define YYPTRDIFF_T ptrdiff_t -# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX -# else -# define YYPTRDIFF_T long -# define YYPTRDIFF_MAXIMUM LONG_MAX -# endif -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned -# endif -#endif - -#define YYSIZE_MAXIMUM \ - YY_CAST (YYPTRDIFF_T, \ - (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ - ? YYPTRDIFF_MAXIMUM \ - : YY_CAST (YYSIZE_T, -1))) - -#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) - - -/* Stored state numbers (used for stacks). */ -typedef yytype_int8 yy_state_t; - -/* State numbers in computations. */ -typedef int yy_state_fast_t; - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(Msgid) dgettext ("bison-runtime", Msgid) -# endif -# endif -# ifndef YY_ -# define YY_(Msgid) Msgid -# endif -#endif - - -#ifndef YY_ATTRIBUTE_PURE -# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) -# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) -# else -# define YY_ATTRIBUTE_PURE -# endif -#endif - -#ifndef YY_ATTRIBUTE_UNUSED -# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) -# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -# else -# define YY_ATTRIBUTE_UNUSED -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YY_USE(E) ((void) (E)) -#else -# define YY_USE(E) /* empty */ -#endif - -/* Suppress an incorrect diagnostic about yylval being uninitialized. */ -#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ -# if __GNUC__ * 100 + __GNUC_MINOR__ < 407 -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") -# else -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ - _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") -# endif -# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ - _Pragma ("GCC diagnostic pop") -#else -# define YY_INITIAL_VALUE(Value) Value -#endif -#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_END -#endif -#ifndef YY_INITIAL_VALUE -# define YY_INITIAL_VALUE(Value) /* Nothing. */ -#endif - -#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ -# define YY_IGNORE_USELESS_CAST_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") -# define YY_IGNORE_USELESS_CAST_END \ - _Pragma ("GCC diagnostic pop") -#endif -#ifndef YY_IGNORE_USELESS_CAST_BEGIN -# define YY_IGNORE_USELESS_CAST_BEGIN -# define YY_IGNORE_USELESS_CAST_END -#endif - - -#define YY_ASSERT(E) ((void) (0 && (E))) - -#if !defined yyoverflow - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS -# include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's 'empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* !defined yyoverflow */ - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yy_state_t yyss_alloc; - YYSTYPE yyvs_alloc; -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -# define YYCOPY_NEEDED 1 - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYPTRDIFF_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / YYSIZEOF (*yyptr); \ - } \ - while (0) - -#endif - -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from SRC to DST. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) -# else -# define YYCOPY(Dst, Src, Count) \ - do \ - { \ - YYPTRDIFF_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ - } \ - while (0) -# endif -# endif -#endif /* !YYCOPY_NEEDED */ - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 4 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 28 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 23 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 6 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 13 -/* YYNSTATES -- Number of states. */ -#define YYNSTATES 32 - -/* YYMAXUTOK -- Last valid token kind. */ -#define YYMAXUTOK 277 - - -/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM - as returned by yylex, with out-of-bounds checking. */ -#define YYTRANSLATE(YYX) \ - (0 <= (YYX) && (YYX) <= YYMAXUTOK \ - ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ - : YYSYMBOL_YYUNDEF) - -/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM - as returned by yylex. */ -static const yytype_int8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22 -}; - -#if YYDEBUG -/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ -static const yytype_int8 yyrline[] = -{ - 0, 60, 60, 63, 64, 64, 67, 68, 71, 72, - 73, 74, 75, 76 -}; -#endif - -/** Accessing symbol of state STATE. */ -#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) - -#if YYDEBUG || 0 -/* The user-facing name of the symbol whose (internal) number is - YYSYMBOL. No bounds checking. */ -static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; - -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "\"end of file\"", "error", "\"invalid token\"", "NEVER", "IF", "FI", - "IMPLIES", "GOTO", "AND", "OR", "NOT", "LEFT_PAR", "RIGHT_PAR", "CASE", - "COLON", "SEMI_COLON", "CASE_TRUE", "LEFT_BRACE", "RIGHT_BRACE", - "LITT_ENT", "LITT_CHAINE", "LITT_REEL", "ID", "$accept", "automaton", - "stateseq", "$@1", "option", "exp", YY_NULLPTR -}; - -static const char * -yysymbol_name (yysymbol_kind_t yysymbol) -{ - return yytname[yysymbol]; -} -#endif - -#define YYPACT_NINF (-16) - -#define yypact_value_is_default(Yyn) \ - ((Yyn) == YYPACT_NINF) - -#define YYTABLE_NINF (-1) - -#define yytable_value_is_error(Yyn) \ - 0 - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -static const yytype_int8 yypact[] = -{ - 0, -15, 10, -13, -16, 2, 1, -16, -16, 16, - 8, -10, 17, -10, -10, -16, -16, 9, 11, -16, - -1, 18, -10, -10, -13, -16, 5, -16, -16, -16, - 8, -16 -}; - -/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE does not specify something else to do. Zero - means the default is an error. */ -static const yytype_int8 yydefact[] = -{ - 0, 0, 0, 3, 1, 0, 0, 4, 2, 0, - 6, 0, 0, 0, 0, 12, 13, 0, 0, 11, - 0, 0, 0, 0, 3, 8, 0, 10, 9, 5, - 6, 7 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yytype_int8 yypgoto[] = -{ - -16, -16, 4, -16, -7, -9 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int8 yydefgoto[] = -{ - 0, 2, 6, 9, 12, 17 -}; - -/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule whose - number is the opposite. If YYTABLE_NINF, syntax error. */ -static const yytype_int8 yytable[] = -{ - 13, 14, 3, 1, 19, 20, 15, 22, 23, 5, - 4, 25, 16, 27, 28, 21, 7, 22, 23, 8, - 10, 11, 18, 31, 0, 26, 24, 30, 29 -}; - -static const yytype_int8 yycheck[] = -{ - 10, 11, 17, 3, 13, 14, 16, 8, 9, 22, - 0, 12, 22, 22, 23, 6, 14, 8, 9, 18, - 4, 13, 5, 30, -1, 7, 15, 22, 24 -}; - -/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of - state STATE-NUM. */ -static const yytype_int8 yystos[] = -{ - 0, 3, 24, 17, 0, 22, 25, 14, 18, 26, - 4, 13, 27, 10, 11, 16, 22, 28, 5, 28, - 28, 6, 8, 9, 15, 12, 7, 28, 28, 25, - 22, 27 -}; - -/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ -static const yytype_int8 yyr1[] = -{ - 0, 23, 24, 25, 26, 25, 27, 27, 28, 28, - 28, 28, 28, 28 -}; - -/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ -static const yytype_int8 yyr2[] = -{ - 0, 2, 4, 0, 0, 8, 0, 6, 3, 3, - 3, 2, 1, 1 -}; - - -enum { YYENOMEM = -2 }; - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab -#define YYNOMEM goto yyexhaustedlab - - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ - do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ - while (0) - -/* Backward compatibility with an undocumented macro. - Use YYerror or YYUNDEF. */ -#define YYERRCODE YYUNDEF - - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - - - - -# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Kind, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - - -/*-----------------------------------. -| Print this symbol's value on YYO. | -`-----------------------------------*/ - -static void -yy_symbol_value_print (FILE *yyo, - yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) -{ - FILE *yyoutput = yyo; - YY_USE (yyoutput); - if (!yyvaluep) - return; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YY_USE (yykind); - YY_IGNORE_MAYBE_UNINITIALIZED_END -} - - -/*---------------------------. -| Print this symbol on YYO. | -`---------------------------*/ - -static void -yy_symbol_print (FILE *yyo, - yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) -{ - YYFPRINTF (yyo, "%s %s (", - yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); - - yy_symbol_value_print (yyo, yykind, yyvaluep); - YYFPRINTF (yyo, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -static void -yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) -{ - YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -static void -yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, - int yyrule) -{ - int yylno = yyrline[yyrule]; - int yynrhs = yyr2[yyrule]; - int yyi; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, - YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), - &yyvsp[(yyi + 1) - (yynrhs)]); - YYFPRINTF (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyssp, yyvsp, Rule); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) ((void) 0) -# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - - - - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -static void -yydestruct (const char *yymsg, - yysymbol_kind_t yykind, YYSTYPE *yyvaluep) -{ - YY_USE (yyvaluep); - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YY_USE (yykind); - YY_IGNORE_MAYBE_UNINITIALIZED_END -} - - -/* Lookahead token kind. */ -int yychar; - -/* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; -/* Number of syntax errors so far. */ -int yynerrs; - - - - -/*----------. -| yyparse. | -`----------*/ - -int -yyparse (void) -{ - yy_state_fast_t yystate = 0; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus = 0; - - /* Refer to the stacks through separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* Their size. */ - YYPTRDIFF_T yystacksize = YYINITDEPTH; - - /* The state stack: array, bottom, top. */ - yy_state_t yyssa[YYINITDEPTH]; - yy_state_t *yyss = yyssa; - yy_state_t *yyssp = yyss; - - /* The semantic value stack: array, bottom, top. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - YYSTYPE *yyvsp = yyvs; - - int yyn; - /* The return value of yyparse. */ - int yyresult; - /* Lookahead symbol kind. */ - yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - - - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yychar = YYEMPTY; /* Cause a token to be read. */ - - goto yysetstate; - - -/*------------------------------------------------------------. -| yynewstate -- push a new state, which is found in yystate. | -`------------------------------------------------------------*/ -yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - -/*--------------------------------------------------------------------. -| yysetstate -- set current state (the top of the stack) to yystate. | -`--------------------------------------------------------------------*/ -yysetstate: - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - YY_ASSERT (0 <= yystate && yystate < YYNSTATES); - YY_IGNORE_USELESS_CAST_BEGIN - *yyssp = YY_CAST (yy_state_t, yystate); - YY_IGNORE_USELESS_CAST_END - YY_STACK_PRINT (yyss, yyssp); - - if (yyss + yystacksize - 1 <= yyssp) -#if !defined yyoverflow && !defined YYSTACK_RELOCATE - YYNOMEM; -#else - { - /* Get the current used size of the three stacks, in elements. */ - YYPTRDIFF_T yysize = yyssp - yyss + 1; - -# if defined yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - yy_state_t *yyss1 = yyss; - YYSTYPE *yyvs1 = yyvs; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * YYSIZEOF (*yyssp), - &yyvs1, yysize * YYSIZEOF (*yyvsp), - &yystacksize); - yyss = yyss1; - yyvs = yyvs1; - } -# else /* defined YYSTACK_RELOCATE */ - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - YYNOMEM; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yy_state_t *yyss1 = yyss; - union yyalloc *yyptr = - YY_CAST (union yyalloc *, - YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); - if (! yyptr) - YYNOMEM; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - YY_IGNORE_USELESS_CAST_BEGIN - YYDPRINTF ((stderr, "Stack size increased to %ld\n", - YY_CAST (long, yystacksize))); - YY_IGNORE_USELESS_CAST_END - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } -#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ - - - if (yystate == YYFINAL) - YYACCEPT; - - goto yybackup; - - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to lookahead token. */ - yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token\n")); - yychar = yylex (); - } - - if (yychar <= YYEOF) - { - yychar = YYEOF; - yytoken = YYSYMBOL_YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else if (yychar == YYerror) - { - /* The scanner already issued an error message, process directly - to error recovery. But do not keep the error token as - lookahead, it is too special and may lead us to an endless - loop in error recovery. */ - yychar = YYUNDEF; - yytoken = YYSYMBOL_YYerror; - goto yyerrlab1; - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yytable_value_is_error (yyn)) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the lookahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - yystate = yyn; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - - /* Discard the shifted token. */ - yychar = YYEMPTY; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - '$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 4: /* $@1: %empty */ -#line 64 "parserPromela.yacc" - { new_state((yyvsp[-1].string), 1);} -#line 1116 "parserPromela.tab.cacc" - break; - - case 7: /* option: CASE exp IMPLIES GOTO ID option */ -#line 68 "parserPromela.yacc" - { new_transition((yyvsp[-1].string), (yyvsp[-4].label));} -#line 1122 "parserPromela.tab.cacc" - break; - - case 8: /* exp: LEFT_PAR exp RIGHT_PAR */ -#line 71 "parserPromela.yacc" - { (yyval.label) = (yyvsp[-1].label); } -#line 1128 "parserPromela.tab.cacc" - break; - - case 9: /* exp: exp OR exp */ -#line 72 "parserPromela.yacc" - { (yyval.label) = xbt_automaton_exp_label_new_or((yyvsp[-2].label), (yyvsp[0].label)); } -#line 1134 "parserPromela.tab.cacc" - break; - - case 10: /* exp: exp AND exp */ -#line 73 "parserPromela.yacc" - { (yyval.label) = xbt_automaton_exp_label_new_and((yyvsp[-2].label), (yyvsp[0].label)); } -#line 1140 "parserPromela.tab.cacc" - break; - - case 11: /* exp: NOT exp */ -#line 74 "parserPromela.yacc" - { (yyval.label) = xbt_automaton_exp_label_new_not((yyvsp[0].label)); } -#line 1146 "parserPromela.tab.cacc" - break; - - case 12: /* exp: CASE_TRUE */ -#line 75 "parserPromela.yacc" - { (yyval.label) = xbt_automaton_exp_label_new_one(); } -#line 1152 "parserPromela.tab.cacc" - break; - - case 13: /* exp: ID */ -#line 76 "parserPromela.yacc" - { (yyval.label) = xbt_automaton_exp_label_new_predicat((yyvsp[0].string)); } -#line 1158 "parserPromela.tab.cacc" - break; - - -#line 1162 "parserPromela.tab.cacc" - - default: break; - } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ - YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - - *++yyvsp = yyval; - - /* Now 'shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - { - const int yylhs = yyr1[yyn] - YYNTOKENS; - const int yyi = yypgoto[yylhs] + *yyssp; - yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp - ? yytable[yyi] - : yydefgoto[yylhs]); - } - - goto yynewstate; - - -/*--------------------------------------. -| yyerrlab -- here on detecting error. | -`--------------------------------------*/ -yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; - yyerror (YY_("syntax error")); - } - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - /* Pacify compilers when the user code never invokes YYERROR and the - label yyerrorlab therefore never appears in user code. */ - if (0) - YYERROR; - ++yynerrs; - - /* Do not reclaim the symbols of the rule whose action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - /* Pop stack until we find a state that shifts the error token. */ - for (;;) - { - yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) - { - yyn += YYSYMBOL_YYerror; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - - yydestruct ("Error: popping", - YY_ACCESSING_SYMBOL (yystate), yyvsp); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturnlab; - - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturnlab; - - -/*-----------------------------------------------------------. -| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | -`-----------------------------------------------------------*/ -yyexhaustedlab: - yyerror (YY_("memory exhausted")); - yyresult = 2; - goto yyreturnlab; - - -/*----------------------------------------------------------. -| yyreturnlab -- parsing is finished, clean up and return. | -`----------------------------------------------------------*/ -yyreturnlab: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - } - /* Do not reclaim the symbols of the rule whose action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - YY_ACCESSING_SYMBOL (+*yyssp), yyvsp); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - - return yyresult; -} - -#line 79 "parserPromela.yacc" - - - - -void yyerror(const char *s){ - fprintf (stderr, "%s\n", s); -} - - - diff --git a/src/xbt/automaton/parserPromela.tab.hacc b/src/xbt/automaton/parserPromela.tab.hacc deleted file mode 100644 index 9579e0bd57..0000000000 --- a/src/xbt/automaton/parserPromela.tab.hacc +++ /dev/null @@ -1,107 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.8.2. */ - -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, - Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, - especially those whose name start with YY_ or yy_. They are - private implementation details that can be changed or removed. */ - -#ifndef YY_XBT_AUTOMATON_PARSER_PARSERPROMELA_TAB_HACC_INCLUDED -# define YY_XBT_AUTOMATON_PARSER_PARSERPROMELA_TAB_HACC_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 1 -#endif -#if YYDEBUG -extern int xbt_automaton_parser_debug; -#endif - -/* Token kinds. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - YYEMPTY = -2, - YYEOF = 0, /* "end of file" */ - YYerror = 256, /* error */ - YYUNDEF = 257, /* "invalid token" */ - NEVER = 258, /* NEVER */ - IF = 259, /* IF */ - FI = 260, /* FI */ - IMPLIES = 261, /* IMPLIES */ - GOTO = 262, /* GOTO */ - AND = 263, /* AND */ - OR = 264, /* OR */ - NOT = 265, /* NOT */ - LEFT_PAR = 266, /* LEFT_PAR */ - RIGHT_PAR = 267, /* RIGHT_PAR */ - CASE = 268, /* CASE */ - COLON = 269, /* COLON */ - SEMI_COLON = 270, /* SEMI_COLON */ - CASE_TRUE = 271, /* CASE_TRUE */ - LEFT_BRACE = 272, /* LEFT_BRACE */ - RIGHT_BRACE = 273, /* RIGHT_BRACE */ - LITT_ENT = 274, /* LITT_ENT */ - LITT_CHAINE = 275, /* LITT_CHAINE */ - LITT_REEL = 276, /* LITT_REEL */ - ID = 277 /* ID */ - }; - typedef enum yytokentype yytoken_kind_t; -#endif - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -union YYSTYPE -{ -#line 23 "parserPromela.yacc" - - double real; - int integer; - char* string; - xbt_automaton_exp_label_t label; - -#line 93 "parserPromela.tab.hacc" - -}; -typedef union YYSTYPE YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - - -extern YYSTYPE xbt_automaton_parser_lval; - - -int xbt_automaton_parser_parse (void); - - -#endif /* !YY_XBT_AUTOMATON_PARSER_PARSERPROMELA_TAB_HACC_INCLUDED */ diff --git a/src/xbt/automaton/parserPromela.yacc b/src/xbt/automaton/parserPromela.yacc deleted file mode 100644 index 05bb382bcf..0000000000 --- a/src/xbt/automaton/parserPromela.yacc +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (c) 2012-2023. 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" -#if !HAVE_UNISTD_H -#define YY_NO_UNISTD_H /* hello Windows */ -#endif - -#include "automaton_lexer.yy.c" -#include - -void yyerror(const char *s); - -static void new_state(const char* id, int src); -static void new_transition(const char* id, xbt_automaton_exp_label_t label); - -%} - -%union{ - double real; - int integer; - char* string; - xbt_automaton_exp_label_t label; -} - -%token NEVER -%token IF -%token FI -%token IMPLIES -%token GOTO -%token AND -%token OR -%token NOT -%token LEFT_PAR -%token RIGHT_PAR -%token CASE -%token COLON -%token SEMI_COLON -%token CASE_TRUE -%token LEFT_BRACE -%token RIGHT_BRACE -%token LITT_ENT -%token LITT_CHAINE -%token LITT_REEL -%token ID - -%type