Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Reduce code duplication. master
authorArnaud Giersch <arnaud.giersch@univ-fcomte.fr>
Thu, 29 Sep 2022 08:42:43 +0000 (10:42 +0200)
committerArnaud Giersch <arnaud.giersch@univ-fcomte.fr>
Thu, 29 Sep 2022 08:42:43 +0000 (10:42 +0200)
156 files changed:
.mailmap
CMakeLists.txt
ChangeLog
MANIFEST.in
docs/source/Configuring_SimGrid.rst
docs/source/Installing_SimGrid.rst
docs/source/Platform_cpp.rst
docs/source/Release_Notes.rst
examples/cpp/CMakeLists.txt
examples/cpp/mc-failing-assert/s4u-mc-failing-assert-nodpor.tesh [new file with mode: 0644]
examples/cpp/mc-failing-assert/s4u-mc-failing-assert-statequality.tesh [new file with mode: 0644]
examples/cpp/synchro-mutex/s4u-mc-synchro-mutex.tesh
examples/sthread/CMakeLists.txt
include/simgrid/modelchecker.h
include/simgrid/plugins/file_system.h
include/simgrid/s4u/Exec.hpp
include/smpi/smpi_helpers.h
include/smpi/smpi_helpers_internal.h
include/xbt/range.hpp
src/bindings/java/org/simgrid/NativeLib.java
src/include/xbt/mmalloc.h
src/include/xbt/xbt_modinter.h
src/instr/instr_config.cpp
src/instr/instr_paje_header.cpp
src/kernel/EngineImpl.cpp
src/kernel/EngineImpl.hpp
src/kernel/activity/ActivityImpl.cpp
src/kernel/activity/CommImpl.cpp
src/kernel/activity/ExecImpl.hpp
src/kernel/activity/MailboxImpl.cpp
src/kernel/actor/CommObserver.cpp
src/kernel/actor/CommObserver.hpp
src/kernel/actor/SimcallObserver.cpp
src/kernel/actor/SimcallObserver.hpp
src/kernel/context/ContextUnix.cpp
src/kernel/lmm/System.cpp
src/kernel/lmm/System.hpp
src/kernel/lmm/bmf.cpp
src/kernel/lmm/bmf.hpp
src/kernel/resource/DiskImpl.cpp
src/kernel/resource/VirtualMachineImpl.cpp
src/kernel/resource/profile/ProfileBuilder.cpp
src/kernel/routing/FatTreeZone.cpp
src/mc/ModelChecker.cpp
src/mc/ModelChecker.hpp
src/mc/VisitedState.cpp
src/mc/VisitedState.hpp
src/mc/api.cpp [deleted file]
src/mc/api.hpp [deleted file]
src/mc/api/ActorState.hpp [moved from src/mc/mc_pattern.hpp with 68% similarity]
src/mc/api/RemoteApp.cpp [moved from src/mc/Session.cpp with 56% similarity]
src/mc/api/RemoteApp.hpp [moved from src/mc/Session.hpp with 64% similarity]
src/mc/api/State.cpp
src/mc/api/State.hpp
src/mc/compare.cpp
src/mc/explo/CommunicationDeterminismChecker.cpp
src/mc/explo/DFSExplorer.cpp
src/mc/explo/DFSExplorer.hpp
src/mc/explo/Exploration.cpp [new file with mode: 0644]
src/mc/explo/Exploration.hpp
src/mc/explo/LivenessChecker.cpp
src/mc/explo/LivenessChecker.hpp
src/mc/explo/UdporChecker.cpp
src/mc/explo/UdporChecker.hpp
src/mc/explo/simgrid_mc.cpp
src/mc/inspect/LocationList.hpp
src/mc/inspect/mc_dwarf.cpp
src/mc/inspect/mc_unw_vmread.cpp
src/mc/mc_base.cpp
src/mc/mc_client_api.cpp
src/mc/mc_config.cpp
src/mc/mc_config.hpp
src/mc/mc_global.cpp
src/mc/mc_hash.cpp [deleted file]
src/mc/mc_hash.hpp [deleted file]
src/mc/mc_ignore.hpp [deleted file]
src/mc/mc_private.hpp
src/mc/mc_safety.hpp [deleted file]
src/mc/mc_smx.cpp [deleted file]
src/mc/remote/AppSide.cpp
src/mc/remote/AppSide.hpp
src/mc/remote/RemoteProcess.cpp
src/mc/remote/RemoteProcess.hpp
src/mc/remote/mc_protocol.h
src/mc/sosp/Snapshot.cpp
src/mc/sosp/Snapshot.hpp
src/mc/sosp/Snapshot_test.cpp
src/mc/transition/TransitionAny.cpp
src/mc/transition/TransitionComm.cpp
src/plugins/chaos_monkey.cpp
src/plugins/file_system/s4u_FileSystem.cpp
src/plugins/link_load.cpp
src/s4u/s4u_Comm.cpp
src/s4u/s4u_Exec.cpp
src/simgrid/sg_config.cpp
src/smpi/bindings/smpi_f77.cpp
src/smpi/bindings/smpi_mpi.cpp
src/smpi/bindings/smpi_pmpi_file.cpp
src/smpi/include/smpi_file.hpp
src/smpi/include/smpi_replay.hpp
src/smpi/internals/smpi_bench.cpp
src/smpi/internals/smpi_config.cpp
src/smpi/internals/smpi_replay.cpp
src/smpi/mpi/smpi_file.cpp
src/smpi/mpi/smpi_request.cpp
src/smpi/smpicc.in
src/smpi/smpicxx.in
src/smpi/smpiff.in
src/sthread/sthread.c
src/sthread/sthread.h
src/sthread/sthread_impl.cpp
src/surf/HostImpl.cpp
src/surf/cpu_cas01.cpp
src/surf/network_cm02.cpp
src/surf/ptask_L07.cpp
src/surf/xml/surfxml_sax_cb.cpp
src/xbt/dict_test.cpp
src/xbt/mmalloc/mfree.c
src/xbt/mmalloc/mm_interface.c [new file with mode: 0644]
src/xbt/mmalloc/mm_legacy.c
src/xbt/mmalloc/mm_module.c
src/xbt/mmalloc/mmalloc.c
src/xbt/mmalloc/mmorecore.c
src/xbt/mmalloc/mmprivate.h
src/xbt/mmalloc/swag.c
src/xbt/mmalloc/swag.h
src/xbt/xbt_main.cpp
teshsuite/mc/dwarf-expression/dwarf-expression.cpp
teshsuite/mc/dwarf/dwarf.cpp
teshsuite/mc/random-bug/random-bug-nocrash.tesh
teshsuite/mc/random-bug/random-bug.tesh
teshsuite/platforms/flatifier.tesh
teshsuite/smpi/CMakeLists.txt
teshsuite/smpi/coll-allreduce-with-leaks/mc-coll-allreduce-with-leaks.tesh
teshsuite/smpi/coll-allreduce/coll-allreduce-automatic.tesh
teshsuite/smpi/coll-alltoall/griffon.tesh [deleted file]
teshsuite/smpi/coll-alltoallv/coll-alltoallv.c
teshsuite/smpi/io-all-at/io-all-at.tesh
teshsuite/smpi/io-all/io-all.tesh
teshsuite/smpi/io-ordered/io-ordered.tesh
teshsuite/smpi/io-shared/io-shared.tesh
teshsuite/smpi/io-simple-at/io-simple-at.tesh
teshsuite/smpi/io-simple/io-simple.tesh
teshsuite/smpi/mpich3-test/rma/CMakeLists.txt
teshsuite/xbt/CMakeLists.txt
teshsuite/xbt/mmalloc/mmalloc_32.tesh
teshsuite/xbt/mmalloc/mmalloc_64.tesh
teshsuite/xbt/mmalloc/mmalloc_test.cpp
tools/address_sanitizer.supp
tools/cmake/DefinePackages.cmake
tools/cmake/Flags.cmake
tools/cmake/MakeLib.cmake
tools/jenkins/Coverage.sh
tools/jenkins/Flags.sh
tools/jenkins/Sanitizers.sh
tools/jenkins/build.sh

index c279754..f7f551c 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -39,7 +39,9 @@ Clément Courageux-Sudan <clement.courageux-sudan@inria.fr> <clement.courageux-s
 Clément Courageux-Sudan <clement.courageux-sudan@inria.fr> <clementcourageuxsudan@gmail.com>
 Augustin Degomme <adegomme@gmail.com>
 Augustin Degomme <adegomme@gmail.com> <13270544+adegomme@users.noreply.github.com>
+Augustin Degomme <adegomme@gmail.com> <26892-adegomme@users.noreply.framagit.org>
 Augustin Degomme <adegomme@gmail.com> <ad254919@cardamome.intra.cea.fr>
+Augustin Degomme <adegomme@gmail.com> <adegomme@ampere03>
 Augustin Degomme <adegomme@gmail.com> <adegomme@users.noreply.github.com>
 Augustin Degomme <adegomme@gmail.com> <augustin.degomme@imag.fr>
 Augustin Degomme <adegomme@gmail.com> <augustin.degomme@unibas.ch>
@@ -108,6 +110,7 @@ Pierre Navarro <pierre.navarro@imag.fr> <pierre@.(none)>
 Pierre Navarro <pierre.navarro@imag.fr> <pierre@chontal.imag.fr>
 Pierre Navarro <pierre.navarro@imag.fr> <pierre@erie.imag.fr>
 Pierre Navarro <pierre.navarro@imag.fr> <pierre@workhorse-2.local>
+Lucas Nesi <lucas.nesi@inf.ufrgs.br> <lucas31nesi@hotmail.com>
 Lucas Nussbaum <lucas.nussbaum@loria.fr> <lucas@lucas-nussbaum.net>
 Tien-Dat Phan <tien-dat.phan@irisa.fr>
 Martin Quinson <martin.quinson@ens-rennes.fr> <(no author)@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
index b03c595..daefe9f 100644 (file)
@@ -23,6 +23,7 @@ cmake_minimum_required(VERSION 3.5)
 if(NOT CMAKE_VERSION VERSION_LESS "3.9")
   cmake_policy(SET CMP0069 NEW)
 endif()
+# once we move >= 3.13, we should use target_link_option in examples/sthread
 message(STATUS "Cmake version ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}")
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_HOME_DIRECTORY}/tools/cmake/Modules)
 
@@ -52,7 +53,7 @@ if (CMAKE_COMPILER_IS_GNUCC)
   endif()
 endif()
 
-## We need a decent support of the C++14 and C11 standards
+## We need a decent support of the C++17 and C11 standards
 set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
@@ -411,6 +412,8 @@ if(enable_model-checking)
     message(WARNING "FreeBSD + Model-Checking + Java = too much for now. Disabling the Java bindings.")
     set(enable_java FALSE)
   endif()
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -gdwarf-4")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -gdwarf-4")
 else()
   SET(SIMGRID_HAVE_MC 0)
   set(HAVE_MMALLOC 0)
@@ -453,27 +456,27 @@ else()
     OUTPUT_VARIABLE compile_makecontext_output)
 
   #If can have both context
-  if(compile_makecontext)
-    set(HAVE_UCONTEXT_CONTEXTS 1)
-    message(STATUS "Support for ucontext factory ok.")
-  else()
+  if(NOT compile_makecontext)
     message(STATUS "Error: <ucontext.h> exists, but makecontext is not compilable. Compilation output:\n ${compile_makecontext_output}")
     message(STATUS "No ucontext factory: makecontext() is not compilable.")
-  endif()
-
-  # Stack setup (size and address)
-  try_run(RUN_makecontext_VAR COMPILE_makecontext_VAR
-    ${CMAKE_BINARY_DIR} ${CMAKE_HOME_DIRECTORY}/tools/cmake/test_prog/prog_stacksetup.c
-    RUN_OUTPUT_VARIABLE stack_setup)
-
-  LIST(LENGTH stack_setup stack_setup_len)
-  if("${stack_setup_len}" STREQUAL "2")
-    LIST(GET stack_setup 0 makecontext_addr)
-    LIST(GET stack_setup 1 makecontext_size)
-    set(sg_makecontext_stack_addr "#define sg_makecontext_stack_addr(skaddr) (${makecontext_addr})")
-    set(sg_makecontext_stack_size "#define sg_makecontext_stack_size(sksize) (${makecontext_size})")
   else()
-    message(FATAL_ERROR "Could not figure out the stack setup. Compil: ${RUN_makecontext_VAR}. Exec: ${COMPILE_makecontext_VAR}. Output: ${stack_setup}")
+    message(STATUS "Support for ucontext factory ok.")
+    set(HAVE_UCONTEXT_CONTEXTS 1)
+
+    # Stack setup (size and address)
+    try_run(RUN_makecontext_VAR COMPILE_makecontext_VAR
+      ${CMAKE_BINARY_DIR} ${CMAKE_HOME_DIRECTORY}/tools/cmake/test_prog/prog_stacksetup.c
+      RUN_OUTPUT_VARIABLE stack_setup)
+
+    LIST(LENGTH stack_setup stack_setup_len)
+    if("${stack_setup_len}" STREQUAL "2")
+      LIST(GET stack_setup 0 makecontext_addr)
+      LIST(GET stack_setup 1 makecontext_size)
+      set(sg_makecontext_stack_addr "#define sg_makecontext_stack_addr(skaddr) (${makecontext_addr})")
+      set(sg_makecontext_stack_size "#define sg_makecontext_stack_size(sksize) (${makecontext_size})")
+    else()
+      message(FATAL_ERROR "Could not figure out the stack setup. Compil: ${RUN_makecontext_VAR}. Exec: ${COMPILE_makecontext_VAR}. Output: ${stack_setup}")
+    endif()
   endif()
 endif()
 
index 3738be9..d6e32b8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -36,7 +36,8 @@ Platform description & visualization:
     demonstrates how we can generate a nice graphical representation of the
        platform.
 
-General: 
+General:
+  - SimGrid now requires a compiler with C++17 support.
   - Modified the host_by_name functions:
     - Now, they return only hosts, not VMs, and in a much more efficient way.
        - If one wants to find a VM by name, he now needs to know the host on
@@ -54,6 +55,7 @@ Fixed bugs (FG#.. -> FramaGit bugs; FG!.. -> FG merge requests)
  - FG#109: Application time reported by --cfg=smpi/display-timing:yes is wrong
  - FG!109: Trigger new engine solve upon host events such as host on/off
  - FG#110: Wait_any does not trigger new model solve when host events occur
+ - FG#111: Wrong execution time in rare cases when using multicore
 
 ----------------------------------------------------------------------------
 
index 09a068e..31e9756 100644 (file)
@@ -316,6 +316,8 @@ include examples/cpp/mc-centralized-mutex/s4u-mc-centralized-mutex.cpp
 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/network-factors/s4u-network-factors.cpp
@@ -553,12 +555,12 @@ include examples/python/exec-async/exec-async.py
 include examples/python/exec-async/exec-async.tesh
 include examples/python/exec-basic/exec-basic.py
 include examples/python/exec-basic/exec-basic.tesh
-include examples/python/exec-basic/exec-ptask.py
-include examples/python/exec-basic/exec-ptask.tesh
 include examples/python/exec-cpu-nonlinear/exec-cpu-nonlinear.py
 include examples/python/exec-cpu-nonlinear/exec-cpu-nonlinear.tesh
 include examples/python/exec-dvfs/exec-dvfs.py
 include examples/python/exec-dvfs/exec-dvfs.tesh
+include examples/python/exec-ptask/exec-ptask.py
+include examples/python/exec-ptask/exec-ptask.tesh
 include examples/python/exec-remote/exec-remote.py
 include examples/python/exec-remote/exec-remote.tesh
 include examples/python/io-degradation/io-degradation.py
@@ -713,6 +715,7 @@ 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-mutex-simple.c
+include examples/sthread/pthread-mutex-simple.tesh
 include examples/sthread/sthread-mutex-simple.c
 include src/include/catch_simgrid.hpp
 include teshsuite/java/semaphoregc/SemaphoreGC.java
@@ -937,7 +940,6 @@ include teshsuite/smpi/coll-allreduce/coll-allreduce.tesh
 include teshsuite/smpi/coll-alltoall/clusters.tesh
 include teshsuite/smpi/coll-alltoall/coll-alltoall.c
 include teshsuite/smpi/coll-alltoall/coll-alltoall.tesh
-include teshsuite/smpi/coll-alltoall/griffon.tesh
 include teshsuite/smpi/coll-alltoallv/coll-alltoallv.c
 include teshsuite/smpi/coll-alltoallv/coll-alltoallv.tesh
 include teshsuite/smpi/coll-barrier/coll-barrier.c
@@ -2277,18 +2279,18 @@ include src/kernel/timer/Timer.cpp
 include src/mc/AddressSpace.hpp
 include src/mc/ModelChecker.cpp
 include src/mc/ModelChecker.hpp
-include src/mc/Session.cpp
-include src/mc/Session.hpp
 include src/mc/VisitedState.cpp
 include src/mc/VisitedState.hpp
-include src/mc/api.cpp
-include src/mc/api.hpp
+include src/mc/api/ActorState.hpp
+include src/mc/api/RemoteApp.cpp
+include src/mc/api/RemoteApp.hpp
 include src/mc/api/State.cpp
 include src/mc/api/State.hpp
 include src/mc/compare.cpp
 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
@@ -2321,17 +2323,11 @@ include src/mc/mc_config.hpp
 include src/mc/mc_exit.hpp
 include src/mc/mc_forward.hpp
 include src/mc/mc_global.cpp
-include src/mc/mc_hash.cpp
-include src/mc/mc_hash.hpp
-include src/mc/mc_ignore.hpp
 include src/mc/mc_mmu.hpp
-include src/mc/mc_pattern.hpp
 include src/mc/mc_private.hpp
 include src/mc/mc_record.cpp
 include src/mc/mc_record.hpp
 include src/mc/mc_replay.hpp
-include src/mc/mc_safety.hpp
-include src/mc/mc_smx.cpp
 include src/mc/remote/AppSide.cpp
 include src/mc/remote/AppSide.hpp
 include src/mc/remote/Channel.cpp
@@ -2656,6 +2652,7 @@ 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
index f907c9d..4ea9206 100644 (file)
@@ -119,6 +119,7 @@ Existing Configuration Items
 - **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`
@@ -769,6 +770,15 @@ The ``model-check/communications-determinism`` and
 communication determinism mode of the model checker, which checks
 determinism properties of the communications of an application.
 
+.. _cfg=model-check/setenv:
+
+Passing environment variables
+.............................
+
+You can specify extra environment variables to be set in the verified application
+with ``model-check/setenv``. For example, you can preload a library as follows:
+``-cfg=model-check/setenv:LD_PRELOAD=toto;LD_LIBRARY_PATH=/tmp``.
+
 .. _options_mc_perf:
 
 Verification Performance Considerations
index 9d5d606..e1234ab 100644 (file)
@@ -111,8 +111,8 @@ Getting the Dependencies
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
 C++ compiler (either g++, clang, or icc).
-  We use the C++14 standard, and older compilers tend to fail on
-  us. It seems that g++ 5.0 or higher is required nowadays (because of
+  We use the C++17 standard, and older compilers tend to fail on
+  us. It seems that g++ 7.0 or higher is required nowadays (because of
   boost).  SimGrid compiles well with `clang` or `icc` too.
 Python 3.
   SimGrid should build without Python. That is only needed by our regression test suite.
@@ -122,11 +122,11 @@ cmake (v3.5).
   configuration options (e.g., if your Python installation is not standard).
 boost (at least v1.48, v1.59 recommended)
   - On Debian / Ubuntu: ``apt install libboost-dev libboost-context-dev``
-  - On CentOS / Fedora: ``yum install boost-devel``
+  - On CentOS / Fedora: ``dnf install boost-devel``
   - On macOS with homebrew: ``brew install boost``
 Eigen3 (optional)
   - On Debian / Ubuntu: ``apt install libeigen3-dev``
-  - On CentOS / Fedora: ``yum install eigen3-devel``
+  - 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.
 Java (optional):
index 75abec5..e0aad12 100644 (file)
@@ -155,7 +155,7 @@ Note that the leaves and loopback links are defined through callbacks, as follow
 
     /* create each leaf in the Fat-Tree, return a pair composed of: <object (host, zone), gateway> */
     static std::pair<simgrid::kernel::routing::NetPoint*, simgrid::kernel::routing::NetPoint*>
-    create_hostzone(const sg4::NetZone* zone, const std::vector<unsigned int>& /*coord*/, int id)
+    create_hostzone(const sg4::NetZone* zone, const std::vector<unsigned long>& /*coord*/, unsigned long id)
     {
       /* creating zone */
       std::string hostname = "host" + std::to_string(id);
index 6dfa36e..49e970b 100644 (file)
@@ -495,8 +495,8 @@ old, non-free ISP test suite by the one from the `MPI Bug Initiative <https://ha
 This will eventually help improving the robustness of Mc SimGrid.
 
 These changes unlock the future of Mc SimGrid. For the next releases, we plan to implement another exploration algorithm based on event unfoldings (using 
-`The Anh Pham's thesis <https://tel.archives-ouvertes.fr/tel-02462074/document>`_), the exploration of scenarios where the actors get killed and/or where
-communications timeout, and the addition of a `wrapper to pthreads <https://hal.inria.fr/hal-02449080>`, opening the path to the verification classical
+`The Anh Pham's thesis <https://tel.archives-ouvertes.fr/tel-02462074>`_), the exploration of scenarios where the actors get killed and/or where
+communications timeout, and the addition of a `wrapper to pthreads <https://hal.inria.fr/hal-02449080>`_, opening the path to the verification classical
 multithreaded applications.
 
 
index cacac73..1e41321 100644 (file)
@@ -90,9 +90,18 @@ foreach (example synchro-barrier synchro-mutex synchro-semaphore)
              --setenv srcdir=${CMAKE_CURRENT_SOURCE_DIR}/${example}
              --cd ${CMAKE_CURRENT_SOURCE_DIR}/${example}
              ${CMAKE_HOME_DIRECTORY}/examples/cpp/${example}/s4u-mc-${example}.tesh)
+
+    add_dependencies(tests-mc s4u-${example})
   endif()
 endforeach()
 
+if (SIMGRID_HAVE_MC)
+  # Dependency on the regular tests
+  foreach(example mc-centralized-mutex)
+    add_dependencies(tests-mc s4u-${example})
+  endforeach()
+endif()
+
 
 if(NOT HAVE_GRAPHVIZ)
   set(_dag-from-dot_disable 1)
@@ -204,6 +213,31 @@ foreach(example app-bittorrent app-masterworkers
                                              ${CMAKE_HOME_DIRECTORY}/examples/cpp/${example}/s4u-${example}.tesh)
 endforeach()
 
+# Test non-DPOR reductions on a given MC test
+foreach(example mc-failing-assert)
+  if(SIMGRID_HAVE_MC)
+# 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.
+#
+#    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)
+
+    ADD_TESH(s4u-${example}-nodpor    --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}-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()
+
 # Examples not accepting factories
 ##################################
 
diff --git a/examples/cpp/mc-failing-assert/s4u-mc-failing-assert-nodpor.tesh b/examples/cpp/mc-failing-assert/s4u-mc-failing-assert-nodpor.tesh
new file mode 100644 (file)
index 0000000..912b9a1
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env tesh
+
+! expect return 1
+! timeout 300
+$ ${bindir:=.}/../../../bin/simgrid-mc --cfg=model-check/reduction:none -- ${bindir:=.}/s4u-mc-failing-assert ${platfdir}/small_platform.xml --log=root.thresh:critical
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'none'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: none.
+> [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. 119 unique states visited; 36 backtracks (330 transition replays, 175 states visited overall)
+
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
new file mode 100644 (file)
index 0000000..97c8085
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env tesh
+
+! expect return 1
+! timeout 300
+$ ${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)
index e7dedc4..5bec63f 100644 (file)
@@ -3,8 +3,8 @@
 p This file tests the dependencies between MUTEX transitions
 
 $ ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:verbose --log=root.fmt="[Checker]%e%m%n" -- ${bindir:=.}/s4u-synchro-mutex --cfg=actors:1 --log=s4u_test.thres:critical --log=root.fmt="[App%e%e%e%e]%e%m%n"
-> [Checker] Start a DFS exploration. Reduction is: dpor.
 > [App    ] Configuration change: Set 'actors' to '1'
+> [Checker] Start a DFS exploration. Reduction is: dpor.
 > [Checker] Execute 1: MUTEX_LOCK(mutex: 0, owner:1) (stack depth: 1, state: 1, 0 interleaves)
 > [Checker] Execute 1: MUTEX_WAIT(mutex: 0, owner:1) (stack depth: 2, state: 2, 0 interleaves)
 > [Checker] Execute 1: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 3, state: 3, 0 interleaves)
@@ -43,8 +43,8 @@ $ ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:verbose --log=root.fmt
 > [Checker] DFS exploration ended. 13 unique states visited; 3 backtracks (18 transition replays, 3 states visited overall)
 
 $ ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:verbose --log=root.fmt="[Checker]%e%m%n" -- ${bindir:=.}/s4u-synchro-mutex --cfg=actors:2 --log=s4u_test.thres:critical --log=root.fmt="[App%e%e%e%e]%e%m%n"
-> [Checker] Start a DFS exploration. Reduction is: dpor.
 > [App    ] Configuration change: Set 'actors' to '2'
+> [Checker] Start a DFS exploration. Reduction is: dpor.
 > [Checker] Execute 1: MUTEX_LOCK(mutex: 0, owner:1) (stack depth: 1, state: 1, 0 interleaves)
 > [Checker] Execute 1: MUTEX_WAIT(mutex: 0, owner:1) (stack depth: 2, state: 2, 0 interleaves)
 > [Checker] Execute 1: MUTEX_UNLOCK(mutex: 0, owner:-1) (stack depth: 3, state: 3, 0 interleaves)
@@ -221,6 +221,6 @@ $ ${bindir:=.}/../../../bin/simgrid-mc --log=mc_dfs.thres:verbose --log=root.fmt
 > [Checker] DFS exploration ended. 37 unique states visited; 7 backtracks (76 transition replays, 33 states visited overall)
 
 $ ${bindir:=.}/../../../bin/simgrid-mc -- ${bindir:=.}/s4u-synchro-mutex --cfg=actors:3 --log=s4u_test.thres:critical
-> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
 > [0.000000] [xbt_cfg/INFO] Configuration change: Set 'actors' to '3'
+> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: dpor.
 > [0.000000] [mc_dfs/INFO] DFS exploration ended. 85 unique states visited; 15 backtracks (240 transition replays, 141 states visited overall)
index bf915fc..81d4ef1 100644 (file)
@@ -11,6 +11,7 @@ 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)
+    target_link_libraries(pthread-${x} PUBLIC "-Wl,-znorelro -Wl,-znoseparate-code") # TODO: convert to target_link_option once cmake is >3.13
 
     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)
index 661fc12..69217b7 100644 (file)
@@ -5,12 +5,6 @@
 /* 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 modelchecker.h
- *
- *  This is the API used by the user simulated program to communicate
- *  with the MC.
- */
-
 #ifndef SIMGRID_MODELCHECKER_H
 #define SIMGRID_MODELCHECKER_H
 
@@ -26,9 +20,7 @@ XBT_PUBLIC int MC_random(int min, int max);
 
 #if SIMGRID_HAVE_MC
 
-/* Internal variable used to check if we're running under the MC
- *
- * Please don't use directly: you should use MC_is_active. */
+/* Internal variable used to check if we're running under the MC. Please use MC_is_active instead. */
 extern XBT_PUBLIC int _sg_do_model_check;
 extern XBT_PUBLIC int _sg_mc_max_visited_states;
 
@@ -44,12 +36,9 @@ XBT_PUBLIC void MC_assert(int);
 XBT_PUBLIC void MC_automaton_new_propositional_symbol(const char* id, int (*fct)(void));
 XBT_PUBLIC void MC_automaton_new_propositional_symbol_pointer(const char* id, int* value);
 
-XBT_PUBLIC void MC_cut(void);
 XBT_PUBLIC void MC_ignore(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);
-XBT_PUBLIC void MC_ignore_global_variable(const char* var_name);
 
 #else
 
@@ -57,14 +46,13 @@ XBT_PUBLIC void MC_ignore_global_variable(const char* var_name);
 #define MC_visited_reduction()          0
 
 #define MC_assert(a)                    xbt_assert(a)
+
 #define MC_automaton_new_propositional_symbol(a, b) ((void)0)
 #define MC_automaton_new_propositional_symbol_pointer(a, b) ((void)0)
-#define MC_cut()                        ((void)0)
-#define MC_ignore(a, b)                 ((void)0)
 
-#define MC_ignore_heap(a,s)             ((void)0)
-#define MC_remove_ignore_heap(a,s)      ((void)0)
-#define MC_ignore_global_variable(v)    ((void)0)
+#define MC_ignore(a, b) ((void)0)
+#define MC_ignore_heap(a, s) ((void)0)
+#define MC_unignore_heap(a, s) ((void)0)
 
 #endif
 
index 28c31ea..8994889 100644 (file)
@@ -126,6 +126,7 @@ public:
   void seek(sg_offset_t pos);             /** Sets the file head to the given position. */
   void seek(sg_offset_t pos, int origin); /** Sets the file head to the given position from a given origin. */
   sg_size_t tell() const;                 /** Retrieves the current file position */
+  void update_position(sg_offset_t);      /** set new position in file, grow it if necessary, and increased usage */
 
   /** Rename a file. WARNING: It is forbidden to move the file to another mount point */
   void move(const std::string& fullpath) const;
index b0cdbf2..aa97e9f 100644 (file)
@@ -82,6 +82,7 @@ public:
 
   Host* get_host() const;
   unsigned int get_host_number() const;
+  int get_thread_count() const;
   double get_cost() const;
   bool is_parallel() const { return parallel_; }
   bool is_assigned() const override;
index 5317dee..d5a0100 100644 (file)
@@ -41,4 +41,5 @@
 
 #define exit(x) smpi_exit(x)
 
+#define getpid smpi_getpid
 #endif
index 53ca8a7..26f2148 100644 (file)
 #include <unistd.h>
 
 #include <sys/time.h>
+#include <sys/types.h>
 #if _POSIX_TIMERS
 #include <time.h>
 #endif
 
+#if !defined(SMPI_NO_OVERRIDE_MALLOC) && !defined(__GLIBC__)
+/* For musl libc, <sched.h> must be included before #defining calloc(). Testing if !defined(__GLIBC__) is a bit crude
+ * but I don't know a better way. */
+#include <sched.h>
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -38,6 +45,8 @@ void* smpi_shared_malloc_intercept(size_t size, const char* file, int line);
 void* smpi_shared_calloc_intercept(size_t num_elm, size_t elem_size, const char* file, int line);
 void* smpi_shared_realloc_intercept(void* data, size_t size, const char* file, int line);
 void smpi_shared_free(void* data);
+
+pid_t smpi_getpid();
 #ifdef __cplusplus
 [[noreturn]] // c++11
 #else
index e5fd1ef..86de02c 100644 (file)
@@ -1,5 +1,4 @@
-/* Copyright (c) 2016-2022. The SimGrid Team.
- * All rights reserved.                                                     */
+/* Copyright (c) 2016-2022. 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. */
index 5d2b646..507a2cb 100644 (file)
@@ -48,6 +48,12 @@ public final class NativeLib {
                NativeLib.nativeInit("simgrid");
                NativeLib.nativeInit("simgrid-java");
                isNativeInited = true;
+
+                /* Don't leak the files on disk */
+                if (tempDir != null) {
+                  FileCleaner fclean = new FileCleaner(tempDir.toFile());
+                  fclean.run();
+                }
        }
 
        /** Helper function trying to load one requested library */
@@ -108,8 +114,6 @@ public final class NativeLib {
                        }
 
                        tempDir = Files.createTempDirectory(tempPrefix);
-                       // don't leak the files on disk, but remove it on JVM shutdown
-                       Runtime.getRuntime().addShutdownHook(new Thread(new FileCleaner(tempDir.toFile())));
                }
 
                /* For each possible filename of the given library on all possible OSes, try it */
index f2b85ac..bdff2c1 100644 (file)
 
 #include "src/internal_config.h"
 
+/** Environment variable name used to pass the communication socket.
+ *
+ * It is set by `simgrid-mc` to enable MC support in the children processes.
+ *
+ * It is placed in this file so that it's visible from mmalloc and MC without sharing anythin of xbt in mmalloc
+ */
+#define MC_ENV_SOCKET_FD "SIMGRID_MC_SOCKET_FD"
+
 #include <stdio.h>     /* for NULL */
 #include <sys/types.h> /* for size_t */
 
-#include "xbt/dict.h"
-#include "xbt/dynar.h"
-
 SG_BEGIN_DECL
 
 /* Datatype representing a separate heap. The whole point of the mmalloc module is to allow several such heaps in the
@@ -45,13 +50,14 @@ XBT_PUBLIC void mfree(xbt_mheap_t md, void* ptr);
 
 XBT_PUBLIC xbt_mheap_t xbt_mheap_new(void* baseaddr, int options);
 
-XBT_PUBLIC void xbt_mheap_destroy_no_free(xbt_mheap_t md);
-
 XBT_PUBLIC void* xbt_mheap_destroy(xbt_mheap_t md);
 
 /* To get the heap used when using the legacy version malloc/free/realloc and such */
 xbt_mheap_t mmalloc_get_current_heap(void);
 
+/* Returns true if we are using the internal mmalloc, and false if we are using the libc's malloc */
+XBT_PUBLIC int malloc_use_mmalloc(void);
+
 #endif
 SG_END_DECL
 
index 254f554..5913b17 100644 (file)
@@ -20,9 +20,6 @@ void xbt_log_postexit(void);
 void xbt_dict_preinit(void);
 void xbt_dict_postexit(void);
 
-xbt_mheap_t mmalloc_preinit(void);
-void mmalloc_postexit(void);
-
 extern int xbt_initialized;
 
 SG_END_DECL
index e989fd4..cec90b8 100644 (file)
@@ -279,7 +279,7 @@ static void on_container_creation_ti(const Container& c)
 #ifdef WIN32
     _mkdir(folder_name.c_str());
 #else
-    mkdir(folder_name.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+    mkdir(folder_name.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
 #endif
     ti_unique_file = new std::ofstream(filename.c_str(), std::ofstream::out);
     xbt_assert(not ti_unique_file->fail(), "Tracefile %s could not be opened for writing", filename.c_str());
index 44092c2..a5a68af 100644 (file)
@@ -34,11 +34,9 @@ void dump_comment_file(const std::string& filename)
     throw TracingError(XBT_THROW_POINT,
                        xbt::string_printf("Comment file %s could not be opened for reading.", filename.c_str()));
 
-  while (not fs.eof()) {
-    std::string line;
-    std::getline(fs, line);
+  std::string line;
+  while (std::getline(fs, line))
     tracing_file << "# " << line;
-  }
   fs.close();
 }
 
index 00d0f16..717e771 100644 (file)
@@ -178,10 +178,6 @@ EngineImpl::~EngineImpl()
   delete maestro_;
   delete context_factory_;
 
-  /* Free the remaining data structures */
-#if SIMGRID_HAVE_MC
-  xbt_dynar_free(&actors_vector_);
-#endif
   /* clear models before freeing handle, network models can use external callback defined in the handle */
   models_prio_.clear();
 }
@@ -195,7 +191,7 @@ void EngineImpl::initialize(int* argc, char** argv)
   // The communication initialization is done ASAP, as we need to get some init parameters from the MC for different
   // layers. But instance_ needs to be created, as we send the address of some of its fields to the MC that wants to
   // read them directly.
-  simgrid::mc::AppSide::initialize(actors_vector_);
+  simgrid::mc::AppSide::initialize();
 #endif
 
   if (xbt_initialized == 0) {
index 6ea9106..d2d4108 100644 (file)
@@ -48,16 +48,6 @@ class EngineImpl {
                          boost::intrusive::member_hook<actor::ActorImpl, boost::intrusive::list_member_hook<>,
                                                        &actor::ActorImpl::kernel_destroy_list_hook>>
       actors_to_destroy_;
-#if SIMGRID_HAVE_MC
-  /* MCer cannot read members actor_list_ above in the remote process, so we copy the info it needs in a dynar.
-   * FIXME: This is supposed to be a temporary hack.
-   * A better solution would be to change the split between MCer and MCed, where the responsibility
-   *   to compute the list of the enabled transitions goes to the MCed.
-   * That way, the MCer would not need to have the list of actors on its side.
-   * These info could be published by the MCed to the MCer in a way inspired of vd.so
-   */
-  xbt_dynar_t actors_vector_      = xbt_dynar_new(sizeof(actor::ActorImpl*), nullptr);
-#endif
 
   static double now_;
   static EngineImpl* instance_;
@@ -136,11 +126,6 @@ public:
   void add_actor(aid_t pid, actor::ActorImpl* actor) { actor_list_[pid] = actor; }
   void remove_actor(aid_t pid) { actor_list_.erase(pid); }
 
-#if SIMGRID_HAVE_MC
-  void reset_actor_dynar() { xbt_dynar_reset(actors_vector_); }
-  void add_actor_to_dynar(actor::ActorImpl* actor) { xbt_dynar_push_as(actors_vector_, actor::ActorImpl*, actor); }
-#endif
-
   const std::map<aid_t, actor::ActorImpl*>& get_actor_list() const { return actor_list_; }
   const std::vector<actor::ActorImpl*>& get_actors_to_run() const { return actors_to_run_; }
   const std::vector<actor::ActorImpl*>& get_actors_that_ran() const { return actors_that_ran_; }
index c75799a..1f373dd 100644 (file)
@@ -140,12 +140,13 @@ void ActivityImpl::wait_any_for(actor::ActorImpl* issuer, const std::vector<Acti
     auto* observer = dynamic_cast<kernel::actor::ActivityWaitanySimcall*>(issuer->simcall_.observer_);
     xbt_assert(observer != nullptr);
     xbt_assert(timeout <= 0.0, "Timeout not implemented for waitany in the model-checker");
-    int idx   = observer->get_value();
-    auto* act = activities[idx];
-    act->simcalls_.push_back(&issuer->simcall_);
-    observer->set_result(idx);
-    act->set_state(State::DONE);
-    act->finish();
+    if (int idx = observer->get_value(); idx != -1) {
+      auto* act = activities.at(idx);
+      act->simcalls_.push_back(&issuer->simcall_);
+      observer->set_result(idx);
+      act->set_state(State::DONE);
+      act->finish();
+    }
     return;
   }
 
index e027255..ed8a0f4 100644 (file)
@@ -542,6 +542,9 @@ void CommImpl::finish()
   if (get_state() == State::DONE)
     copy_data();
 
+  if (detached_)
+    EngineImpl::get_instance()->get_maestro()->activities_.remove(this);
+
   while (not simcalls_.empty()) {
     actor::Simcall* simcall = simcalls_.front();
     simcalls_.pop_front();
index 22dfb5c..ed936f2 100644 (file)
@@ -42,6 +42,7 @@ public:
   ExecImpl& set_hosts(const std::vector<s4u::Host*>& hosts);
 
   unsigned int get_host_number() const { return static_cast<unsigned>(get_hosts().size()); }
+  int get_thread_count() const { return thread_count_; }
   double get_seq_remaining_ratio();
   double get_par_remaining_ratio();
   double get_remaining() const override;
index 7ee160c..b738381 100644 (file)
@@ -21,7 +21,11 @@ unsigned MailboxImpl::next_id_ = 0;
 
 MailboxImpl::~MailboxImpl()
 {
-  clear(false);
+  try {
+    clear(false);
+  } catch (const std::bad_alloc& ba) {
+    XBT_ERROR("MailboxImpl::clear() failure: %s", ba.what());
+  }
   set_receiver(nullptr);
 }
 
index f44571e..e15d6aa 100644 (file)
@@ -18,16 +18,16 @@ namespace simgrid::kernel::actor {
 
 ActivityTestanySimcall::ActivityTestanySimcall(ActorImpl* actor, const std::vector<activity::ActivityImpl*>& activities)
     : ResultingSimcall(actor, -1), activities_(activities)
-{
-}
-
-int ActivityTestanySimcall::get_max_consider()
 {
   indexes_.clear();
   // list all the activities that are ready
   for (unsigned i = 0; i < activities_.size(); i++)
     if (activities_[i]->test(get_issuer()))
       indexes_.push_back(i);
+}
+
+int ActivityTestanySimcall::get_max_consider() const
+{
   return indexes_.size() + 1;
 }
 
@@ -94,6 +94,11 @@ ActivityWaitanySimcall::ActivityWaitanySimcall(ActorImpl* actor, const std::vect
                                                double timeout)
     : ResultingSimcall(actor, -1), activities_(activities), timeout_(timeout)
 {
+  // list all the activities that are ready
+  indexes_.clear();
+  for (unsigned i = 0; i < activities_.size(); i++)
+    if (activities_[i]->test(get_issuer()))
+      indexes_.push_back(i);
 }
 
 bool ActivityWaitSimcall::is_enabled()
@@ -119,14 +124,8 @@ bool ActivityWaitanySimcall::is_enabled()
   return not indexes_.empty();
 }
 
-int ActivityWaitanySimcall::get_max_consider()
+int ActivityWaitanySimcall::get_max_consider() const
 {
-  // list all the activities that are ready
-  indexes_.clear();
-  for (unsigned i = 0; i < activities_.size(); i++)
-    if (activities_[i]->test(get_issuer()))
-      indexes_.push_back(i);
-
   int res = indexes_.size();
   //  if (_sg_mc_timeout && timeout_)
   //    res++;
index 9cba17d..41607aa 100644 (file)
@@ -38,7 +38,7 @@ public:
   bool is_visible() const override { return true; }
   bool is_enabled() override { return true; /* can return -1 if no activity is ready */ }
   void serialize(std::stringstream& stream) const override;
-  int get_max_consider() override;
+  int get_max_consider() const override;
   void prepare(int times_considered) override;
   const std::vector<activity::ActivityImpl*>& get_activities() const { return activities_; }
   int get_value() const { return next_value_; }
@@ -73,7 +73,7 @@ public:
   void serialize(std::stringstream& stream) const override;
   bool is_visible() const override { return true; }
   void prepare(int times_considered) override;
-  int get_max_consider() override;
+  int get_max_consider() const override;
   const std::vector<activity::ActivityImpl*>& get_activities() const { return activities_; }
   double get_timeout() const { return timeout_; }
   int get_value() const { return next_value_; }
index e4ffca2..87991cc 100644 (file)
@@ -32,7 +32,7 @@ void RandomSimcall::prepare(int times_considered)
   XBT_DEBUG("MC_RANDOM(%d, %d) will return %d after %d times", min_, max_, next_value_, times_considered);
 }
 
-int RandomSimcall::get_max_consider()
+int RandomSimcall::get_max_consider() const
 {
   return max_ - min_ + 1;
 }
index 6eabf88..a4095e4 100644 (file)
@@ -37,7 +37,7 @@ public:
    * If it's more than one (as with mc_random or waitany), we need to consider this transition several times to start
    * differing branches
    */
-  virtual int get_max_consider() { return 1; }
+  virtual int get_max_consider() const { return 1; }
 
   /** Prepares the simcall to be used.
    *
@@ -83,7 +83,7 @@ public:
     xbt_assert(min < max);
   }
   void serialize(std::stringstream& stream) const override;
-  int get_max_consider() override;
+  int get_max_consider() const override;
   void prepare(int times_considered) override;
   int get_value() const { return next_value_; }
 };
index 24b2b1f..98f7832 100644 (file)
@@ -8,7 +8,7 @@
 #include "mc/mc.h"
 #include "simgrid/Exception.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
-#include "src/mc/mc_ignore.hpp"
+#include "src/mc/remote/AppSide.hpp"
 
 #include "ContextUnix.hpp"
 
@@ -62,9 +62,8 @@ UContext::UContext(std::function<void()>&& code, actor::ActorImpl* actor, Swappe
     makecontext(&this->uc_, (void (*)())sysv_ctx_wrapper, 2, ctx_addr[0], ctx_addr[1]);
 
 #if SIMGRID_HAVE_MC
-    if (MC_is_active()) {
-      MC_register_stack_area(get_stack(), &(this->uc_), stack_size);
-    }
+    if (MC_is_active())
+      simgrid::mc::AppSide::get()->declare_stack(get_stack(), stack_size, &uc_);
 #endif
   }
 }
index 326b404..2f7f25f 100644 (file)
@@ -57,7 +57,7 @@ void Element::increase_concurrency(bool check_limit)
              "Concurrency limit overflow!");
 }
 
-System* System::build(const std::string& solver_name, bool selective_update)
+System* System::build(std::string_view solver_name, bool selective_update)
 {
   System* system = nullptr;
   if (solver_name == "bmf") {
@@ -270,18 +270,20 @@ Element& System::expand_add_to_elem(Element& elem, const Constraint* cnst, doubl
   return elem;
 }
 
-void System::expand(Constraint* cnst, Variable* var, double consumption_weight)
+void System::expand(Constraint* cnst, Variable* var, double consumption_weight, bool force_creation)
 {
   modified_ = true;
 
   auto elem_it =
       std::find_if(begin(var->cnsts_), end(var->cnsts_), [&cnst](Element const& x) { return x.constraint == cnst; });
-  if (elem_it != end(var->cnsts_) && var->sharing_penalty_ != 0.0) {
+
+  bool reuse_elem = elem_it != end(var->cnsts_) && not force_creation;
+  if (reuse_elem && var->sharing_penalty_ != 0.0) {
     /* before changing it, decreases concurrency on constraint, it'll be added back later */
     elem_it->decrease_concurrency();
   }
-  Element& elem = elem_it != end(var->cnsts_) ? expand_add_to_elem(*elem_it, cnst, consumption_weight)
-                                              : expand_create_elem(cnst, var, consumption_weight);
+  Element& elem = reuse_elem ? expand_add_to_elem(*elem_it, cnst, consumption_weight)
+                             : expand_create_elem(cnst, var, consumption_weight);
 
   // Check if we need to disable the variable
   if (var->sharing_penalty_ != 0) {
index 173d044..a0505ce 100644 (file)
@@ -18,6 +18,7 @@
 #include <cmath>
 #include <limits>
 #include <memory>
+#include <string_view>
 #include <vector>
 
 namespace simgrid::kernel::lmm {
@@ -418,7 +419,7 @@ public:
    * @param selective_update Enables lazy updates
    * @return pointer to System instance
    */
-  static System* build(const std::string& solver_name, bool selective_update);
+  static System* build(std::string_view solver_name, bool selective_update);
   /** @brief Validates solver configuration */
   static void validate_solver(const std::string& solver_name);
 
@@ -464,8 +465,11 @@ public:
    * @param cnst A constraint
    * @param var A variable
    * @param value The coefficient associated to the variable in the constraint
+   * @param force_creation Force the creation of new element linking the variable to the constraint. Should be used only
+   * by the model ptask_L07 to cope with ptasks composed of flows running on the same resource (see
+   * https://framagit.org/simgrid/simgrid/-/issues/111)
    */
-  void expand(Constraint * cnst, Variable * var, double value);
+  void expand(Constraint* cnst, Variable* var, double value, bool force_creation = false);
 
   /** @brief Update the bound of a variable */
   void update_variable_bound(Variable * var, double bound);
index b6647a6..24d6638 100644 (file)
@@ -4,7 +4,6 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/kernel/lmm/bmf.hpp"
-#include "xbt/config.hpp"
 
 #include <Eigen/LU>
 #include <iostream>
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_bmf, kernel, "Kernel BMF solver");
 
-simgrid::config::Flag<int>
-    cfg_bmf_max_iteration("bmf/max-iterations",
-                          "Maximum number of steps to be performed while searching for a BMF allocation", 1000);
-
-simgrid::config::Flag<double> cfg_bmf_precision{"bmf/precision",
-                                                "Numerical precision used when computing resource sharing", 1E-12};
-
 namespace simgrid::kernel::lmm {
 
 AllocationGenerator::AllocationGenerator(Eigen::MatrixXd A) : A_(std::move(A)), alloc_(A_.cols(), 0)
@@ -71,7 +63,6 @@ BmfSolver::BmfSolver(Eigen::MatrixXd A, Eigen::MatrixXd maxA, Eigen::VectorXd C,
     , C_shared_(std::move(shared))
     , phi_(std::move(phi))
     , gen_(A_)
-    , max_iteration_(cfg_bmf_max_iteration)
 
 {
   xbt_assert(max_iteration_ > 0,
index dfc7ff9..fa6b8bb 100644 (file)
@@ -7,6 +7,7 @@
 #define SIMGRID_KERNEL_LMM_BMF_HPP
 
 #include "src/kernel/lmm/System.hpp"
+#include "xbt/config.hpp"
 
 #ifdef __clang__
 // Ignore deprecation warnings with Eigen < 4.0 (see https://gitlab.com/libeigen/eigen/-/issues/1850)
@@ -73,6 +74,12 @@ private:
  * @endrst
  */
 class XBT_PUBLIC BmfSolver {
+  inline static simgrid::config::Flag<int> cfg_bmf_max_iteration{
+      "bmf/max-iterations", "Maximum number of steps to be performed while searching for a BMF allocation", 1000};
+
+  inline static simgrid::config::Flag<double> cfg_bmf_precision{
+      "bmf/precision", "Numerical precision used when computing resource sharing", 1E-12};
+
 public:
   /**
    * @brief Instantiate the BMF solver
@@ -195,7 +202,7 @@ private:
   std::set<std::vector<int>> allocations_; //!< set of already tested allocations, since last identified loop
   AllocationGenerator gen_;
   static constexpr int NO_RESOURCE = -1;                    //!< flag to indicate player has selected no resource
-  int max_iteration_;                                       //!< number maximum of iterations of BMF algorithm
+  int max_iteration_               = cfg_bmf_max_iteration; //!< number maximum of iterations of BMF algorithm
 };
 
 /**
index 29198e1..07709ce 100644 (file)
@@ -29,7 +29,7 @@ xbt::signal<void(DiskAction const&, Action::State, Action::State)> DiskAction::o
 
 DiskModel::DiskModel(const std::string& name) : Model(name)
 {
-  set_maxmin_system(lmm::System::build(cfg_disk_solver, true /* selective update */));
+  set_maxmin_system(lmm::System::build(cfg_disk_solver.get(), true /* selective update */));
 }
 
 /************
index 854aafc..cda3fdb 100644 (file)
@@ -71,7 +71,8 @@ static void add_active_exec(s4u::Exec const& task)
   const s4u::VirtualMachine* vm = dynamic_cast<s4u::VirtualMachine*>(task.get_host());
   if (vm != nullptr) {
     VirtualMachineImpl* vm_impl = vm->get_vm_impl();
-    vm_impl->add_active_exec();
+    for (int i = 1; i <= task.get_thread_count(); i++)
+      vm_impl->add_active_exec();
     vm_impl->update_action_weight();
   }
 }
@@ -86,7 +87,8 @@ static void remove_active_exec(s4u::Activity const& task)
   const s4u::VirtualMachine* vm = dynamic_cast<s4u::VirtualMachine*>(exec->get_host());
   if (vm != nullptr) {
     VirtualMachineImpl* vm_impl = vm->get_vm_impl();
-    vm_impl->remove_active_exec();
+    for (int i = 1; i <= exec->get_thread_count(); i++)
+      vm_impl->remove_active_exec();
     vm_impl->update_action_weight();
   }
 }
index 038a0ea..d31d31a 100644 (file)
@@ -237,8 +237,8 @@ Profile* ProfileBuilder::from_file(const std::string& path)
 
 
 Profile* ProfileBuilder::from_void() {
-  static Profile void_profile("__void__", nullptr, -1.0);
-  return &void_profile;
+  static auto* void_profile = new Profile("__void__", nullptr, -1.0);
+  return void_profile;
 }
 
 Profile* ProfileBuilder::from_callback(const std::string& name, const std::function<UpdateCb>& cb, double repeat_delay) {
index 851b140..3c6bfc6 100644 (file)
@@ -77,8 +77,8 @@ void FatTreeZone::get_local_route(const NetPoint* src, const NetPoint* dst, Rout
     for (unsigned int i = 0; i < currentNode->level; i++)
       d /= this->num_parents_per_node_[i];
 
-    int k = this->num_parents_per_node_[currentNode->level];
-    d     = d % k;
+    int k = this->num_parents_per_node_[currentNode->level] * this->num_port_lower_level_[currentNode->level];
+    d = d % k;
 
     if (currentNode->limiter_link_)
       into->link_list_.push_back(currentNode->limiter_link_);
@@ -93,7 +93,9 @@ void FatTreeZone::get_local_route(const NetPoint* src, const NetPoint* dst, Rout
 
   // Down part
   while (currentNode != destination) {
-    for (unsigned int i = 0; i < currentNode->children.size(); i++) {
+    //pick cable when multiple parallels
+    int d = source->position % this->num_port_lower_level_[currentNode->level - 1];
+    for (unsigned int i = d * this->num_children_per_node_[currentNode->level - 1]; i < currentNode->children.size(); i++) {
       if (i % this->num_children_per_node_[currentNode->level - 1] == destination->label[currentNode->level - 1]) {
         add_link_latency(into->link_list_, currentNode->children[i]->down_link_, latency);
 
index 1e3c2be..17e2bce 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "src/mc/ModelChecker.hpp"
 #include "src/mc/explo/Exploration.hpp"
+#include "src/mc/explo/LivenessChecker.hpp"
 #include "src/mc/mc_config.hpp"
 #include "src/mc/mc_exit.hpp"
 #include "src/mc/mc_private.hpp"
@@ -66,8 +67,13 @@ void ModelChecker::start()
   xbt_assert(waitpid(pid, &status, WAITPID_CHECKED_FLAGS) == pid && WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP,
              "Could not wait model-checked process");
 
-  if (not _sg_mc_dot_output_file.get().empty())
-    MC_init_dot_output();
+  if (not _sg_mc_dot_output_file.get().empty()) {
+    dot_output_ = fopen(_sg_mc_dot_output_file.get().c_str(), "w");
+    xbt_assert(dot_output_ != nullptr, "Error open dot output file: %s", strerror(errno));
+
+    fprintf(dot_output_, "digraph graphname{\n fixedsize=true; rankdir=TB; ranksep=.25; edge [fontsize=12]; node "
+                         "[fontsize=10, shape=circle,width=.5 ]; graph [resolution=20, fontsize=10];\n");
+  }
 
   setup_ignore();
 
@@ -87,6 +93,16 @@ void ModelChecker::start()
              errno);
 }
 
+void ModelChecker::dot_output(const char* fmt, ...)
+{
+  if (dot_output_ != nullptr) {
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(dot_output_, fmt, ap);
+    va_end(ap);
+  }
+}
+
 static constexpr auto ignored_local_variables = {
     std::make_pair("e", "*"),
     std::make_pair("_log_ev", "*"),
@@ -125,7 +141,7 @@ void ModelChecker::resume()
   remote_process_->clear_cache();
 }
 
-static void MC_report_crash(int status)
+static void MC_report_crash(Exploration* explorer, int status)
 {
   XBT_INFO("**************************");
   XBT_INFO("** CRASH IN THE PROGRAM **");
@@ -136,12 +152,12 @@ static void MC_report_crash(int status)
     XBT_INFO("From exit: %i", WEXITSTATUS(status));
   if (not xbt_log_no_loc)
     XBT_INFO("%s core dump was generated by the system.", WCOREDUMP(status) ? "A" : "No");
-  if (mc_model_checker->get_exploration()) {
+  if (explorer) {
     XBT_INFO("Counter-example execution trace:");
-    for (auto const& s : mc_model_checker->get_exploration()->get_textual_trace())
+    for (auto const& s : explorer->get_textual_trace())
       XBT_INFO("  %s", s.c_str());
-    XBT_INFO("Path = %s", mc_model_checker->get_exploration()->get_record_trace().to_string().c_str());
-    Api::get().get_session().log_state();
+    XBT_INFO("Path = %s", explorer->get_record_trace().to_string().c_str());
+    explorer->log_state();
     if (xbt_log_no_loc) {
       XBT_INFO("Stack trace not displayed because you passed --log=no_loc");
     } else {
@@ -163,7 +179,7 @@ bool ModelChecker::handle_message(const char* buffer, ssize_t size)
       xbt_assert(size == sizeof(message), "Broken message. Got %d bytes instead of %d.", (int)size, (int)sizeof(message));
       memcpy(&message, buffer, sizeof(message));
 
-      get_remote_process().init(message.mmalloc_default_mdp, message.maxpid, message.actors);
+      get_remote_process().init(message.mmalloc_default_mdp, message.maxpid);
       break;
     }
 
@@ -211,14 +227,7 @@ bool ModelChecker::handle_message(const char* buffer, ssize_t size)
       xbt_assert(not message.callback, "Support for client-side function proposition is not implemented.");
       XBT_DEBUG("Received symbol: %s", message.name.data());
 
-      if (property_automaton == nullptr)
-        property_automaton = xbt_automaton_new();
-
-      const RemoteProcess* process    = &this->get_remote_process();
-      RemotePtr<int> address          = remote((int*)message.data);
-      xbt::add_proposition(property_automaton, message.name.data(),
-                           [process, address]() { return process->read(address); });
-
+      LivenessChecker::automaton_register_symbol(get_remote_process(), message.name.data(), remote((int*)message.data));
       break;
     }
 
@@ -233,7 +242,7 @@ bool ModelChecker::handle_message(const char* buffer, ssize_t size)
       for (auto const& s : get_exploration()->get_textual_trace())
         XBT_INFO("  %s", s.c_str());
       XBT_INFO("Path = %s", get_exploration()->get_record_trace().to_string().c_str());
-      Api::get().get_session().log_state();
+      exploration_->log_state();
 
       this->exit(SIMGRID_MC_EXIT_SAFETY);
 
@@ -273,7 +282,7 @@ void ModelChecker::handle_waitpid()
       if (status>>8 == (SIGTRAP | (PTRACE_EVENT_EXIT<<8))) {
         xbt_assert(ptrace(PTRACE_GETEVENTMSG, remote_process_->pid(), 0, &status) != -1, "Could not get exit status");
         if (WIFSIGNALED(status)) {
-          MC_report_crash(status);
+          MC_report_crash(exploration_, status);
           this->get_remote_process().terminate();
           this->exit(SIMGRID_MC_EXIT_PROGRAM_CRASH);
         }
@@ -293,7 +302,7 @@ void ModelChecker::handle_waitpid()
       }
 
       else if (WIFSIGNALED(status)) {
-        MC_report_crash(status);
+        MC_report_crash(exploration_, status);
         this->get_remote_process().terminate();
         this->exit(SIMGRID_MC_EXIT_PROGRAM_CRASH);
       } else if (WIFEXITED(status)) {
@@ -349,7 +358,11 @@ void ModelChecker::finalize_app(bool terminate_asap)
   xbt_assert(checker_side_.get_channel().send(m) == 0, "Could not ask the app to finalize on need");
 
   s_mc_message_t answer;
-  xbt_assert(checker_side_.get_channel().receive(answer) != -1, "Could not receive answer to FINALIZE");
+  ssize_t s = checker_side_.get_channel().receive(answer);
+  xbt_assert(s != -1, "Could not receive answer to FINALIZE");
+  xbt_assert(s == sizeof(answer) && answer.type == MessageType::FINALIZE_REPLY,
+             "Received unexpected message %s (%i, size=%i) expected MessageType::FINALIZE_REPLY (%i, size=%i)",
+             to_c_str(answer.type), (int)answer.type, (int)s, (int)MessageType::FINALIZE_REPLY, (int)sizeof(answer));
 }
 
 } // namespace simgrid::mc
index c4b1894..09fbfcb 100644 (file)
@@ -28,10 +28,9 @@ class ModelChecker {
   std::unique_ptr<RemoteProcess> remote_process_;
   Exploration* exploration_ = nullptr;
 
-  unsigned long visited_states_ = 0;
+  FILE* dot_output_ = nullptr;
 
-  // Expect MessageType::SIMCALL_TO_STRING or MessageType::SIMCALL_DOT_LABEL
-  std::string simcall_to_string(MessageType type, aid_t aid, int times_considered);
+  unsigned long visited_states_ = 0;
 
 public:
   ModelChecker(ModelChecker const&) = delete;
@@ -66,6 +65,18 @@ public:
   unsigned long get_visited_states() const { return visited_states_; }
   void inc_visited_states() { visited_states_++; }
 
+  void dot_output(const char* fmt, ...) XBT_ATTRIB_PRINTF(2, 3);
+  void dot_output_flush()
+  {
+    if (dot_output_ != nullptr)
+      fflush(dot_output_);
+  }
+  void dot_output_close()
+  {
+    if (dot_output_ != nullptr)
+      fclose(dot_output_);
+  }
+
 private:
   void setup_ignore();
   bool handle_message(const char* buffer, ssize_t size);
index 6e46c3c..8264c2a 100644 (file)
@@ -4,23 +4,23 @@
  * 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_private.hpp"
 
 #include <unistd.h>
 #include <sys/wait.h>
 #include <memory>
 #include <boost/range/algorithm.hpp>
-#include "src/mc/api.hpp"
 
 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) : num(state_number)
+VisitedState::VisitedState(unsigned long state_number, unsigned int actor_count)
+    : actor_count_(actor_count), num(state_number)
 {
-  this->heap_bytes_used = Api::get().get_remote_heap_bytes();
-  this->actors_count    = Api::get().get_actors().size();
+  this->heap_bytes_used = mc_model_checker->get_remote_process().get_remote_heap_bytes();
   this->system_state = std::make_shared<simgrid::mc::Snapshot>(state_number);
 }
 
@@ -39,45 +39,42 @@ void VisitedStates::prune()
 }
 
 /** @brief Checks whether a given state has already been visited by the algorithm. */
-std::unique_ptr<simgrid::mc::VisitedState>
-VisitedStates::addVisitedState(unsigned long state_number, simgrid::mc::State* graph_state, bool compare_snapshots)
+std::unique_ptr<simgrid::mc::VisitedState> VisitedStates::addVisitedState(unsigned long state_number,
+                                                                          simgrid::mc::State* graph_state)
 {
-  auto new_state             = std::make_unique<simgrid::mc::VisitedState>(state_number);
+  auto new_state = std::make_unique<simgrid::mc::VisitedState>(state_number, graph_state->get_actor_count());
   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(), Api::get().compare_pair());
+  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);
+  });
 
-  if (compare_snapshots)
-    for (auto i = range_begin; i != range_end; ++i) {
-      auto& visited_state = *i;
-      if (Api::get().snapshot_equal(visited_state->system_state.get(), new_state->system_state.get())) {
-        // The state has been visited:
+  for (auto i = range_begin; i != range_end; ++i) {
+    auto& visited_state = *i;
+    if (*visited_state->system_state.get() == *new_state->system_state.get()) {
+      // The state has been visited:
 
-        std::unique_ptr<simgrid::mc::VisitedState> old_state =
-          std::move(visited_state);
+      std::unique_ptr<simgrid::mc::VisitedState> 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;
+      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;
 
-        if (dot_output == nullptr)
-          XBT_DEBUG("State %ld already visited ! (equal to state %ld)", new_state->num, old_state->num);
-        else
-          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);
+      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);
+      /* 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;
-      }
+      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));
index 33f3d1a..9cec57a 100644 (file)
@@ -18,11 +18,11 @@ class XBT_PRIVATE VisitedState {
 public:
   std::shared_ptr<simgrid::mc::Snapshot> system_state = nullptr;
   std::size_t heap_bytes_used = 0;
-  int actors_count            = 0;
-  long num                                            = 0; // unique id of that state in the storage of all stored IDs
+  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);
+  explicit VisitedState(unsigned long state_number, unsigned int actor_count);
 };
 
 class XBT_PRIVATE VisitedStates {
@@ -30,7 +30,7 @@ class XBT_PRIVATE VisitedStates {
 public:
   void clear() { states_.clear(); }
   std::unique_ptr<simgrid::mc::VisitedState> addVisitedState(unsigned long state_number,
-                                                             simgrid::mc::State* graph_state, bool compare_snapshots);
+                                                             simgrid::mc::State* graph_state);
 
 private:
   void prune();
diff --git a/src/mc/api.cpp b/src/mc/api.cpp
deleted file mode 100644 (file)
index 840ffef..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/* Copyright (c) 2020-2022. 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 "api.hpp"
-
-#include "src/kernel/activity/MailboxImpl.hpp"
-#include "src/kernel/activity/MutexImpl.hpp"
-#include "src/kernel/actor/SimcallObserver.hpp"
-#include "src/mc/Session.hpp"
-#include "src/mc/explo/Exploration.hpp"
-#include "src/mc/mc_base.hpp"
-#include "src/mc/mc_exit.hpp"
-#include "src/mc/mc_pattern.hpp"
-#include "src/mc/mc_private.hpp"
-#include "src/mc/remote/RemoteProcess.hpp"
-#include "src/surf/HostImpl.hpp"
-
-#include <xbt/asserts.h>
-#include <xbt/log.h>
-#include "simgrid/s4u/Host.hpp"
-#include "xbt/string.hpp"
-#if HAVE_SMPI
-#include "src/smpi/include/smpi_request.hpp"
-#endif
-
-XBT_LOG_NEW_DEFAULT_SUBCATEGORY(Api, mc, "Logging specific to MC Facade APIs ");
-XBT_LOG_EXTERNAL_CATEGORY(mc_global);
-
-namespace simgrid::mc {
-
-simgrid::mc::Exploration* Api::initialize(char** argv, simgrid::mc::ExplorationAlgorithm algo)
-{
-  session_ = std::make_unique<simgrid::mc::Session>([argv] {
-    int i = 1;
-    while (argv[i] != nullptr && argv[i][0] == '-')
-      i++;
-    xbt_assert(argv[i] != nullptr,
-               "Unable to find a binary to exec on the command line. Did you only pass config flags?");
-    execvp(argv[i], argv + i);
-    xbt_die("The model-checked process failed to exec(%s): %s", argv[i], strerror(errno));
-  });
-
-  simgrid::mc::Exploration* explo;
-  switch (algo) {
-    case ExplorationAlgorithm::CommDeterminism:
-      explo = simgrid::mc::create_communication_determinism_checker(session_.get());
-      break;
-
-    case ExplorationAlgorithm::UDPOR:
-      explo = simgrid::mc::create_udpor_checker(session_.get());
-      break;
-
-    case ExplorationAlgorithm::Safety:
-      explo = simgrid::mc::create_dfs_exploration(session_.get());
-      break;
-
-    case ExplorationAlgorithm::Liveness:
-      explo = simgrid::mc::create_liveness_checker(session_.get());
-      break;
-
-    default:
-      THROW_IMPOSSIBLE;
-  }
-
-  mc_model_checker->set_exploration(explo);
-  return explo;
-}
-
-std::vector<simgrid::mc::ActorInformation>& Api::get_actors() const
-{
-  return mc_model_checker->get_remote_process().actors();
-}
-
-unsigned long Api::get_maxpid() const
-{
-  return mc_model_checker->get_remote_process().get_maxpid();
-}
-
-std::size_t Api::get_remote_heap_bytes() const
-{
-  RemoteProcess& process    = mc_model_checker->get_remote_process();
-  auto heap_bytes_used      = mmalloc_get_bytes_used_remote(process.get_heap()->heaplimit, process.get_malloc_info());
-  return heap_bytes_used;
-}
-
-void Api::mc_inc_visited_states() const
-{
-  mc_model_checker->inc_visited_states();
-}
-
-unsigned long Api::mc_get_visited_states() const
-{
-  return mc_model_checker->get_visited_states();
-}
-
-void Api::mc_exit(int status) const
-{
-  mc_model_checker->exit(status);
-}
-
-void Api::restore_state(const simgrid::mc::Snapshot* system_state) const
-{
-  system_state->restore(&mc_model_checker->get_remote_process());
-}
-
-bool Api::snapshot_equal(const Snapshot* s1, const Snapshot* s2) const
-{
-  return simgrid::mc::snapshot_equal(s1, s2);
-}
-
-simgrid::mc::Snapshot* Api::take_snapshot(long num_state) const
-{
-  auto snapshot = new simgrid::mc::Snapshot(num_state);
-  return snapshot;
-}
-
-void Api::s_close()
-{
-  session_.reset();
-  if (simgrid::mc::property_automaton != nullptr) {
-    xbt_automaton_free(simgrid::mc::property_automaton);
-    simgrid::mc::property_automaton = nullptr;
-  }
-}
-
-void Api::automaton_load(const char* file) const
-{
-  if (simgrid::mc::property_automaton == nullptr)
-    simgrid::mc::property_automaton = xbt_automaton_new();
-
-  xbt_automaton_load(simgrid::mc::property_automaton, file);
-}
-
-std::vector<int> Api::automaton_propositional_symbol_evaluate() const
-{
-  unsigned int cursor = 0;
-  std::vector<int> values;
-  xbt_automaton_propositional_symbol_t ps = nullptr;
-  xbt_dynar_foreach (mc::property_automaton->propositional_symbols, cursor, ps)
-    values.push_back(xbt_automaton_propositional_symbol_evaluate(ps));
-  return values;
-}
-
-std::vector<xbt_automaton_state_t> Api::get_automaton_state() const
-{
-  std::vector<xbt_automaton_state_t> automaton_stack;
-  unsigned int cursor = 0;
-  xbt_automaton_state_t automaton_state;
-  xbt_dynar_foreach (mc::property_automaton->states, cursor, automaton_state)
-    if (automaton_state->type == -1)
-      automaton_stack.push_back(automaton_state);
-  return automaton_stack;
-}
-
-int Api::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 (simgrid::mc::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 Api::set_property_automaton(xbt_automaton_state_t const& automaton_state) const
-{
-  mc::property_automaton->current_state = automaton_state;
-}
-
-xbt_automaton_exp_label_t Api::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 Api::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;
-}
-
-} // namespace simgrid::mc
diff --git a/src/mc/api.hpp b/src/mc/api.hpp
deleted file mode 100644 (file)
index 88b2e0c..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* Copyright (c) 2020-2022. 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_API_HPP
-#define SIMGRID_MC_API_HPP
-
-#include <memory>
-#include <vector>
-
-#include "simgrid/forward.h"
-#include "src/mc/Session.hpp"
-#include "src/mc/api/State.hpp"
-#include "src/mc/mc_forward.hpp"
-#include "src/mc/mc_record.hpp"
-#include "xbt/automaton.hpp"
-#include "xbt/base.h"
-
-namespace simgrid::mc {
-
-XBT_DECLARE_ENUM_CLASS(ExplorationAlgorithm, Safety, UDPOR, Liveness, CommDeterminism);
-
-/*
-** This class aimes to implement FACADE APIs for simgrid. The FACADE layer sits between the CheckerSide
-** (Unfolding_Checker, DPOR, ...) layer and the
-** AppSide layer. The goal is to drill down into the entagled details in the CheckerSide layer and break down the
-** detailes in a way that the CheckerSide eventually
-** be capable to acquire the required information through the FACADE layer rather than the direct access to the AppSide.
-*/
-
-class Api {
-private:
-  Api() = default;
-
-  struct DerefAndCompareByActorsCountAndUsedHeap {
-    template <class X, class Y> bool operator()(X const& a, Y const& b) const
-    {
-      return std::make_pair(a->actors_count, a->heap_bytes_used) < std::make_pair(b->actors_count, b->heap_bytes_used);
-    }
-  };
-
-  std::unique_ptr<simgrid::mc::Session> session_;
-
-public:
-  // No copy:
-  Api(Api const&) = delete;
-  void operator=(Api const&) = delete;
-
-  static Api& get()
-  {
-    static Api api;
-    return api;
-  }
-
-  simgrid::mc::Exploration* initialize(char** argv, simgrid::mc::ExplorationAlgorithm algo);
-
-  // ACTOR APIs
-  std::vector<simgrid::mc::ActorInformation>& get_actors() const;
-  unsigned long get_maxpid() const;
-
-  // REMOTE APIs
-  std::size_t get_remote_heap_bytes() const;
-
-  // MODEL CHECKER APIs
-  void mc_inc_visited_states() const;
-  unsigned long mc_get_visited_states() const;
-  XBT_ATTRIB_NORETURN void mc_exit(int status) const;
-
-  // STATE APIs
-  void restore_state(const Snapshot* system_state) const;
-
-  // SNAPSHOT APIs
-  bool snapshot_equal(const Snapshot* s1, const Snapshot* s2) const;
-  simgrid::mc::Snapshot* take_snapshot(long num_state) const;
-
-  // SESSION APIs
-  simgrid::mc::Session const& get_session() const { return *session_; }
-  void s_close();
-
-  // AUTOMATION APIs
-  void automaton_load(const char* file) const;
-  std::vector<int> automaton_propositional_symbol_evaluate() const;
-  std::vector<xbt_automaton_state_t> 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;
-  inline DerefAndCompareByActorsCountAndUsedHeap compare_pair() const
-  {
-    return DerefAndCompareByActorsCountAndUsedHeap();
-  }
-  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;
-};
-
-} // namespace simgrid::mc
-
-#endif
similarity index 68%
rename from src/mc/mc_pattern.hpp
rename to src/mc/api/ActorState.hpp
index e29895c..6538eff 100644 (file)
@@ -31,18 +31,36 @@ class ActorState {
   /** Exploration control information */
   InterleavingType state_ = InterleavingType::disabled;
 
-  /** Number of times that the process was considered to be executed */
+  /** The ID of that actor */
+  const aid_t aid_;
+
+  /** Number of times that the actor was considered to be executed in previous explorations of the state space */
   unsigned int times_considered_ = 0;
+  /** Maximal amount of times that the actor can be considered for execution in this state.
+   * If times_considered==max_consider, we fully explored that part of the state space */
+  unsigned int max_consider_ = 0;
+
+  /** Whether that actor is initially enabled in this state */
+  bool enabled_;
 
 public:
-  unsigned int do_consider(unsigned int max_consider)
+  ActorState(aid_t aid, bool enabled, unsigned int max_consider)
+      : aid_(aid), max_consider_(max_consider), enabled_(enabled)
+  {
+  }
+
+  unsigned int do_consider()
   {
-    if (max_consider <= times_considered_ + 1)
+    if (max_consider_ <= times_considered_ + 1)
       set_done();
     return times_considered_++;
   }
   unsigned int get_times_considered() const { return times_considered_; }
+  aid_t get_aid() const { return aid_; }
 
+  /* returns whether the actor is marked as enabled in the application side */
+  bool is_enabled() const { return enabled_; }
+  /* returns whether the actor is marked as disabled by the exploration algorithm */
   bool is_disabled() const { return this->state_ == InterleavingType::disabled; }
   bool is_done() const { return this->state_ == InterleavingType::done; }
   bool is_todo() const { return this->state_ == InterleavingType::todo; }
similarity index 56%
rename from src/mc/Session.cpp
rename to src/mc/api/RemoteApp.cpp
index 7b4e357..cc4cea6 100644 (file)
@@ -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/Session.hpp"
+#include "src/mc/api/RemoteApp.hpp"
 #include "src/internal_config.h" // HAVE_SMPI
 #include "src/mc/explo/Exploration.hpp"
 #include "src/mc/mc_config.hpp"
 #include "smpi/smpi.h"
 #include "src/smpi/include/private.hpp"
 #endif
+#include "signal.h"
 #include "src/mc/api/State.hpp"
+#include "src/mc/mc_config.hpp"
 #include "src/mc/mc_exit.hpp"
 #include "src/mc/mc_private.hpp"
 #include "xbt/log.h"
 #include "xbt/system_error.hpp"
 
-#include "signal.h"
 #include <array>
+#include <boost/tokenizer.hpp>
 #include <memory>
 #include <string>
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_Session, mc, "Model-checker session");
 XBT_LOG_EXTERNAL_CATEGORY(mc_global);
 
+static simgrid::config::Flag<std::string> _sg_mc_setenv{
+    "model-check/setenv", "Extra environment variables to pass to the child process (ex: 'AZE=aze;QWE=qwe').", "",
+    [](std::string_view value) {
+      xbt_assert(value.empty() || value.find('=', 0) != std::string_view::npos,
+                 "The 'model-check/setenv' parameter must be like 'AZE=aze', but it does not contain an equal sign.");
+    }};
+
 namespace simgrid::mc {
 
-template <class Code> void run_child_process(int socket, Code code)
+static void run_child_process(int socket, const std::vector<char*>& 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
@@ -41,7 +50,7 @@ template <class Code> void run_child_process(int socket, Code code)
 #ifdef __linux__
   // Make sure we do not outlive our parent
   sigset_t mask;
-  sigemptyset (&mask);
+  sigemptyset(&mask);
   xbt_assert(sigprocmask(SIG_SETMASK, &mask, nullptr) >= 0, "Could not unblock signals");
   xbt_assert(prctl(PR_SET_PDEATHSIG, SIGHUP) == 0, "Could not PR_SET_PDEATHSIG");
 #endif
@@ -51,19 +60,40 @@ template <class Code> void run_child_process(int socket, Code code)
   xbt_assert(fdflags != -1 && fcntl(socket, F_SETFD, fdflags & ~FD_CLOEXEC) != -1,
              "Could not remove CLOEXEC for socket");
 
-  // Disable lazy relocation in the model-checked process to prevent the application from
-  // modifying its .got.plt during snapshot.
-  setenv("LC_BIND_NOW", "1", 1);
-
   setenv(MC_ENV_SOCKET_FD, std::to_string(socket).c_str(), 1);
 
-  code();
+  /* Setup the tokenizer that parses the cfg:model-check/setenv parameter */
+  using Tokenizer = boost::tokenizer<boost::char_separator<char>>;
+  boost::char_separator<char> semicol_sep(";");
+  boost::char_separator<char> equal_sep("=");
+  Tokenizer token_vars(_sg_mc_setenv.get(), semicol_sep); /* Iterate over all FOO=foo parts */
+  for (const auto& token : token_vars) {
+    std::vector<std::string> kv;
+    Tokenizer token_kv(token, equal_sep);
+    for (const auto& t : token_kv) /* Iterate over 'FOO' and then 'foo' in that 'FOO=foo' */
+      kv.push_back(t);
+    xbt_assert(kv.size() == 2, "Parse error on 'model-check/setenv' value %s. Does it contain an equal sign?",
+               token.c_str());
+    XBT_INFO("setenv '%s'='%s'", kv[0].c_str(), kv[1].c_str());
+    setenv(kv[0].c_str(), kv[1].c_str(), 1);
+  }
+
+  /* And now, exec the child process */
+  int i = 1;
+  while (args[i] != nullptr && args[i][0] == '-')
+    i++;
+
+  xbt_assert(args[i] != nullptr,
+             "Unable to find a binary to exec on the command line. Did you only pass config flags?");
+
+  execvp(args[i], args.data() + i);
+  xbt_die("The model-checked process failed to exec(%s): %s", args[i], strerror(errno));
 }
 
-Session::Session(const std::function<void()>& code)
+RemoteApp::RemoteApp(const std::vector<char*>& args)
 {
 #if HAVE_SMPI
-  smpi_init_options();//only performed once
+  smpi_init_options(); // only performed once
   xbt_assert(smpi_cfg_privatization() != SmpiPrivStrategies::MMAP,
              "Please use the dlopen privatization schema when model-checking SMPI code");
 #endif
@@ -79,7 +109,7 @@ Session::Session(const std::function<void()>& code)
 
   if (pid == 0) { // Child
     ::close(sockets[1]);
-    run_child_process(sockets[0], code);
+    run_child_process(sockets[0], args);
     DIE_IMPOSSIBLE;
   }
 
@@ -93,42 +123,13 @@ Session::Session(const std::function<void()>& code)
 
   mc_model_checker = model_checker_.get();
   model_checker_->start();
-}
 
-Session::~Session()
-{
-  this->close();
-}
-
-/** The application must be stopped. */
-void Session::take_initial_snapshot()
-{
-  xbt_assert(initial_snapshot_ == nullptr);
+  /* Take the initial snapshot */
   model_checker_->wait_for_requests();
   initial_snapshot_ = std::make_shared<simgrid::mc::Snapshot>(0);
 }
 
-void Session::restore_initial_state() const
-{
-  this->initial_snapshot_->restore(&model_checker_->get_remote_process());
-}
-
-void Session::log_state() const
-{
-  model_checker_->get_exploration()->log_state();
-
-  if (not _sg_mc_dot_output_file.get().empty()) {
-    fprintf(dot_output, "}\n");
-    fclose(dot_output);
-  }
-  if (getenv("SIMGRID_MC_SYSTEM_STATISTICS")){
-    int ret=system("free");
-    if (ret != 0)
-      XBT_WARN("Call to system(free) did not return 0, but %d", ret);
-  }
-}
-
-void Session::close()
+RemoteApp::~RemoteApp()
 {
   initial_snapshot_ = nullptr;
   if (model_checker_) {
@@ -138,20 +139,45 @@ void Session::close()
   }
 }
 
-bool Session::actor_is_enabled(aid_t pid) const
+void RemoteApp::restore_initial_state() const
 {
-  s_mc_message_actor_enabled_t msg;
+  this->initial_snapshot_->restore(&model_checker_->get_remote_process());
+}
+
+unsigned long RemoteApp::get_maxpid() const
+{
+  return model_checker_->get_remote_process().get_maxpid();
+}
+
+void RemoteApp::get_actors_status(std::map<aid_t, ActorState>& whereto) const
+{
+  s_mc_message_t msg;
   memset(&msg, 0, sizeof msg);
-  msg.type = simgrid::mc::MessageType::ACTOR_ENABLED;
-  msg.aid  = pid;
+  msg.type = simgrid::mc::MessageType::ACTORS_STATUS;
   model_checker_->channel().send(msg);
-  std::array<char, MC_MESSAGE_LENGTH> buff;
-  ssize_t received = model_checker_->channel().receive(buff.data(), buff.size(), true);
-  xbt_assert(received == sizeof(s_mc_message_int_t), "Unexpected size in answer to ACTOR_ENABLED");
-  return ((s_mc_message_int_t*)buff.data())->value;
+
+  s_mc_message_actors_status_answer_t answer;
+  ssize_t received = model_checker_->channel().receive(answer);
+  xbt_assert(received != -1, "Could not receive message");
+  xbt_assert(received == sizeof(answer) && answer.type == MessageType::ACTORS_STATUS_REPLY,
+             "Received unexpected message %s (%i, size=%i) "
+             "expected MessageType::ACTORS_STATUS_REPLY (%i, size=%i)",
+             to_c_str(answer.type), (int)answer.type, (int)received, (int)MessageType::ACTORS_STATUS_REPLY,
+             (int)sizeof(answer));
+
+  std::vector<s_mc_message_actors_status_one_t> status(answer.count);
+  if (answer.count > 0) {
+    size_t size = status.size() * sizeof(s_mc_message_actors_status_one_t);
+    received    = model_checker_->channel().receive(status.data(), size);
+    xbt_assert(static_cast<size_t>(received) == size);
+  }
+
+  whereto.clear();
+  for (auto const& actor : status)
+    whereto.try_emplace(actor.aid, actor.aid, actor.enabled, actor.max_considered);
 }
 
-void Session::check_deadlock() const
+void RemoteApp::check_deadlock() const
 {
   xbt_assert(model_checker_->channel().send(MessageType::DEADLOCK_CHECK) == 0, "Could not check deadlock state");
   s_mc_message_int_t message;
@@ -171,7 +197,7 @@ void Session::check_deadlock() const
     for (auto const& frame : model_checker_->get_exploration()->get_textual_trace())
       XBT_CINFO(mc_global, "  %s", frame.c_str());
     XBT_CINFO(mc_global, "Path = %s", model_checker_->get_exploration()->get_record_trace().to_string().c_str());
-    log_state();
+    model_checker_->get_exploration()->log_state();
     throw DeadlockError();
   }
 }
similarity index 64%
rename from src/mc/Session.hpp
rename to src/mc/api/RemoteApp.hpp
index b84e6fe..7ad580c 100644 (file)
@@ -3,18 +3,19 @@
 /* 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_SESSION_HPP
-#define SIMGRID_MC_SESSION_HPP
+#ifndef SIMGRID_MC_REMOTE_APP_HPP
+#define SIMGRID_MC_REMOTE_APP_HPP
 
 #include "simgrid/forward.h"
 #include "src/mc/ModelChecker.hpp"
+#include "src/mc/api/ActorState.hpp"
 #include "src/mc/remote/RemotePtr.hpp"
 
 #include <functional>
 
 namespace simgrid::mc {
 
-/** A model-checking session
+/** High-level view of the verified application, from the model-checker POV
  *
  *  This is expected to become the interface used by model-checking
  *  algorithms to control the execution of the model-checked process
@@ -22,14 +23,14 @@ namespace simgrid::mc {
  *  algorithms should be able to be written in high-level languages
  *  (e.g. Python) using bindings on this interface.
  */
-class XBT_PUBLIC Session {
+class XBT_PUBLIC RemoteApp {
 private:
   std::unique_ptr<ModelChecker> model_checker_;
   std::shared_ptr<simgrid::mc::Snapshot> initial_snapshot_;
 
   // No copy:
-  Session(Session const&) = delete;
-  Session& operator=(Session const&) = delete;
+  RemoteApp(RemoteApp const&) = delete;
+  RemoteApp& operator=(RemoteApp const&) = delete;
 
 public:
   /** Create a new session by executing the provided code in a fork()
@@ -39,20 +40,23 @@ public:
    *
    *  The code is expected to `exec` the model-checked application.
    */
-  explicit Session(const std::function<void()>& code);
+  explicit RemoteApp(const std::vector<char*>& args);
 
-  ~Session();
-  void close();
+  ~RemoteApp();
 
-  void take_initial_snapshot();
   void restore_initial_state() const;
 
   /** Ask to the application to check for a deadlock. If so, do an error message and throw a DeadlockError. */
   void check_deadlock() const;
 
-  void log_state() const;
+  /** Retrieve the max PID of the running actors */
+  unsigned long get_maxpid() const;
 
-  bool actor_is_enabled(aid_t pid) const;
+  /* Get the list of actors that are ready to run at that step. Usually shorter than maxpid */
+  void get_actors_status(std::map<aid_t, simgrid::mc::ActorState>& whereto) const;
+
+  /* Get the remote process */
+  RemoteProcess& get_remote_process() { return model_checker_->get_remote_process(); }
 };
 } // namespace simgrid::mc
 
index fac456f..777ca4d 100644 (file)
@@ -4,7 +4,6 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/mc/api/State.hpp"
-#include "src/mc/api.hpp"
 #include "src/mc/mc_config.hpp"
 
 #include <boost/range/algorithm.hpp>
@@ -15,21 +14,20 @@ namespace simgrid::mc {
 
 long State::expended_states_ = 0;
 
-State::State() : num_(++expended_states_)
+State::State(const RemoteApp& remote_app) : num_(++expended_states_)
 {
-  const unsigned long maxpid = Api::get().get_maxpid();
-  actor_states_.resize(maxpid);
+  remote_app.get_actors_status(actors_to_run_);
+
   transition_.reset(new Transition());
   /* Stateful model checking */
   if ((_sg_mc_checkpoint > 0 && (num_ % _sg_mc_checkpoint == 0)) || _sg_mc_termination) {
-    auto snapshot_ptr = Api::get().take_snapshot(num_);
-    system_state_     = std::shared_ptr<simgrid::mc::Snapshot>(snapshot_ptr);
+    system_state_ = std::make_shared<simgrid::mc::Snapshot>(num_);
   }
 }
 
 std::size_t State::count_todo() const
 {
-  return boost::range::count_if(this->actor_states_, [](simgrid::mc::ActorState const& a) { return a.is_todo(); });
+  return boost::range::count_if(this->actors_to_run_, [](auto& pair) { return pair.second.is_todo(); });
 }
 
 Transition* State::get_transition() const
@@ -37,34 +35,28 @@ Transition* State::get_transition() const
   return transition_.get();
 }
 
-int State::next_transition() const
+aid_t State::next_transition() const
 {
-  std::vector<ActorInformation>& actors = mc_model_checker->get_remote_process().actors();
-  XBT_DEBUG("Search for an actor to run. %zu actors to consider", actors.size());
-  for (unsigned int i = 0; i < actors.size(); i++) {
-    /* Only consider actors (1) marked as interleaving by the checker and (2) currently enabled in the application*/
-    if (aid_t aid = actors[i].copy.get_buffer()->get_pid();
-        not actor_states_[aid].is_todo() || not Api::get().get_session().actor_is_enabled(aid))
+  XBT_DEBUG("Search for an actor to run. %zu actors to consider", actors_to_run_.size());
+  for (auto const& [aid, actor] : actors_to_run_) {
+    /* Only consider actors (1) marked as interleaving by the checker and (2) currently enabled in the application */
+    if (not actor.is_todo() || not actor.is_enabled())
       continue;
 
-    return i;
+    return aid;
   }
   return -1;
 }
-void State::execute_next(int next)
+void State::execute_next(aid_t next)
 {
-  std::vector<ActorInformation>& actors = mc_model_checker->get_remote_process().actors();
-  const kernel::actor::ActorImpl* actor = actors[next].copy.get_buffer();
-  const aid_t aid                       = actor->get_pid();
-
   /* This actor is ready to be executed. Prepare its execution when simcall_handle will be called on it */
-  const unsigned times_considered = actor_states_[aid].do_consider(actor->simcall_.mc_max_consider_);
+  const unsigned times_considered = actors_to_run_.at(next).do_consider();
 
-  XBT_DEBUG("Let's run actor %ld (times_considered = %u)", aid, times_considered);
+  XBT_DEBUG("Let's run actor %ld (times_considered = %u)", next, times_considered);
 
   Transition::executed_transitions_++;
 
-  transition_.reset(mc_model_checker->handle_simcall(aid, times_considered, true));
+  transition_.reset(mc_model_checker->handle_simcall(next, times_considered, true));
   mc_model_checker->wait_for_requests();
 }
 } // namespace simgrid::mc
index 8432206..92164cf 100644 (file)
@@ -6,7 +6,8 @@
 #ifndef SIMGRID_MC_STATE_HPP
 #define SIMGRID_MC_STATE_HPP
 
-#include "src/mc/mc_pattern.hpp"
+#include "src/mc/api/ActorState.hpp"
+#include "src/mc/api/RemoteApp.hpp"
 #include "src/mc/sosp/Snapshot.hpp"
 #include "src/mc/transition/Transition.hpp"
 
@@ -19,30 +20,34 @@ class XBT_PRIVATE State : public xbt::Extendable<State> {
   /* Outgoing transition: what was the last transition that we took to leave this state? */
   std::unique_ptr<Transition> transition_;
 
-  /** Sequential state number (used for debugging) */
+  /** Sequential state ID (used for debugging) */
   long num_ = 0;
 
-  /** State's exploration status by process */
-  std::vector<ActorState> actor_states_;
+  /** State's exploration status by actor. Not all the actors are there, only the ones that are ready-to-run in this state */
+  std::map<aid_t, ActorState> actors_to_run_;
 
   /** Snapshot of system state (if needed) */
   std::shared_ptr<Snapshot> system_state_;
 
 public:
-  explicit State();
+  explicit State(const RemoteApp& remote_app);
 
   /* Returns a positive number if there is another transition to pick, or -1 if not */
-  int next_transition() const;
+  aid_t next_transition() const;
 
   /* Explore a new path; the parameter must be the result of a previous call to next_transition() */
-  void execute_next(int next);
+  void execute_next(aid_t next);
 
   long get_num() const { return num_; }
   std::size_t count_todo() const;
-  void mark_todo(aid_t actor) { this->actor_states_[actor].mark_todo(); }
-  bool is_done(aid_t actor) const { return this->actor_states_[actor].is_done(); }
+  void mark_todo(aid_t actor) { actors_to_run_.at(actor).mark_todo(); }
+  bool is_done(aid_t actor) const { return actors_to_run_.at(actor).is_done(); }
   Transition* get_transition() const;
   void set_transition(Transition* t) { transition_.reset(t); }
+  std::map<aid_t, ActorState> const& get_actors_list() const { return actors_to_run_; }
+
+  unsigned long get_actor_count() const { return actors_to_run_.size(); }
+  bool is_actor_enabled(aid_t actor) { return actors_to_run_.at(actor).is_enabled(); }
 
   Snapshot* get_system_state() const { return system_state_.get(); }
   void set_system_state(std::shared_ptr<Snapshot> state) { system_state_ = std::move(state); }
index 6b7ffe1..fdeba59 100644 (file)
@@ -201,6 +201,37 @@ static bool heap_area_differ(const RemoteProcess& process, StateComparator& stat
                              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 RemoteProcess& process, StateComparator& state, const Snapshot& snapshot1,
                                 const Snapshot& snapshot2)
 {
@@ -814,9 +845,7 @@ static bool heap_area_differ(const RemoteProcess& process, StateComparator& stat
     }
 
     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() ||
-         type->name == "struct s_smx_context")) { // FIXME: there is no struct s_smx_context anymore
+        type_size != (ssize_t)heapinfo2->busy_block.busy_size && type->name.empty()) {
       if (match_pairs)
         state.match_equals(previous);
       return false;
@@ -1174,65 +1203,62 @@ static bool local_variables_differ(const simgrid::mc::RemoteProcess& process, si
 
 namespace simgrid::mc {
 
-bool snapshot_equal(const Snapshot* s1, const Snapshot* s2)
+bool Snapshot::operator==(const Snapshot& other)
 {
   // TODO, make this a field of ModelChecker or something similar
   static StateComparator state_comparator;
 
   const RemoteProcess& process = mc_model_checker->get_remote_process();
 
-  if (s1->hash_ != s2->hash_) {
-    XBT_VERB("(%ld - %ld) Different hash: 0x%" PRIx64 "--0x%" PRIx64, s1->num_state_, s2->num_state_, s1->hash_,
-             s2->hash_);
+  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, s1->num_state_, s2->num_state_, s1->hash_);
+  XBT_VERB("(%ld - %ld) Same hash: 0x%" PRIx64, this->num_state_, other.num_state_, this->hash_);
 
-  /* Compare enabled processes */
-  if (s1->enabled_processes_ != s2->enabled_processes_) {
-    XBT_VERB("(%ld - %ld) Different amount of enabled processes", s1->num_state_, s2->num_state_);
-    return false;
-  }
+  /* TODO: re-enable the quick filter of counting enabled processes in each snapshots */
 
   /* Compare size of stacks */
-  for (unsigned long i = 0; i < s1->stacks_.size(); i++) {
-    size_t size_used1 = s1->stack_sizes_[i];
-    size_t size_used2 = s2->stack_sizes_[i];
+  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", s1->num_state_, s2->num_state_, size_used1,
+      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<xbt_mheap_t>(
-      s1->read_bytes(alloca(sizeof(s_xbt_mheap_t)), sizeof(s_xbt_mheap_t), process.heap_address, ReadOptions::lazy()));
-  const s_xbt_mheap_t* heap2 = static_cast<xbt_mheap_t>(
-      s2->read_bytes(alloca(sizeof(s_xbt_mheap_t)), sizeof(s_xbt_mheap_t), process.heap_address, ReadOptions::lazy()));
-  if (state_comparator.initHeapInformation(heap1, heap2, s1->to_ignore_, s2->to_ignore_) == -1) {
-    XBT_VERB("(%ld - %ld) Different heap information", s1->num_state_, s2->num_state_);
+  const s_xbt_mheap_t* heap1 = static_cast<xbt_mheap_t>(this->read_bytes(
+      alloca(sizeof(s_xbt_mheap_t)), sizeof(s_xbt_mheap_t), process.heap_address, ReadOptions::lazy()));
+  const s_xbt_mheap_t* heap2 = static_cast<xbt_mheap_t>(other.read_bytes(
+      alloca(sizeof(s_xbt_mheap_t)), sizeof(s_xbt_mheap_t), process.heap_address, ReadOptions::lazy()));
+  if (state_comparator.initHeapInformation(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 < s1->stacks_.size(); cursor++) {
-    const_mc_snapshot_stack_t stack1 = &s1->stacks_[cursor];
-    const_mc_snapshot_stack_t stack2 = &s2->stacks_[cursor];
+  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(process, state_comparator, *s1, *s2, stack1, stack2)) {
-      XBT_VERB("(%ld - %ld) Different local variables between stacks %u", s1->num_state_, s2->num_state_, cursor + 1);
+    if (local_variables_differ(process, 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 = s1->snapshot_regions_.size();
-  if (regions_count != s2->snapshot_regions_.size())
+  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 = s1->snapshot_regions_[k].get();
-    Region* region2 = s2->snapshot_regions_[k].get();
+    Region* region1 = this->snapshot_regions_[k].get();
+    Region* region2 = other.snapshot_regions_[k].get();
 
     // Preconditions:
     if (region1->region_type() != RegionType::Data)
@@ -1243,20 +1269,21 @@ bool snapshot_equal(const Snapshot* s1, const Snapshot* s2)
     xbt_assert(region1->object_info());
 
     /* Compare global variables */
-    if (global_variables_differ(process, state_comparator, region1->object_info(), region1, region2, *s1, *s2)) {
+    if (global_variables_differ(process, 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", s1->num_state_, s2->num_state_, name.c_str());
+      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(process, state_comparator, *s1, *s2)) {
-    XBT_VERB("(%ld - %ld) Different heap (mmalloc_compare)", s1->num_state_, s2->num_state_);
+  if (mmalloc_heap_differ(process, 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", s1->num_state_, s2->num_state_);
+  XBT_VERB("(%ld - %ld) No difference found", this->num_state_, other.num_state_);
 
   return true;
 }
index 4464631..bb9a5b2 100644 (file)
@@ -60,9 +60,14 @@ struct PatternCommunicationList {
 
 /********** Checker extension **********/
 
-struct CommDetExtension {
+class CommDetExtension {
+  Exploration& exploration_;
+
+public:
   static simgrid::xbt::Extension<simgrid::mc::Exploration, CommDetExtension> EXTENSION_ID;
 
+  explicit CommDetExtension(Exploration& explo) : exploration_(explo) {}
+
   std::vector<simgrid::mc::PatternCommunicationList> initial_communications_pattern;
   std::vector<std::vector<simgrid::mc::PatternCommunication*>> incomplete_communications_pattern;
 
@@ -74,12 +79,12 @@ struct CommDetExtension {
 
   void exploration_start()
   {
-    const unsigned long maxpid = Api::get().get_maxpid();
+    const unsigned long maxpid = exploration_.get_remote_app().get_maxpid();
 
     initial_communications_pattern.resize(maxpid);
     incomplete_communications_pattern.resize(maxpid);
   }
-  void restore_communications_pattern(const simgrid::mc::State* state);
+  void restore_communications_pattern(const simgrid::mc::State* state, RemoteApp const& remote_app);
   void enforce_deterministic_pattern(aid_t process, const PatternCommunication* comm);
   void get_comm_pattern(const Transition* transition);
   void complete_comm_pattern(const CommWaitTransition* transition);
@@ -94,17 +99,17 @@ public:
   std::vector<unsigned> communication_indices_;
 
   static simgrid::xbt::Extension<simgrid::mc::State, StateCommDet> EXTENSION_ID;
-  explicit StateCommDet(CommDetExtension* checker)
+  explicit StateCommDet(CommDetExtension& checker, RemoteApp const& remote_app)
   {
-    const unsigned long maxpid = Api::get().get_maxpid();
+    const unsigned long maxpid = remote_app.get_maxpid();
     for (unsigned long i = 0; i < maxpid; i++) {
       std::vector<simgrid::mc::PatternCommunication> res;
-      for (auto const& comm : checker->incomplete_communications_pattern[i])
+      for (auto const& comm : checker.incomplete_communications_pattern[i])
         res.push_back(comm->dup());
       incomplete_comm_pattern_.push_back(std::move(res));
     }
 
-    for (auto const& list_process_comm : checker->initial_communications_pattern)
+    for (auto const& list_process_comm : checker.initial_communications_pattern)
       this->communication_indices_.push_back(list_process_comm.index_comm);
   }
 };
@@ -129,13 +134,13 @@ static simgrid::mc::CommPatternDifference compare_comm_pattern(const simgrid::mc
   return CommPatternDifference::NONE;
 }
 
-void CommDetExtension::restore_communications_pattern(const simgrid::mc::State* state)
+void CommDetExtension::restore_communications_pattern(const simgrid::mc::State* state, RemoteApp const& remote_app)
 {
   for (size_t i = 0; i < initial_communications_pattern.size(); i++)
     initial_communications_pattern[i].index_comm =
         state->extension<simgrid::mc::StateCommDet>()->communication_indices_[i];
 
-  const unsigned long maxpid = Api::get().get_maxpid();
+  const unsigned long maxpid = remote_app.get_maxpid();
   for (unsigned long i = 0; i < maxpid; i++) {
     incomplete_communications_pattern[i].clear();
     for (simgrid::mc::PatternCommunication const& comm :
@@ -202,8 +207,8 @@ void CommDetExtension::enforce_deterministic_pattern(aid_t actor, const PatternC
       XBT_INFO("***** Non-send-deterministic communications pattern *****");
       XBT_INFO("*********************************************************");
       XBT_INFO("%s", send_diff.c_str());
-      Api::get().get_session().log_state();
-      Api::get().mc_exit(SIMGRID_MC_EXIT_NON_DETERMINISM);
+      exploration_.log_state();
+      mc_model_checker->exit(SIMGRID_MC_EXIT_NON_DETERMINISM);
     } else if (_sg_mc_comms_determinism && (not send_deterministic && not recv_deterministic)) {
       XBT_INFO("****************************************************");
       XBT_INFO("***** Non-deterministic communications pattern *****");
@@ -212,8 +217,8 @@ void CommDetExtension::enforce_deterministic_pattern(aid_t actor, const PatternC
         XBT_INFO("%s", send_diff.c_str());
       if (not recv_diff.empty())
         XBT_INFO("%s", recv_diff.c_str());
-      Api::get().get_session().log_state();
-      Api::get().mc_exit(SIMGRID_MC_EXIT_NON_DETERMINISM);
+      exploration_.log_state();
+      mc_model_checker->exit(SIMGRID_MC_EXIT_NON_DETERMINISM);
     }
   }
 }
@@ -314,26 +319,32 @@ void CommDetExtension::handle_comm_pattern(const Transition* transition)
       }
  */
 
-Exploration* create_communication_determinism_checker(Session* session)
+Exploration* create_communication_determinism_checker(const std::vector<char*>& args, bool with_dpor)
 {
   CommDetExtension::EXTENSION_ID = simgrid::mc::Exploration::extension_create<CommDetExtension>();
   StateCommDet::EXTENSION_ID     = simgrid::mc::State::extension_create<StateCommDet>();
 
   XBT_DEBUG("********* Start communication determinism verification *********");
 
-  auto extension = new CommDetExtension();
+  auto base      = new DFSExplorer(args, with_dpor);
+  auto extension = new CommDetExtension(*base);
 
-  DFSExplorer::on_exploration_start([extension]() {
+  DFSExplorer::on_exploration_start([extension](RemoteApp const&) {
     XBT_INFO("Check communication determinism");
     extension->exploration_start();
   });
-  DFSExplorer::on_backtracking([extension]() { extension->initial_communications_pattern_done = true; });
-  DFSExplorer::on_state_creation([extension](State* state) { state->extension_set(new StateCommDet(extension)); });
+  DFSExplorer::on_backtracking(
+      [extension](RemoteApp const&) { extension->initial_communications_pattern_done = true; });
+  DFSExplorer::on_state_creation([extension](State* state, RemoteApp const& remote_app) {
+    state->extension_set(new StateCommDet(*extension, remote_app));
+  });
 
-  DFSExplorer::on_restore_system_state([extension](State* state) { extension->restore_communications_pattern(state); });
+  DFSExplorer::on_restore_system_state([extension](State const* state, RemoteApp const& remote_app) {
+    extension->restore_communications_pattern(state, remote_app);
+  });
 
-  DFSExplorer::on_restore_initial_state([extension]() {
-    const unsigned long maxpid = Api::get().get_maxpid();
+  DFSExplorer::on_restore_initial_state([extension](RemoteApp const& remote_app) {
+    const unsigned long maxpid = remote_app.get_maxpid();
     assert(maxpid == extension->incomplete_communications_pattern.size());
     assert(maxpid == extension->initial_communications_pattern.size());
     for (unsigned long j = 0; j < maxpid; j++) {
@@ -342,10 +353,12 @@ Exploration* create_communication_determinism_checker(Session* session)
     }
   });
 
-  DFSExplorer::on_transition_replay([extension](Transition* t) { extension->handle_comm_pattern(t); });
-  DFSExplorer::on_transition_execute([extension](Transition* t) { extension->handle_comm_pattern(t); });
+  DFSExplorer::on_transition_replay(
+      [extension](Transition const* t, RemoteApp const&) { extension->handle_comm_pattern(t); });
+  DFSExplorer::on_transition_execute(
+      [extension](Transition const* t, RemoteApp const&) { extension->handle_comm_pattern(t); });
 
-  DFSExplorer::on_log_state([extension]() {
+  DFSExplorer::on_log_state([extension](RemoteApp const&) {
     if (_sg_mc_comms_determinism) {
       if (extension->send_deterministic && not extension->recv_deterministic) {
         XBT_INFO("*******************************************************");
@@ -366,7 +379,7 @@ Exploration* create_communication_determinism_checker(Session* session)
     delete extension;
   });
 
-  return new DFSExplorer(session);
+  return base;
 }
 
 } // namespace simgrid::mc
index b39b7fb..03122f3 100644 (file)
@@ -26,22 +26,22 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dfs, mc, "DFS exploration algorithm of the mo
 
 namespace simgrid::mc {
 
-xbt::signal<void()> DFSExplorer::on_exploration_start_signal;
-xbt::signal<void()> DFSExplorer::on_backtracking_signal;
+xbt::signal<void(RemoteApp&)> DFSExplorer::on_exploration_start_signal;
+xbt::signal<void(RemoteApp&)> DFSExplorer::on_backtracking_signal;
 
-xbt::signal<void(State*)> DFSExplorer::on_state_creation_signal;
+xbt::signal<void(State*, RemoteApp&)> DFSExplorer::on_state_creation_signal;
 
-xbt::signal<void(State*)> DFSExplorer::on_restore_system_state_signal;
-xbt::signal<void()> DFSExplorer::on_restore_initial_state_signal;
-xbt::signal<void(Transition*)> DFSExplorer::on_transition_replay_signal;
-xbt::signal<void(Transition*)> DFSExplorer::on_transition_execute_signal;
+xbt::signal<void(State*, RemoteApp&)> DFSExplorer::on_restore_system_state_signal;
+xbt::signal<void(RemoteApp&)> DFSExplorer::on_restore_initial_state_signal;
+xbt::signal<void(Transition*, RemoteApp&)> DFSExplorer::on_transition_replay_signal;
+xbt::signal<void(Transition*, RemoteApp&)> DFSExplorer::on_transition_execute_signal;
 
-xbt::signal<void()> DFSExplorer::on_log_state_signal;
+xbt::signal<void(RemoteApp&)> DFSExplorer::on_log_state_signal;
 
 void DFSExplorer::check_non_termination(const State* current_state)
 {
   for (auto state = stack_.rbegin(); state != stack_.rend(); ++state)
-    if (Api::get().snapshot_equal((*state)->get_system_state(), current_state->get_system_state())) {
+    if (*(*state)->get_system_state() == *current_state->get_system_state()) {
       XBT_INFO("Non-progressive cycle: state %ld -> state %ld", (*state)->get_num(), current_state->get_num());
       XBT_INFO("******************************************");
       XBT_INFO("*** NON-PROGRESSIVE CYCLE DETECTED ***");
@@ -76,16 +76,16 @@ std::vector<std::string> DFSExplorer::get_textual_trace() // override
 
 void DFSExplorer::log_state() // override
 {
-  on_log_state_signal();
+  on_log_state_signal(get_remote_app());
   XBT_INFO("DFS exploration ended. %ld unique states visited; %ld backtracks (%lu transition replays, %lu states "
            "visited overall)",
-           State::get_expanded_states(), backtrack_count_, Api::get().mc_get_visited_states(),
+           State::get_expanded_states(), backtrack_count_, mc_model_checker->get_visited_states(),
            Transition::get_replayed_transitions());
 }
 
 void DFSExplorer::run()
 {
-  on_exploration_start_signal();
+  on_exploration_start_signal(get_remote_app());
   /* This function runs the DFS algorithm the state space.
    * We do so iteratively instead of recursively, dealing with the call stack manually.
    * This allows one to explore the call stack at will. */
@@ -98,11 +98,11 @@ void DFSExplorer::run()
     XBT_DEBUG("Exploration depth=%zu (state:%ld; %zu interleaves)", stack_.size(), state->get_num(),
               state->count_todo());
 
-    Api::get().mc_inc_visited_states();
+    mc_model_checker->inc_visited_states();
 
     // Backtrack if we reached the maximum depth
     if (stack_.size() > (std::size_t)_sg_mc_max_depth) {
-      if (reductionMode_ == ReductionMode::dpor) {
+      if (reduction_mode_ == ReductionMode::dpor) {
         XBT_ERROR("/!\\ Max depth of %d reached! THIS WILL PROBABLY BREAK the dpor reduction /!\\",
                   _sg_mc_max_depth.get());
         XBT_ERROR("/!\\ If bad things happen, disable dpor with --cfg=model-check/reduction:none /!\\");
@@ -123,13 +123,13 @@ void DFSExplorer::run()
     }
 
     // Search for the next transition
-    int next = state->next_transition();
+    aid_t next = state->next_transition();
 
     if (next < 0) { // If there is no more transition in the current state, backtrack.
-      XBT_DEBUG("There remains %zu actors, but none to interleave (depth %zu).",
-                mc_model_checker->get_remote_process().actors().size(), stack_.size() + 1);
+      XBT_DEBUG("There remains %lu actors, but none to interleave (depth %zu).", state->get_actor_count(),
+                stack_.size() + 1);
 
-      if (mc_model_checker->get_remote_process().actors().empty()) {
+      if (state->get_actor_count() == 0) {
         mc_model_checker->finalize_app();
         XBT_VERB("Execution came to an end at %s (state: %ld, depth: %zu)", get_record_trace().to_string().c_str(),
                  state->get_num(), stack_.size());
@@ -140,49 +140,42 @@ void DFSExplorer::run()
 
     /* Actually answer the request: let's execute the selected request (MCed does one step) */
     state->execute_next(next);
-    on_transition_execute_signal(state->get_transition());
+    on_transition_execute_signal(state->get_transition(), get_remote_app());
 
     // If there are processes to interleave and the maximum depth has not been
     // reached then perform one step of the exploration algorithm.
     XBT_VERB("Execute %ld: %.60s (stack depth: %zu, state: %ld, %zu interleaves)", state->get_transition()->aid_,
              state->get_transition()->to_string().c_str(), stack_.size(), state->get_num(), state->count_todo());
 
-    std::string req_str;
-    if (dot_output != nullptr)
-      req_str = state->get_transition()->dot_string();
-
     /* Create the new expanded state (copy the state of MCed into our MCer data) */
-    auto next_state = std::make_unique<State>();
-    on_state_creation_signal(next_state.get());
+    auto next_state = std::make_unique<State>(get_remote_app());
+    on_state_creation_signal(next_state.get(), get_remote_app());
 
     if (_sg_mc_termination)
       this->check_non_termination(next_state.get());
 
     /* 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(), true);
+      visited_state_ = visited_states_.addVisitedState(next_state->get_num(), next_state.get());
 
     /* 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 */
-      auto actors = Api::get().get_actors();
-      for (auto& remoteActor : actors) {
-        auto actor = remoteActor.copy.get_buffer();
-        if (get_session().actor_is_enabled(actor->get_pid())) {
-          next_state->mark_todo(actor->get_pid());
-          if (reductionMode_ == ReductionMode::dpor)
+      for (auto const& [aid, _] : next_state->get_actors_list()) {
+        if (next_state->is_actor_enabled(aid)) {
+          next_state->mark_todo(aid);
+          if (reduction_mode_ == ReductionMode::dpor)
             break; // With DPOR, we take the first enabled transition
         }
       }
 
-      if (dot_output != nullptr)
-        std::fprintf(dot_output, "\"%ld\" -> \"%ld\" [%s];\n", state->get_num(), next_state->get_num(),
-                     req_str.c_str());
-
-    } else if (dot_output != nullptr)
-      std::fprintf(dot_output, "\"%ld\" -> \"%ld\" [%s];\n", state->get_num(),
-                   visited_state_->original_num == -1 ? visited_state_->num : visited_state_->original_num,
-                   req_str.c_str());
+      mc_model_checker->dot_output("\"%ld\" -> \"%ld\" [%s];\n", state->get_num(), next_state->get_num(),
+                                   state->get_transition()->dot_string().c_str());
+    } else
+      mc_model_checker->dot_output("\"%ld\" -> \"%ld\" [%s];\n", state->get_num(),
+                                   visited_state_->original_num == -1 ? visited_state_->num
+                                                                      : visited_state_->original_num,
+                                   state->get_transition()->dot_string().c_str());
 
     stack_.push_back(std::move(next_state));
   }
@@ -194,20 +187,20 @@ void DFSExplorer::backtrack()
 {
   backtrack_count_++;
   XBT_VERB("Backtracking from %s", get_record_trace().to_string().c_str());
-  on_backtracking_signal();
+  on_backtracking_signal(get_remote_app());
   stack_.pop_back();
 
-  get_session().check_deadlock();
+  get_remote_app().check_deadlock();
 
   /* Traverse the stack backwards until a state with a non empty interleave set is found, deleting all the states that
    *  have it empty in the way. For each deleted state, check if the request that has generated it (from its
    *  predecessor state), depends on any other previous request executed before it. If it does then add it to the
    *  interleave set of the state that executed that previous request. */
-
-  while (not stack_.empty()) {
+  bool found_backtracking_point = false;
+  while (not stack_.empty() && not found_backtracking_point) {
     std::unique_ptr<State> state = std::move(stack_.back());
     stack_.pop_back();
-    if (reductionMode_ == ReductionMode::dpor) {
+    if (reduction_mode_ == ReductionMode::dpor) {
       aid_t issuer_id = state->get_transition()->aid_;
       for (auto i = stack_.rbegin(); i != stack_.rend(); ++i) {
         State* prev_state = i->get();
@@ -233,76 +226,68 @@ void DFSExplorer::backtrack()
       }
     }
 
-    if (state->count_todo() && stack_.size() < (std::size_t)_sg_mc_max_depth) {
-      /* We found a back-tracking point, let's loop */
-      XBT_DEBUG("Back-tracking to state %ld at depth %zu", state->get_num(), stack_.size() + 1);
-      stack_.push_back(
-          std::move(state)); // Put it back on the stack from which it was removed earlier in this while loop
-      this->restore_state();
-      XBT_DEBUG("Back-tracking to state %ld at depth %zu done", stack_.back()->get_num(), stack_.size());
-      break;
-    } else {
+    if (state->count_todo() == 0) { // Empty interleaving set
       XBT_DEBUG("Delete state %ld at depth %zu", state->get_num(), stack_.size() + 1);
+
+    } else {
+      XBT_DEBUG("Back-tracking to state %ld at depth %zu", state->get_num(), stack_.size() + 1);
+      stack_.push_back(std::move(state)); // Put it back on the stack
+      found_backtracking_point = true;
     }
   }
-}
 
-void DFSExplorer::restore_state()
-{
-  /* If asked to rollback on a state that has a snapshot, restore it */
-  State* last_state = stack_.back().get();
-  if (const auto* system_state = last_state->get_system_state()) {
-    Api::get().restore_state(system_state);
-    on_restore_system_state_signal(last_state);
-    return;
-  }
+  if (found_backtracking_point) {
+    /* If asked to rollback on a state that has a snapshot, restore it */
+    State* last_state = stack_.back().get();
+    if (const auto* system_state = last_state->get_system_state()) {
+      system_state->restore(&get_remote_app().get_remote_process());
+      on_restore_system_state_signal(last_state, get_remote_app());
+      return;
+    }
 
-  /* if no snapshot, we need to restore the initial state and replay the transitions */
-  get_session().restore_initial_state();
-  on_restore_initial_state_signal();
-
-  /* Traverse the stack from the state at position start and re-execute the transitions */
-  for (std::unique_ptr<State> const& state : stack_) {
-    if (state == stack_.back()) /* If we are arrived on the target state, don't replay the outgoing transition */
-      break;
-    state->get_transition()->replay();
-    on_transition_replay_signal(state->get_transition());
-    /* Update statistics */
-    Api::get().mc_inc_visited_states();
-  }
+    /* if no snapshot, we need to restore the initial state and replay the transitions */
+    get_remote_app().restore_initial_state();
+    on_restore_initial_state_signal(get_remote_app());
+
+    /* Traverse the stack from the state at position start and re-execute the transitions */
+    for (std::unique_ptr<State> const& state : stack_) {
+      if (state == stack_.back()) /* If we are arrived on the target state, don't replay the outgoing transition */
+        break;
+      state->get_transition()->replay();
+      on_transition_replay_signal(state->get_transition(), get_remote_app());
+      /* Update statistics */
+      mc_model_checker->inc_visited_states();
+    }
+  } // If no backtracing point, then the stack is empty and the exploration is over
 }
 
-DFSExplorer::DFSExplorer(Session* session) : Exploration(session)
+DFSExplorer::DFSExplorer(const std::vector<char*>& args, bool with_dpor) : Exploration(args)
 {
-  reductionMode_ = reduction_mode;
-  if (_sg_mc_termination)
-    reductionMode_ = ReductionMode::none;
-  else if (reductionMode_ == ReductionMode::unset)
-    reductionMode_ = ReductionMode::dpor;
-
-  if (_sg_mc_termination)
-    XBT_INFO("Check non progressive cycles");
+  if (with_dpor)
+    reduction_mode_ = ReductionMode::dpor;
   else
-    XBT_INFO("Start a DFS exploration. Reduction is: %s.",
-             (reductionMode_ == ReductionMode::none ? "none"
-                                                    : (reductionMode_ == ReductionMode::dpor ? "dpor" : "unknown")));
-
-  get_session().take_initial_snapshot();
+    reduction_mode_ = ReductionMode::none;
 
-  XBT_DEBUG("Starting the DFS exploration");
+  if (_sg_mc_termination) {
+    if (with_dpor) {
+      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_));
 
-  auto initial_state = std::make_unique<State>();
+  auto initial_state = std::make_unique<State>(get_remote_app());
 
   XBT_DEBUG("**************************************************");
 
   /* Get an enabled actor and insert it in the interleave set of the initial state */
-  auto actors = Api::get().get_actors();
-  XBT_DEBUG("Initial state. %zu actors to consider", actors.size());
-  for (auto& actor : actors) {
-    aid_t aid = actor.copy.get_buffer()->get_pid();
-    if (get_session().actor_is_enabled(aid)) {
+  XBT_DEBUG("Initial state. %lu actors to consider", initial_state->get_actor_count());
+  for (auto const& [aid, _] : initial_state->get_actors_list()) {
+    if (initial_state->is_actor_enabled(aid)) {
       initial_state->mark_todo(aid);
-      if (reductionMode_ == ReductionMode::dpor) {
+      if (reduction_mode_ == ReductionMode::dpor) {
         XBT_DEBUG("Actor %ld is TODO, DPOR is ON so let's go for this one.", aid);
         break;
       }
@@ -313,9 +298,9 @@ DFSExplorer::DFSExplorer(Session* session) : Exploration(session)
   stack_.push_back(std::move(initial_state));
 }
 
-Exploration* create_dfs_exploration(Session* session)
+Exploration* create_dfs_exploration(const std::vector<char*>& args, bool with_dpor)
 {
-  return new DFSExplorer(session);
+  return new DFSExplorer(args, with_dpor);
 }
 
 } // namespace simgrid::mc
index 8c59356..d30de61 100644 (file)
@@ -8,7 +8,6 @@
 
 #include "src/mc/VisitedState.hpp"
 #include "src/mc/explo/Exploration.hpp"
-#include "src/mc/mc_safety.hpp"
 
 #include <list>
 #include <memory>
 namespace simgrid::mc {
 
 class XBT_PRIVATE DFSExplorer : public Exploration {
-  ReductionMode reductionMode_ = ReductionMode::unset;
+  XBT_DECLARE_ENUM_CLASS(ReductionMode, none, dpor);
+
+  ReductionMode reduction_mode_;
   long backtrack_count_        = 0;
 
-  static xbt::signal<void()> on_exploration_start_signal;
-  static xbt::signal<void()> on_backtracking_signal;
+  static xbt::signal<void(RemoteApp&)> on_exploration_start_signal;
+  static xbt::signal<void(RemoteApp&)> on_backtracking_signal;
 
-  static xbt::signal<void(State*)> on_state_creation_signal;
+  static xbt::signal<void(State*, RemoteApp&)> on_state_creation_signal;
 
-  static xbt::signal<void(State*)> on_restore_system_state_signal;
-  static xbt::signal<void()> on_restore_initial_state_signal;
-  static xbt::signal<void(Transition*)> on_transition_replay_signal;
-  static xbt::signal<void(Transition*)> on_transition_execute_signal;
+  static xbt::signal<void(State*, RemoteApp&)> on_restore_system_state_signal;
+  static xbt::signal<void(RemoteApp&)> on_restore_initial_state_signal;
+  static xbt::signal<void(Transition*, RemoteApp&)> on_transition_replay_signal;
+  static xbt::signal<void(Transition*, RemoteApp&)> on_transition_execute_signal;
 
-  static xbt::signal<void()> on_log_state_signal;
+  static xbt::signal<void(RemoteApp&)> on_log_state_signal;
 
 public:
-  explicit DFSExplorer(Session* session);
+  explicit DFSExplorer(const std::vector<char*>& args, bool with_dpor);
   void run() override;
   RecordTrace get_record_trace() override;
   std::vector<std::string> get_textual_trace() override;
   void log_state() override;
 
   /** Called once when the exploration starts */
-  static void on_exploration_start(std::function<void()> const& f) { on_exploration_start_signal.connect(f); }
+  static void on_exploration_start(std::function<void(RemoteApp& remote_app)> const& f)
+  {
+    on_exploration_start_signal.connect(f);
+  }
   /** Called each time that the exploration backtracks from a exploration end */
-  static void on_backtracking(std::function<void()> const& f) { on_backtracking_signal.connect(f); }
+  static void on_backtracking(std::function<void(RemoteApp& remote_app)> const& f)
+  {
+    on_backtracking_signal.connect(f);
+  }
   /** Called each time that a new state is create */
-  static void on_state_creation(std::function<void(State*)> const& f) { on_state_creation_signal.connect(f); }
+  static void on_state_creation(std::function<void(State*, RemoteApp& remote_app)> const& f)
+  {
+    on_state_creation_signal.connect(f);
+  }
   /** Called when rollbacking directly onto a previously checkpointed state */
-  static void on_restore_system_state(std::function<void(State*)> const& f)
+  static void on_restore_system_state(std::function<void(State*, RemoteApp& remote_app)> const& f)
   {
     on_restore_system_state_signal.connect(f);
   }
   /** Called when the state to which we backtrack was not checkpointed state, forcing us to restore the initial state
    * before replaying some transitions */
-  static void on_restore_initial_state(std::function<void()> const& f) { on_restore_initial_state_signal.connect(f); }
+  static void on_restore_initial_state(std::function<void(RemoteApp& remote_app)> const& f)
+  {
+    on_restore_initial_state_signal.connect(f);
+  }
   /** Called when replaying a transition that was previously executed, to reach a backtracked state */
-  static void on_transition_replay(std::function<void(Transition*)> const& f)
+  static void on_transition_replay(std::function<void(Transition*, RemoteApp& remote_app)> const& f)
   {
     on_transition_replay_signal.connect(f);
   }
   /** Called when executing a new transition */
-  static void on_transition_execute(std::function<void(Transition*)> const& f)
+  static void on_transition_execute(std::function<void(Transition*, RemoteApp& remote_app)> const& f)
   {
     on_transition_execute_signal.connect(f);
   }
   /** Called when displaying the statistics at the end of the exploration */
-  static void on_log_state(std::function<void()> const& f) { on_log_state_signal.connect(f); }
+  static void on_log_state(std::function<void(RemoteApp&)> const& f) { on_log_state_signal.connect(f); }
 
 private:
   void check_non_termination(const State* current_state);
   void backtrack();
-  void restore_state();
 
   /** Stack representing the position in the exploration graph */
   std::list<std::unique_ptr<State>> stack_;
diff --git a/src/mc/explo/Exploration.cpp b/src/mc/explo/Exploration.cpp
new file mode 100644 (file)
index 0000000..e23d38c
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (c) 2016-2022. 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/Exploration.hpp"
+#include "src/mc/mc_config.hpp"
+#include "src/mc/mc_private.hpp"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_explo, mc, "Generic exploration algorithm of the model-checker");
+
+namespace simgrid::mc {
+
+Exploration::Exploration(const std::vector<char*>& args) : remote_app_(std::make_unique<RemoteApp>(args))
+{
+  mc_model_checker->set_exploration(this);
+}
+
+void Exploration::log_state()
+{
+  if (not _sg_mc_dot_output_file.get().empty()) {
+    mc_model_checker->dot_output("}\n");
+    mc_model_checker->dot_output_close();
+  }
+  if (getenv("SIMGRID_MC_SYSTEM_STATISTICS")) {
+    int ret = system("free");
+    if (ret != 0)
+      XBT_WARN("Call to system(free) did not return 0, but %d", ret);
+  }
+}
+
+}; // namespace simgrid::mc
index 5b995f7..9dfebd2 100644 (file)
@@ -1,5 +1,4 @@
-/* Copyright (c) 2016-2022. The SimGrid Team.
- * All rights reserved.                                                     */
+/* Copyright (c) 2016-2022. 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. */
@@ -7,7 +6,12 @@
 #ifndef SIMGRID_MC_CHECKER_HPP
 #define SIMGRID_MC_CHECKER_HPP
 
-#include "src/mc/api.hpp"
+#include "simgrid/forward.h"
+#include "src/mc/api/RemoteApp.hpp"
+#include "src/mc/mc_record.hpp"
+#include <xbt/Extendable.hpp>
+
+#include <memory>
 
 namespace simgrid::mc {
 
@@ -20,15 +24,14 @@ namespace simgrid::mc {
  *  you might be able to write your model-checking algorithm as plain
  *  imperative code instead.
  *
- *  It is expected to interact with the model-checking core through the
- * `Session` interface (but currently the `Session` interface does not
- *  have all the necessary features). */
+ *  It is expected to interact with the model-checked application through the
+ * `RemoteApp` interface (that is currently not perfectly sufficient to that extend). */
 // abstract
 class Exploration : public xbt::Extendable<Exploration> {
-  Session* session_;
+  std::unique_ptr<RemoteApp> remote_app_;
 
 public:
-  explicit Exploration(Session* session) : session_(session) {}
+  explicit Exploration(const std::vector<char*>& args);
 
   // No copy:
   Exploration(Exploration const&) = delete;
@@ -52,16 +55,16 @@ public:
   virtual std::vector<std::string> get_textual_trace() = 0;
 
   /** Log additional information about the state of the model-checker */
-  virtual void log_state() = 0;
+  virtual void log_state();
 
-  Session& get_session() { return *session_; }
+  RemoteApp& get_remote_app() { return *remote_app_.get(); }
 };
 
 // External constructors so that the types (and the types of their content) remain hidden
-XBT_PUBLIC Exploration* create_liveness_checker(Session* session);
-XBT_PUBLIC Exploration* create_dfs_exploration(Session* session);
-XBT_PUBLIC Exploration* create_communication_determinism_checker(Session* session);
-XBT_PUBLIC Exploration* create_udpor_checker(Session* session);
+XBT_PUBLIC Exploration* create_liveness_checker(const std::vector<char*>& args);
+XBT_PUBLIC Exploration* create_dfs_exploration(const std::vector<char*>& args, bool with_dpor);
+XBT_PUBLIC Exploration* create_communication_determinism_checker(const std::vector<char*>& args, bool with_dpor);
+XBT_PUBLIC Exploration* create_udpor_checker(const std::vector<char*>& args);
 
 } // namespace simgrid::mc
 
index c467eee..8f1ecb2 100644 (file)
@@ -4,7 +4,7 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/mc/explo/LivenessChecker.hpp"
-#include "src/mc/Session.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"
@@ -18,21 +18,20 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_liveness, mc, "Logging specific to algorithms
 
 namespace simgrid::mc {
 
-VisitedPair::VisitedPair(int pair_num, xbt_automaton_state_t automaton_state,
-                         std::shared_ptr<const std::vector<int>> atomic_propositions,
-                         std::shared_ptr<State> graph_state)
-    : num(pair_num), automaton_state(automaton_state)
+VisitedPair::VisitedPair(int pair_num, xbt_automaton_state_t prop_state,
+                         std::shared_ptr<const std::vector<int>> atomic_propositions, std::shared_ptr<State> app_state)
+    : num(pair_num), prop_state_(prop_state)
 {
-  this->graph_state = std::move(graph_state);
-  if (not this->graph_state->get_system_state())
-    this->graph_state->set_system_state(std::make_shared<Snapshot>(pair_num));
-  this->heap_bytes_used     = Api::get().get_remote_heap_bytes();
-  this->actors_count        = Api::get().get_actors().size();
+  this->app_state_ = std::move(app_state);
+  if (not this->app_state_->get_system_state())
+    this->app_state_->set_system_state(std::make_shared<Snapshot>(pair_num));
+  this->heap_bytes_used     = mc_model_checker->get_remote_process().get_remote_heap_bytes();
+  this->actor_count_        = app_state_->get_actor_count();
   this->other_num           = -1;
   this->atomic_propositions = std::move(atomic_propositions);
 }
 
-static bool evaluate_label(const xbt_automaton_exp_label* l, std::vector<int> const& values)
+bool LivenessChecker::evaluate_label(const xbt_automaton_exp_label* l, std::vector<int> const& values)
 {
   switch (l->type) {
     case xbt_automaton_exp_label::AUT_OR:
@@ -42,7 +41,7 @@ static bool evaluate_label(const xbt_automaton_exp_label* l, std::vector<int> co
     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(Api::get().compare_automaton_exp_label(l)) != 0;
+      return values.at(compare_automaton_exp_label(l)) != 0;
     case xbt_automaton_exp_label::AUT_ONE:
       return true;
     default:
@@ -54,30 +53,31 @@ Pair::Pair(unsigned long expanded_pairs) : num(expanded_pairs) {}
 
 std::shared_ptr<const std::vector<int>> LivenessChecker::get_proposition_values() const
 {
-  auto values = Api::get().automaton_propositional_symbol_evaluate();
+  auto values = automaton_propositional_symbol_evaluate();
   return std::make_shared<const std::vector<int>>(std::move(values));
 }
 
 std::shared_ptr<VisitedPair> LivenessChecker::insert_acceptance_pair(simgrid::mc::Pair* pair)
 {
   auto new_pair =
-      std::make_shared<VisitedPair>(pair->num, pair->automaton_state, pair->atomic_propositions, pair->graph_state);
+      std::make_shared<VisitedPair>(pair->num, pair->prop_state_, pair->atomic_propositions, pair->app_state_);
 
-  auto [res_begin, res_end] = boost::range::equal_range(acceptance_pairs_, new_pair.get(), Api::get().compare_pair());
+  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<simgrid::mc::VisitedPair> const& pair_test = *i;
-      if (xbt_automaton_state_compare(pair_test->automaton_state, new_pair->automaton_state) != 0 ||
+      if (xbt_automaton_state_compare(pair_test->prop_state_, new_pair->prop_state_) != 0 ||
           *(pair_test->atomic_propositions) != *(new_pair->atomic_propositions) ||
-          not Api::get().snapshot_equal(pair_test->graph_state->get_system_state(),
-                                        new_pair->graph_state->get_system_state()))
+          (*pair_test->app_state_->get_system_state() != *new_pair->app_state_->get_system_state()))
         continue;
       XBT_INFO("Pair %d already reached (equal to pair %d) !", new_pair->num, pair_test->num);
       exploration_stack_.pop_back();
-      if (dot_output != nullptr)
-        fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", this->previous_pair_, pair_test->num,
-                this->previous_request_.c_str());
+      mc_model_checker->dot_output("\"%d\" -> \"%d\" [%s];\n", this->previous_pair_, pair_test->num,
+                                   this->previous_request_.c_str());
       return nullptr;
     }
 
@@ -101,13 +101,13 @@ void LivenessChecker::replay()
   /* Intermediate backtracking */
   if (_sg_mc_checkpoint > 0) {
     const Pair* pair = exploration_stack_.back().get();
-    if (const auto* system_state = pair->graph_state->get_system_state()) {
-      Api::get().restore_state(system_state);
+    if (const auto* system_state = pair->app_state_->get_system_state()) {
+      system_state->restore(&get_remote_app().get_remote_process());
       return;
     }
   }
 
-  get_session().restore_initial_state();
+  get_remote_app().restore_initial_state();
 
   /* Traverse the stack from the initial state and re-execute the transitions */
   int depth = 1;
@@ -115,7 +115,7 @@ void LivenessChecker::replay()
     if (pair == exploration_stack_.back())
       break;
 
-    std::shared_ptr<State> state = pair->graph_state;
+    std::shared_ptr<State> state = pair->app_state_;
 
     if (pair->exploration_started) {
       state->get_transition()->replay();
@@ -139,27 +139,25 @@ int LivenessChecker::insert_visited_pair(std::shared_ptr<VisitedPair> visited_pa
 
   if (visited_pair == nullptr)
     visited_pair =
-        std::make_shared<VisitedPair>(pair->num, pair->automaton_state, pair->atomic_propositions, pair->graph_state);
+        std::make_shared<VisitedPair>(pair->num, pair->prop_state_, pair->atomic_propositions, pair->app_state_);
 
-  auto [range_begin, range_end] =
-      boost::range::equal_range(visited_pairs_, visited_pair.get(), Api::get().compare_pair());
+  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->automaton_state, visited_pair->automaton_state) != 0 ||
+    if (xbt_automaton_state_compare(pair_test->prop_state_, visited_pair->prop_state_) != 0 ||
         *(pair_test->atomic_propositions) != *(visited_pair->atomic_propositions) ||
-        not Api::get().snapshot_equal(pair_test->graph_state->get_system_state(),
-                                      visited_pair->graph_state->get_system_state()))
+        (*pair_test->app_state_->get_system_state() != *visited_pair->app_state_->get_system_state()))
       continue;
     if (pair_test->other_num == -1)
       visited_pair->other_num = pair_test->num;
     else
       visited_pair->other_num = pair_test->other_num;
-    if (dot_output == nullptr)
-      XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", visited_pair->num, pair_test->num);
-    else
-      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);
+    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;
   }
@@ -179,13 +177,85 @@ void LivenessChecker::purge_visited_pairs()
   }
 }
 
-LivenessChecker::LivenessChecker(Session* session) : Exploration(session) {}
+LivenessChecker::LivenessChecker(const std::vector<char*>& args) : Exploration(args) {}
+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<int> LivenessChecker::automaton_propositional_symbol_evaluate() const
+{
+  unsigned int cursor = 0;
+  std::vector<int> 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<xbt_automaton_state_t> LivenessChecker::get_automaton_state() const
+{
+  std::vector<xbt_automaton_state_t> 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(RemoteProcess const& remote_process, const char* name,
+                                                RemotePtr<int> 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<Pair> const& pair : exploration_stack_)
-    res.push_back(pair->graph_state->get_transition());
+    res.push_back(pair->app_state_->get_transition());
   return res;
 }
 
@@ -194,6 +264,7 @@ 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)
@@ -213,7 +284,7 @@ std::vector<std::string> LivenessChecker::get_textual_trace() // override
 {
   std::vector<std::string> trace;
   for (std::shared_ptr<Pair> const& pair : exploration_stack_)
-    trace.push_back(pair->graph_state->get_transition()->to_string());
+    trace.push_back(pair->app_state_->get_transition()->to_string());
 
   return trace;
 }
@@ -223,23 +294,21 @@ std::shared_ptr<Pair> LivenessChecker::create_pair(const Pair* current_pair, xbt
 {
   ++expanded_pairs_count_;
   auto next_pair                 = std::make_shared<Pair>(expanded_pairs_count_);
-  next_pair->automaton_state     = state;
-  next_pair->graph_state         = std::make_shared<State>();
+  next_pair->prop_state_         = state;
+  next_pair->app_state_          = std::make_shared<State>(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& act : Api::get().get_actors()) {
-    auto actor = act.copy.get_buffer();
-    if (get_session().actor_is_enabled(actor->get_pid()))
-      next_pair->graph_state->mark_todo(actor->get_pid());
-  }
+  for (auto const& [aid, _] : next_pair->app_state_->get_actors_list())
+    if (next_pair->app_state_->is_actor_enabled(aid))
+      next_pair->app_state_->mark_todo(aid);
 
-  next_pair->requests = next_pair->graph_state->count_todo();
+  next_pair->requests = next_pair->app_state_->count_todo();
   /* FIXME : get search_cycle value for each accepting state */
-  if (next_pair->automaton_state->type == 1 || (current_pair && current_pair->search_cycle))
+  if (next_pair->prop_state_->type == 1 || (current_pair && current_pair->search_cycle))
     next_pair->search_cycle = true;
   else
     next_pair->search_cycle = false;
@@ -262,7 +331,7 @@ void LivenessChecker::backtrack()
       break;
     } else {
       XBT_DEBUG("Delete pair %d at depth %d", current_pair->num, current_pair->depth);
-      if (current_pair->automaton_state->type == 1)
+      if (current_pair->prop_state_->type == 1)
         this->remove_acceptance_pair(current_pair->num);
     }
   }
@@ -271,10 +340,9 @@ void LivenessChecker::backtrack()
 void LivenessChecker::run()
 {
   XBT_INFO("Check the liveness property %s", _sg_mc_property_file.get().c_str());
-  Api::get().automaton_load(_sg_mc_property_file.get().c_str());
+  automaton_load(_sg_mc_property_file.get().c_str());
 
   XBT_DEBUG("Starting the liveness algorithm");
-  get_session().take_initial_snapshot();
 
   /* Initialize */
   this->previous_pair_ = 0;
@@ -283,7 +351,7 @@ void LivenessChecker::run()
 
   // For each initial state of the property automaton, push a
   // (application_state, automaton_state) pair to the exploration stack:
-  auto automaton_stack = Api::get().get_automaton_state();
+  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));
@@ -294,11 +362,11 @@ void LivenessChecker::run()
     std::shared_ptr<Pair> current_pair = exploration_stack_.back();
 
     /* Update current state in buchi automaton */
-    Api::get().set_property_automaton(current_pair->automaton_state);
+    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->graph_state->count_todo(), current_pair->num,
+        current_pair->depth, current_pair->search_cycle, current_pair->app_state_->count_todo(), current_pair->num,
         current_pair->requests);
 
     if (current_pair->requests == 0) {
@@ -307,7 +375,7 @@ void LivenessChecker::run()
     }
 
     std::shared_ptr<VisitedPair> reached_pair;
-    if (current_pair->automaton_state->type == 1 && not current_pair->exploration_started) {
+    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);
@@ -319,11 +387,10 @@ void LivenessChecker::run()
     if (not current_pair->exploration_started) {
       int visited_num = this->insert_visited_pair(reached_pair, current_pair.get());
       if (visited_num != -1) {
-        if (dot_output != nullptr) {
-          fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", this->previous_pair_, visited_num,
-                  this->previous_request_.c_str());
-          fflush(dot_output);
-        }
+        mc_model_checker->dot_output("\"%d\" -> \"%d\" [%s];\n", this->previous_pair_, visited_num,
+                                     this->previous_request_.c_str());
+        mc_model_checker->dot_output_flush();
+
         XBT_DEBUG("Pair already visited (equal to pair %d), exploration on the current path stopped.", visited_num);
         current_pair->requests = 0;
         this->backtrack();
@@ -331,21 +398,20 @@ void LivenessChecker::run()
       }
     }
 
-    current_pair->graph_state->execute_next(current_pair->graph_state->next_transition());
-    XBT_DEBUG("Execute: %s", current_pair->graph_state->get_transition()->to_string().c_str());
+    current_pair->app_state_->execute_next(current_pair->app_state_->next_transition());
+    XBT_DEBUG("Execute: %s", current_pair->app_state_->get_transition()->to_string().c_str());
 
-    if (dot_output != nullptr) {
-      if (this->previous_pair_ != 0 && this->previous_pair_ != current_pair->num) {
-        fprintf(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->graph_state->get_transition()->dot_string();
-      if (current_pair->search_cycle)
-        fprintf(dot_output, "%d [shape=doublecircle];\n", current_pair->num);
-      fflush(dot_output);
+    /* Update the dot output */
+    if (this->previous_pair_ != 0 && this->previous_pair_ != current_pair->num) {
+      mc_model_checker->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()->dot_string();
+    if (current_pair->search_cycle)
+      mc_model_checker->dot_output("%d [shape=doublecircle];\n", current_pair->num);
+    mc_model_checker->dot_output_flush();
 
     if (not current_pair->exploration_started)
       visited_pairs_count_++;
@@ -358,10 +424,9 @@ void LivenessChecker::run()
 
     // 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->automaton_state->out) - 1; i >= 0; i--) {
-      const auto* transition_succ_label =
-          Api::get().get_automaton_transition_label(current_pair->automaton_state->out, i);
-      auto* transition_succ_dst = Api::get().get_automaton_transition_dst(current_pair->automaton_state->out, i);
+    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));
     }
@@ -371,9 +436,9 @@ void LivenessChecker::run()
   log_state();
 }
 
-Exploration* create_liveness_checker(Session* session)
+Exploration* create_liveness_checker(const std::vector<char*>& args)
 {
-  return new LivenessChecker(session);
+  return new LivenessChecker(args);
 }
 
 } // namespace simgrid::mc
index 31aa65c..a9008f9 100644 (file)
@@ -19,10 +19,10 @@ namespace simgrid::mc {
 
 class XBT_PRIVATE Pair {
 public:
-  int num                               = 0;
-  bool search_cycle                     = false;
-  std::shared_ptr<State> graph_state    = nullptr; /* System state included */
-  xbt_automaton_state_t automaton_state = nullptr;
+  int num                           = 0;
+  bool search_cycle                 = false;
+  std::shared_ptr<State> 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<const std::vector<int>> atomic_propositions;
   int requests             = 0;
   int depth                = 0;
@@ -38,19 +38,21 @@ class XBT_PRIVATE VisitedPair {
 public:
   int num;
   int other_num                      = 0;       /* Dot output for */
-  std::shared_ptr<State> graph_state = nullptr; /* System state included */
-  xbt_automaton_state_t automaton_state;
+  std::shared_ptr<State> app_state_  = nullptr; /* State of the application (including system state) */
+  xbt_automaton_state_t prop_state_;            /* State of the property automaton */
   std::shared_ptr<const std::vector<int>> atomic_propositions;
   std::size_t heap_bytes_used = 0;
-  int actors_count            = 0;
+  int actor_count_;
 
-  VisitedPair(int pair_num, xbt_automaton_state_t automaton_state,
-              std::shared_ptr<const std::vector<int>> atomic_propositions, std::shared_ptr<State> graph_state);
+  VisitedPair(int pair_num, xbt_automaton_state_t prop_state,
+              std::shared_ptr<const std::vector<int>> atomic_propositions, std::shared_ptr<State> app_state);
 };
 
 class XBT_PRIVATE LivenessChecker : public Exploration {
 public:
-  explicit LivenessChecker(Session* session);
+  explicit LivenessChecker(const std::vector<char*>& args);
+  ~LivenessChecker() override;
+
   void run() override;
   RecordTrace get_record_trace() override;
   std::vector<std::string> get_textual_trace() override;
@@ -76,6 +78,29 @@ private:
   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<int> const& values);
+
+public:
+  void automaton_load(const char* file) const;
+  std::vector<int> automaton_propositional_symbol_evaluate() const;
+  std::vector<xbt_automaton_state_t> 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(RemoteProcess const& remote_process, const char* name, RemotePtr<int> addr);
 };
 
 } // namespace simgrid::mc
index 7f43c4e..edd6add 100644 (file)
@@ -10,7 +10,7 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_udpor, mc, "Logging specific to MC safety ver
 
 namespace simgrid::mc {
 
-UdporChecker::UdporChecker(Session* session) : Exploration(session) {}
+UdporChecker::UdporChecker(const std::vector<char*>& args) : Exploration(args) {}
 
 void UdporChecker::run() {}
 
@@ -26,11 +26,9 @@ std::vector<std::string> UdporChecker::get_textual_trace()
   return trace;
 }
 
-void UdporChecker::log_state() {}
-
-Exploration* create_udpor_checker(Session* session)
+Exploration* create_udpor_checker(const std::vector<char*>& args)
 {
-  return new UdporChecker(session);
+  return new UdporChecker(args);
 }
 
 } // namespace simgrid::mc
index 168a14a..828f43b 100644 (file)
@@ -14,11 +14,10 @@ namespace simgrid::mc {
 
 class XBT_PRIVATE UdporChecker : public Exploration {
 public:
-  explicit UdporChecker(Session* session);
+  explicit UdporChecker(const std::vector<char*>& args);
   void run() override;
   RecordTrace get_record_trace() override;
   std::vector<std::string> get_textual_trace() override;
-  void log_state() override;
 };
 
 } // namespace simgrid::mc
index afd997a..d540f2a 100644 (file)
@@ -4,7 +4,6 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "simgrid/sg_config.hpp"
-#include "src/internal_config.h"
 #include "src/mc/explo/Exploration.hpp"
 #include "src/mc/mc_config.hpp"
 #include "src/mc/mc_exit.hpp"
@@ -13,9 +12,9 @@
 #include "smpi/smpi.h"
 #endif
 
-#include <cstring>
-#include <memory>
-#include <unistd.h>
+XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(mc);
+
+using namespace simgrid::mc;
 
 int main(int argc, char** argv)
 {
@@ -30,32 +29,29 @@ int main(int argc, char** argv)
 
   xbt_log_init(&argc, argv);
 #if HAVE_SMPI
-  smpi_init_options(); // only performed once
+  smpi_init_options(); // that's OK to call it twice, and we need it ASAP
 #endif
   sg_config_init(&argc, argv);
 
-  simgrid::mc::ExplorationAlgorithm algo;
+  std::unique_ptr<Exploration> explo;
+
   if (_sg_mc_comms_determinism || _sg_mc_send_determinism)
-    algo = simgrid::mc::ExplorationAlgorithm::CommDeterminism;
+    explo = std::unique_ptr<Exploration>(create_communication_determinism_checker(argv_copy, cfg_use_DPOR()));
   else if (_sg_mc_unfolding_checker)
-    algo = simgrid::mc::ExplorationAlgorithm::UDPOR;
+    explo = std::unique_ptr<Exploration>(create_udpor_checker(argv_copy));
   else if (_sg_mc_property_file.get().empty())
-    algo = simgrid::mc::ExplorationAlgorithm::Safety;
+    explo = std::unique_ptr<Exploration>(create_dfs_exploration(argv_copy, cfg_use_DPOR()));
   else
-    algo = simgrid::mc::ExplorationAlgorithm::Liveness;
+    explo = std::unique_ptr<Exploration>(create_liveness_checker(argv_copy));
 
-  int res      = SIMGRID_MC_EXIT_SUCCESS;
-  std::unique_ptr<simgrid::mc::Exploration> checker{simgrid::mc::Api::get().initialize(argv_copy.data(), algo)};
   try {
-    checker->run();
-  } catch (const simgrid::mc::DeadlockError&) {
-    res = SIMGRID_MC_EXIT_DEADLOCK;
-  } catch (const simgrid::mc::TerminationError&) {
-    res = SIMGRID_MC_EXIT_NON_TERMINATION;
-  } catch (const simgrid::mc::LivenessError&) {
-    res = SIMGRID_MC_EXIT_LIVENESS;
+    explo->run();
+  } catch (const DeadlockError&) {
+    return SIMGRID_MC_EXIT_DEADLOCK;
+  } catch (const TerminationError&) {
+    return SIMGRID_MC_EXIT_NON_TERMINATION;
+  } catch (const LivenessError&) {
+    return SIMGRID_MC_EXIT_LIVENESS;
   }
-  simgrid::mc::Api::get().s_close();
-  checker.release(); // FIXME: this line should not exist, but it segfaults in liveness
-  return res;
+  return SIMGRID_MC_EXIT_SUCCESS;
 }
index 12c79f0..f8608cd 100644 (file)
@@ -31,9 +31,7 @@ private:
 public:
   LocationListEntry() = default;
   LocationListEntry(DwarfExpression expression, range_type range) : expression_(std::move(expression)), range_(range) {}
-  explicit LocationListEntry(DwarfExpression expression) : expression_(std::move(expression)), range_({0, UINT64_MAX})
-  {
-  }
+  explicit LocationListEntry(DwarfExpression expression) : expression_(std::move(expression)) {}
 
   DwarfExpression& expression() { return expression_; }
   DwarfExpression const& expression() const { return expression_; }
index 553ec19..44ad73e 100644 (file)
@@ -516,7 +516,7 @@ static simgrid::mc::Type MC_dwarf_die_to_type(simgrid::mc::ObjectInformation* in
   // Global Offset
   type.id = dwarf_dieoffset(die);
 
-  const char* prefix = "";
+  const char* prefix;
   switch (type.type) {
     case DW_TAG_structure_type:
       prefix = "struct ";
index 4515ea6..671fccd 100644 (file)
@@ -1,3 +1,5 @@
+/** \file  Libunwind namespace implementation using process_vm_readv.       */
+
 /* Copyright (c) 2015-2022. The SimGrid Team. All rights reserved.          */
 
 /* This program is free software; you can redistribute it and/or modify it
@@ -13,9 +15,6 @@
 #include <libunwind-ptrace.h>
 #include <libunwind.h>
 
-/** \file
- *  Libunwind namespace implementation using process_vm_readv.
- */
 
 /** Partial structure of libunwind-ptrace context in order to get the PID
  *
@@ -28,21 +27,13 @@ struct _UPT_info {
   // Other things...
 };
 
-/** Get the PID of a `libunwind-ptrace` context
- */
-static inline pid_t _UPT_getpid(void* arg)
-{
-  const _UPT_info* info = static_cast<_UPT_info*>(arg);
-  return info->pid;
-}
-
 /** 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   = _UPT_getpid(arg);
+  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 */
index fe612c9..91012ba 100644 (file)
@@ -16,7 +16,7 @@
 
 #if SIMGRID_HAVE_MC
 #include "src/mc/ModelChecker.hpp"
-#include "src/mc/Session.hpp"
+#include "src/mc/api/RemoteApp.hpp"
 #include "src/mc/remote/RemoteProcess.hpp"
 #endif
 
@@ -40,9 +40,7 @@ namespace simgrid::mc {
 void execute_actors()
 {
   auto* engine = kernel::EngineImpl::get_instance();
-#if SIMGRID_HAVE_MC
-  xbt_assert(mc_model_checker == nullptr, "This must be called from the client");
-#endif
+
   while (engine->has_actors_to_run()) {
     engine->run_all_actors();
     for (auto const& actor : engine->get_actors_that_ran()) {
@@ -51,15 +49,6 @@ void execute_actors()
         actor->simcall_handle(0);
     }
   }
-#if SIMGRID_HAVE_MC
-  engine->reset_actor_dynar();
-  for (auto const& [_, actor] : engine->get_actor_list()) {
-    // Only visible requests remain at this point, and they all have an observer
-    actor->simcall_.mc_max_consider_ = actor->simcall_.observer_->get_max_consider();
-
-    engine->add_actor_to_dynar(actor);
-  }
-#endif
 }
 
 /** @brief returns if there this transition can proceed in a finite amount of time
index 7d11040..e64019f 100644 (file)
@@ -5,7 +5,6 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/mc/ModelChecker.hpp"
-#include "src/mc/mc_ignore.hpp"
 #include "src/mc/mc_private.hpp"
 #include "src/mc/mc_record.hpp"
 #include "src/mc/mc_replay.hpp"
@@ -31,23 +30,6 @@ void MC_assert(int prop)
   }
 }
 
-void MC_cut()
-{
-  xbt_assert(mc_model_checker == nullptr);
-  if (not MC_is_active())
-    return;
-  // FIXME, We want to do this in the model-checker:
-  xbt_die("MC_cut() not implemented");
-}
-
-void MC_ignore(void* addr, size_t size)
-{
-  xbt_assert(mc_model_checker == nullptr);
-  if (not MC_is_active())
-    return;
-  simgrid::mc::AppSide::get()->ignore_memory(addr, size);
-}
-
 void MC_automaton_new_propositional_symbol(const char* /*id*/, int (*/*fct*/)())
 {
   xbt_assert(mc_model_checker == nullptr);
@@ -65,46 +47,22 @@ void MC_automaton_new_propositional_symbol_pointer(const char *name, int* value)
   simgrid::mc::AppSide::get()->declare_symbol(name, value);
 }
 
-/** @brief 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.
- *
- *  @param stack Where the stack is
- *  @param actor Actor owning the stack
- *  @param context The context associated to that stack
- *  @param size    Size of the stack
- */
-void MC_register_stack_area(void* stack, ucontext_t* context, size_t size)
-{
-  xbt_assert(mc_model_checker == nullptr);
-  if (not MC_is_active())
-    return;
-  simgrid::mc::AppSide::get()->declare_stack(stack, size, context);
-}
-
-void MC_ignore_global_variable(const char* /*name*/)
+void MC_ignore(void* addr, size_t size)
 {
   xbt_assert(mc_model_checker == nullptr);
   if (not MC_is_active())
     return;
-  // TODO, send a message to the model_checker
-  xbt_die("Unimplemented");
+  simgrid::mc::AppSide::get()->ignore_memory(addr, size);
 }
 
 void MC_ignore_heap(void *address, size_t size)
 {
   xbt_assert(mc_model_checker == nullptr);
-  if (not MC_is_active())
-    return;
   simgrid::mc::AppSide::get()->ignore_heap(address, size);
 }
 
 void MC_unignore_heap(void* address, size_t size)
 {
   xbt_assert(mc_model_checker == nullptr);
-  if (not MC_is_active())
-    return;
   simgrid::mc::AppSide::get()->unignore_heap(address, size);
 }
index f33a895..fb1b1a6 100644 (file)
@@ -8,25 +8,18 @@
 #include <simgrid/sg_config.hpp>
 
 #if SIMGRID_HAVE_MC
-#include "src/mc/mc_safety.hpp"
 #include <string_view>
-#endif
 
-#if SIMGRID_HAVE_MC
-namespace simgrid::mc {
-/* Configuration support */
-simgrid::mc::ReductionMode reduction_mode = simgrid::mc::ReductionMode::unset;
-} // namespace simgrid::mc
 #else
 #define _sg_do_model_check 0
 #endif
 
+XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_cfg);
+
 static void _mc_cfg_cb_check(const char* spec, bool more_check = true)
 {
   xbt_assert(_sg_cfg_init_status == 0 || _sg_do_model_check || not more_check,
-             "You are specifying a %s after the initialization (through MSG_config?), but the program was not run "
-             "under the model-checker (with simgrid-mc)). This won't work, sorry.",
-             spec);
+             "Specifying a %s is only allowed within the model-checker. Please use simgrid-mc.", spec);
 }
 
 /* Replay (this part is enabled even if MC it disabled) */
@@ -43,6 +36,13 @@ simgrid::config::Flag<bool> _sg_mc_timeout{
 int _sg_do_model_check = 0;
 int _sg_mc_max_visited_states = 0;
 
+static simgrid::config::Flag<std::string> cfg_mc_reduction{
+    "model-check/reduction", "Specify the kind of exploration reduction (either none or DPOR)", "dpor",
+    [](std::string_view value) {
+      if (value != "none" && value != "dpor")
+        xbt_die("configuration option 'model-check/reduction' can only take 'none' or 'dpor' as a value");
+    }};
+
 simgrid::config::Flag<int> _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 "
@@ -84,27 +84,17 @@ simgrid::config::Flag<std::string> _sg_mc_buffering{
      {"infty", "Infinite system buffering: MPI_Send returns immediately"}},
     [](std::string_view) { _mc_cfg_cb_check("buffering mode"); }};
 
-static simgrid::config::Flag<std::string> _sg_mc_reduce{
-    "model-check/reduction", "Specify the kind of exploration reduction (either none or DPOR)", "dpor",
-    [](std::string_view value) {
-      _mc_cfg_cb_check("reduction strategy");
-
-      if (value == "none")
-        simgrid::mc::reduction_mode = simgrid::mc::ReductionMode::none;
-      else if (value == "dpor")
-        simgrid::mc::reduction_mode = simgrid::mc::ReductionMode::dpor;
-      else
-        xbt_die("configuration option model-check/reduction can only take 'none' or 'dpor' as a value");
-    }};
-
 simgrid::config::Flag<int> _sg_mc_max_depth{"model-check/max-depth",
                                             "Maximal exploration depth (default: 1000)",
                                             1000,
                                             [](int) { _mc_cfg_cb_check("max depth value"); }};
 
 static simgrid::config::Flag<int> _sg_mc_max_visited_states__{
-    "model-check/visited", "Specify the number of visited state stored for state comparison reduction. If value=5, the "
-                           "last 5 visited states are stored. If value=0 (the default), all states are stored.",
+    "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;
@@ -120,4 +110,13 @@ simgrid::config::Flag<bool> _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"); }};
 
+bool simgrid::mc::cfg_use_DPOR()
+{
+  if (cfg_mc_reduction.get() == "dpor" && _sg_mc_max_visited_states__ > 0) {
+    XBT_INFO("Disabling DPOR since state-equality reduction is activated with 'model-check/visited'");
+    return false;
+  }
+  return cfg_mc_reduction.get() == "dpor";
+}
+
 #endif
index e5232f7..39e07cd 100644 (file)
@@ -9,6 +9,10 @@
 #include <xbt/config.hpp>
 
 /********************************** Configuration of MC **************************************/
+namespace simgrid::mc {
+bool cfg_use_DPOR(); // "model-check/reduction" == "DPOR"
+};
+
 extern "C" XBT_PUBLIC int _sg_do_model_check;
 extern XBT_PUBLIC simgrid::config::Flag<std::string> _sg_mc_buffering;
 extern XBT_PRIVATE simgrid::config::Flag<int> _sg_mc_checkpoint;
index ef21204..a3b4a17 100644 (file)
@@ -7,12 +7,11 @@
 #include "src/kernel/actor/ActorImpl.hpp"
 
 #if SIMGRID_HAVE_MC
-#include "src/mc/Session.hpp"
+#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/mc_safety.hpp"
 #include "src/mc/remote/AppSide.hpp"
 #include "src/mc/sosp/Snapshot.hpp"
 
@@ -39,23 +38,8 @@ std::vector<double> processes_time;
 
 #if SIMGRID_HAVE_MC
 
-/* Dot output */
-FILE *dot_output = nullptr;
-
-void MC_init_dot_output()
-{
-  dot_output = fopen(_sg_mc_dot_output_file.get().c_str(), "w");
-  xbt_assert(dot_output != nullptr, "Error open dot output file: %s", strerror(errno));
-
-  fprintf(dot_output,
-          "digraph graphname{\n fixedsize=true; rankdir=TB; ranksep=.25; edge [fontsize=12]; node [fontsize=10, shape=circle,width=.5 ]; graph [resolution=20, fontsize=10];\n");
-}
-
 namespace simgrid::mc {
 
-/* Liveness */
-xbt_automaton_t property_automaton = nullptr;
-
 /*******************************  Core of MC *******************************/
 /**************************************************************************/
 void dumpStack(FILE* file, unw_cursor_t* cursor)
diff --git a/src/mc/mc_hash.cpp b/src/mc/mc_hash.cpp
deleted file mode 100644 (file)
index 8b667d0..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright (c) 2014-2022. 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 <cinttypes>
-#include <cstdint>
-
-#include "xbt/log.h"
-
-#include "mc/datatypes.h"
-#include "src/mc/mc_hash.hpp"
-#include "src/mc/mc_private.hpp"
-#include "src/mc/sosp/Snapshot.hpp"
-#include <mc/mc.h>
-
-XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_hash, mc, "Logging specific to mc_hash");
-
-namespace simgrid::mc {
-
-namespace {
-
-class djb_hash {
-  hash_type state_ = 5381LL;
-
-public:
-  template<class T>
-  void update(T& x)
-  {
-    state_ = (state_ << 5) + state_ + x;
-  }
-  hash_type value() const { return state_; }
-};
-
-}
-
-hash_type hash(Snapshot const& snapshot)
-{
-  XBT_DEBUG("START hash %ld", snapshot.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", snapshot.num_state_);
-  return hash.value();
-}
-
-} // namespace simgrid::mc
diff --git a/src/mc/mc_hash.hpp b/src/mc/mc_hash.hpp
deleted file mode 100644 (file)
index 03110a7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Copyright (c) 2007-2022. 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_HASH_HPP
-#define SIMGRID_MC_HASH_HPP
-
-#include "xbt/base.h"
-#include "src/mc/mc_forward.hpp"
-
-namespace simgrid::mc {
-
-using hash_type = std::uint64_t;
-
-XBT_PRIVATE hash_type hash(simgrid::mc::Snapshot const& snapshot);
-
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/mc_ignore.hpp b/src/mc/mc_ignore.hpp
deleted file mode 100644 (file)
index 55e7254..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Copyright (c) 2015-2022. 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_IGNORE_HPP
-#define SIMGRID_MC_IGNORE_HPP
-
-#include "simgrid/forward.h"
-#include "src/internal_config.h"
-
-#if HAVE_UCONTEXT_H
-#include <ucontext.h> /* context relative declarations */
-
-XBT_PUBLIC void MC_register_stack_area(void* stack, ucontext_t* context, size_t size);
-
-#endif
-
-#endif
index fc37957..b3168d1 100644 (file)
 #include "src/mc/mc_forward.hpp"
 #include "src/xbt/memory_map.hpp"
 
-/********************************* MC Global **********************************/
-
-XBT_PRIVATE void MC_init_dot_output();
-
-XBT_PRIVATE extern FILE* dot_output;
-
 /********************************** Miscellaneous **********************************/
 namespace simgrid::mc {
 
@@ -27,8 +21,6 @@ XBT_PRIVATE void find_object_address(std::vector<simgrid::xbt::VmMap> const& map
 XBT_PRIVATE
 bool snapshot_equal(const Snapshot* s1, const Snapshot* s2);
 
-// Move is somewhere else (in the LivenessChecker class, in the Session class?):
-extern XBT_PRIVATE xbt_automaton_t property_automaton;
 } // namespace simgrid::mc
 
 #endif
diff --git a/src/mc/mc_safety.hpp b/src/mc/mc_safety.hpp
deleted file mode 100644 (file)
index e16f12e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* Copyright (c) 2007-2022. 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_SAFETY_HPP
-#define SIMGRID_MC_SAFETY_HPP
-
-#include "xbt/base.h"
-
-namespace simgrid::mc {
-
-enum class ReductionMode {
-  unset,
-  none,
-  dpor,
-};
-
-extern XBT_PRIVATE simgrid::mc::ReductionMode reduction_mode;
-} // namespace simgrid::mc
-
-#endif
diff --git a/src/mc/mc_smx.cpp b/src/mc/mc_smx.cpp
deleted file mode 100644 (file)
index 7593fc2..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* Copyright (c) 2015-2022. 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/s4u/Host.hpp"
-
-#include "src/mc/ModelChecker.hpp"
-#include "src/mc/remote/RemoteProcess.hpp"
-
-/** @file
- *  @brief (Cross-process, MCer/MCed) Access to SMX structures
- *
- *  We copy some C data structure from the MCed process in the MCer process.
- *  This is implemented by:
- *
- *   - `model_checker->process.smx_process_infos`
- *      (copy of `EngineImpl::actor_list_`);
- *
- *   - `model_checker->hostnames`.
- *
- * The process lists are currently refreshed each time MCed code is executed.
- * We don't try to give a persistent MCer address for a given MCed process.
- * For this reason, a MCer simgrid::mc::Process* is currently not reusable after
- * MCed code.
- */
-
-/** Load the remote list of processes into a vector
- *
- *  @param process      MCed process
- *  @param target       Local vector (to be filled with `simgrid::mc::ActorInformation`)
- *  @param remote_dynar Address of the process dynar in the remote list
- */
-static void MC_process_refresh_simix_actor_dynar(const simgrid::mc::RemoteProcess* process,
-                                                 std::vector<simgrid::mc::ActorInformation>& target,
-                                                 simgrid::mc::RemotePtr<s_xbt_dynar_t> remote_dynar)
-{
-  target.clear();
-
-  s_xbt_dynar_t dynar;
-  process->read_bytes(&dynar, sizeof(dynar), remote_dynar);
-
-  auto* data = static_cast<simgrid::kernel::actor::ActorImpl**>(::operator new(dynar.elmsize * dynar.used));
-  process->read_bytes(data, dynar.elmsize * dynar.used, simgrid::mc::RemotePtr<void>(dynar.data));
-
-  // Load each element of the vector from the MCed process:
-  for (unsigned int i = 0; i < dynar.used; ++i) {
-    simgrid::mc::ActorInformation info;
-
-    info.address  = simgrid::mc::RemotePtr<simgrid::kernel::actor::ActorImpl>(data[i]);
-    process->read_bytes(&info.copy, sizeof(info.copy), simgrid::mc::remote(data[i]));
-    target.push_back(std::move(info));
-  }
-  ::operator delete(data);
-}
-namespace simgrid::mc {
-
-void RemoteProcess::refresh_simix()
-{
-  if (this->cache_flags_ & RemoteProcess::cache_simix_processes)
-    return;
-
-  MC_process_refresh_simix_actor_dynar(this, this->smx_actors_infos, actors_addr_);
-
-  this->cache_flags_ |= RemoteProcess::cache_simix_processes;
-}
-
-} // namespace simgrid::mc
index 2d4dfbe..e74e4d4 100644 (file)
@@ -34,7 +34,7 @@ namespace simgrid::mc {
 
 std::unique_ptr<AppSide> AppSide::instance_;
 
-AppSide* AppSide::initialize(xbt_dynar_t actors_addr)
+AppSide* AppSide::initialize()
 {
   if (not std::getenv(MC_ENV_SOCKET_FD)) // We are not in MC mode: don't initialize the MC world
     return nullptr;
@@ -73,8 +73,8 @@ AppSide* AppSide::initialize(xbt_dynar_t actors_addr)
   xbt_assert(errno == 0 && raise(SIGSTOP) == 0, "Could not wait for the model-checker (errno = %d: %s)", errno,
              strerror(errno));
 
-  s_mc_message_initial_addresses_t message{MessageType::INITIAL_ADDRESSES, mmalloc_preinit(),
-                                           kernel::actor::ActorImpl::get_maxpid_addr(), actors_addr};
+  s_mc_message_initial_addresses_t message{MessageType::INITIAL_ADDRESSES, mmalloc_get_current_heap(),
+                                           kernel::actor::ActorImpl::get_maxpid_addr()};
   xbt_assert(instance_->channel_.send(message) == 0, "Could not send the initial message with addresses.");
 
   instance_->handle_messages();
@@ -122,13 +122,6 @@ void AppSide::handle_simcall_execute(const s_mc_message_simcall_execute_t* messa
   xbt_assert(channel_.send(answer) == 0, "Could not send response");
 }
 
-void AppSide::handle_actor_enabled(const s_mc_message_actor_enabled_t* msg) const
-{
-  bool res = mc::actor_is_enabled(kernel::EngineImpl::get_instance()->get_actor_by_pid(msg->aid));
-  s_mc_message_int_t answer{MessageType::ACTOR_ENABLED_REPLY, res};
-  xbt_assert(channel_.send(answer) == 0, "Could not send ACTOR_ENABLED_REPLY");
-}
-
 void AppSide::handle_finalize(const s_mc_message_int_t* msg) const
 {
   bool terminate_asap = msg->value;
@@ -143,12 +136,33 @@ void AppSide::handle_finalize(const s_mc_message_int_t* msg) const
 #endif
   }
   coverage_checkpoint();
-  xbt_assert(channel_.send(MessageType::DEADLOCK_CHECK_REPLY) == 0, // DEADLOCK_CHECK_REPLY, really?
-             "Could not answer to FINALIZE");
+  xbt_assert(channel_.send(MessageType::FINALIZE_REPLY) == 0, "Could not answer to FINALIZE");
   std::fflush(stdout);
   if (terminate_asap)
     ::_Exit(0);
 }
+void AppSide::handle_actors_status() const
+{
+  auto const& actor_list = kernel::EngineImpl::get_instance()->get_actor_list();
+  int count              = actor_list.size();
+
+  struct s_mc_message_actors_status_answer_t answer {
+    MessageType::ACTORS_STATUS_REPLY, count
+  };
+  std::vector<s_mc_message_actors_status_one_t> status(count);
+  int i = 0;
+  for (auto const& [aid, actor] : actor_list) {
+    status[i].aid            = aid;
+    status[i].enabled        = mc::actor_is_enabled(actor);
+    status[i].max_considered = actor->simcall_.observer_->get_max_consider();
+    i++;
+  }
+  xbt_assert(channel_.send(answer) == 0, "Could not send ACTORS_STATUS_REPLY msg");
+  if (answer.count > 0) {
+    size_t size = status.size() * sizeof(s_mc_message_actors_status_one_t);
+    xbt_assert(channel_.send(status.data(), size) == 0, "Could not send ACTORS_STATUS_REPLY data");
+  }
+}
 
 #define assert_msg_size(_name_, _type_)                                                                                \
   xbt_assert(received_size == sizeof(_type_), "Unexpected size for " _name_ " (%zd != %zu)", received_size,            \
@@ -180,16 +194,16 @@ void AppSide::handle_messages() const
         handle_simcall_execute((s_mc_message_simcall_execute_t*)message_buffer.data());
         break;
 
-      case MessageType::ACTOR_ENABLED:
-        assert_msg_size("ACTOR_ENABLED", s_mc_message_actor_enabled_t);
-        handle_actor_enabled((s_mc_message_actor_enabled_t*)message_buffer.data());
-        break;
-
       case MessageType::FINALIZE:
         assert_msg_size("FINALIZE", s_mc_message_int_t);
         handle_finalize((s_mc_message_int_t*)message_buffer.data());
         break;
 
+      case MessageType::ACTORS_STATUS:
+        assert_msg_size("ACTORS_STATUS", s_mc_message_t);
+        handle_actors_status();
+        break;
+
       default:
         xbt_die("Received unexpected message %s (%i)", to_c_str(message->type), static_cast<int>(message->type));
         break;
@@ -219,6 +233,9 @@ void AppSide::report_assertion_failure() const
 
 void AppSide::ignore_memory(void* addr, std::size_t size) const
 {
+  if (not MC_is_active())
+    return;
+
   s_mc_message_ignore_memory_t message;
   message.type = MessageType::IGNORE_MEMORY;
   message.addr = (std::uintptr_t)addr;
@@ -228,6 +245,9 @@ void AppSide::ignore_memory(void* addr, std::size_t size) const
 
 void AppSide::ignore_heap(void* address, std::size_t size) const
 {
+  if (not MC_is_active())
+    return;
+
   const s_xbt_mheap_t* heap = mmalloc_get_current_heap();
 
   s_mc_message_ignore_heap_t message;
@@ -248,6 +268,9 @@ void AppSide::ignore_heap(void* address, std::size_t size) const
 
 void AppSide::unignore_heap(void* address, std::size_t size) const
 {
+  if (not MC_is_active())
+    return;
+
   s_mc_message_ignore_memory_t message;
   message.type = MessageType::UNIGNORE_HEAP;
   message.addr = (std::uintptr_t)address;
@@ -267,8 +290,17 @@ void AppSide::declare_symbol(const char* name, int* value) const
   xbt_assert(channel_.send(message) == 0, "Could send REGISTER_SYMBOL message to model-checker");
 }
 
+/** 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.
+ */
 void AppSide::declare_stack(void* stack, size_t size, ucontext_t* context) const
 {
+  if (not MC_is_active())
+    return;
+
   const s_xbt_mheap_t* heap = mmalloc_get_current_heap();
 
   s_stack_region_t region;
index 393f1ea..b63a836 100644 (file)
@@ -31,8 +31,8 @@ public:
 private:
   void handle_deadlock_check(const s_mc_message_t* msg) const;
   void handle_simcall_execute(const s_mc_message_simcall_execute_t* message) const;
-  void handle_actor_enabled(const s_mc_message_actor_enabled_t* msg) const;
   void handle_finalize(const s_mc_message_int_t* msg) const;
+  void handle_actors_status() const;
 
 public:
   Channel const& get_channel() const { return channel_; }
@@ -49,7 +49,7 @@ public:
 
   // Singleton :/
   // TODO, remove the singleton antipattern.
-  static AppSide* initialize(xbt_dynar_t actors_addr);
+  static AppSide* initialize();
   static AppSide* get() { return instance_.get(); }
 };
 } // namespace simgrid::mc
index 654717d..75a610d 100644 (file)
@@ -105,11 +105,10 @@ int open_vm(pid_t pid, int flags)
 
 RemoteProcess::RemoteProcess(pid_t pid) : AddressSpace(this), pid_(pid), running_(true) {}
 
-void RemoteProcess::init(xbt_mheap_t mmalloc_default_mdp, unsigned long* maxpid, xbt_dynar_t actors)
+void RemoteProcess::init(xbt_mheap_t mmalloc_default_mdp, unsigned long* maxpid)
 {
   this->heap_address      = remote(mmalloc_default_mdp);
   this->maxpid_addr_      = remote(maxpid);
-  this->actors_addr_      = remote(actors);
 
   this->memory_map_ = simgrid::xbt::get_memory_map(this->pid_);
   this->init_memory_map_info();
@@ -118,7 +117,6 @@ void RemoteProcess::init(xbt_mheap_t mmalloc_default_mdp, unsigned long* maxpid,
   xbt_assert(fd >= 0, "Could not open file for process virtual address space");
   this->memory_file = fd;
 
-  this->smx_actors_infos.clear();
   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_);
@@ -147,8 +145,6 @@ RemoteProcess::~RemoteProcess()
 void RemoteProcess::refresh_heap()
 {
   // Read/dereference/refresh the std_heap pointer:
-  if (not this->heap)
-    this->heap = std::make_unique<s_xbt_mheap_t>();
   this->read(this->heap.get(), this->heap_address);
   this->cache_flags_ |= RemoteProcess::cache_heap;
 }
@@ -169,6 +165,10 @@ void RemoteProcess::refresh_malloc_info()
   this->read_bytes(this->heap_info.data(), count * sizeof(malloc_info), remote(this->heap->heapinfo));
   this->cache_flags_ |= RemoteProcess::cache_malloc;
 }
+std::size_t RemoteProcess::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 RemoteProcess::init_memory_map_info()
@@ -410,12 +410,6 @@ void RemoteProcess::ignore_local_variable(const char* var_name, const char* fram
     info->remove_local_variable(var_name, frame_name);
 }
 
-std::vector<simgrid::mc::ActorInformation>& RemoteProcess::actors()
-{
-  this->refresh_simix();
-  return smx_actors_infos;
-}
-
 void RemoteProcess::dump_stack() const
 {
   unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, BYTE_ORDER);
index 47f6151..4dc3dfd 100644 (file)
@@ -50,16 +50,12 @@ struct IgnoredHeapRegion {
   std::size_t size;
 };
 
-/** The Application's process memory, seen from the MCer perspective
- *
- *  This class is mixing a lot of different responsibilities and is tied
- *  to SIMIX. It should probably be split into different classes.
+/** The Application's process memory, seen from the Checker perspective
  *
  *  Responsibilities:
  *
  *  - reading from the process memory (`AddressSpace`);
  *  - accessing the system state of the process (heap, …);
- *  - storing the SIMIX state of the process;
  *  - privatization;
  *  - stack unwinding;
  *  - etc.
@@ -71,12 +67,11 @@ private:
   static constexpr int cache_none            = 0;
   static constexpr int cache_heap            = 1;
   static constexpr int cache_malloc          = 2;
-  static constexpr int cache_simix_processes = 4;
 
 public:
   explicit RemoteProcess(pid_t pid);
   ~RemoteProcess() override;
-  void init(xbt_mheap_t mmalloc_default_mdp, unsigned long* maxpid, xbt_dynar_t actors);
+  void init(xbt_mheap_t mmalloc_default_mdp, unsigned long* maxpid);
 
   RemoteProcess(RemoteProcess const&) = delete;
   RemoteProcess(RemoteProcess&&)      = delete;
@@ -130,6 +125,8 @@ public:
       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_ = RemoteProcess::cache_none; }
 
@@ -168,11 +165,8 @@ public:
 private:
   // Cache the address of the variables we read directly in the memory of remote
   RemotePtr<unsigned long> maxpid_addr_;
-  RemotePtr<s_xbt_dynar_t> actors_addr_;
 
 public:
-  std::vector<ActorInformation>& actors();
-
   unsigned long get_maxpid() const { return this->read(maxpid_addr_); }
 
   void dump_stack() const;
@@ -181,7 +175,6 @@ private:
   void init_memory_map_info();
   void refresh_heap();
   void refresh_malloc_info();
-  void refresh_simix();
 
   pid_t pid_    = -1;
   bool running_ = false;
@@ -193,13 +186,6 @@ private:
   std::vector<s_stack_region_t> stack_areas_;
   std::vector<IgnoredHeapRegion> ignored_heap_;
 
-  // Copies of MCed SMX data structures
-  /** Copy of `EngineImpl::actor_list_`
-   *
-   *  See mc_smx.cpp.
-   */
-  std::vector<ActorInformation> smx_actors_infos;
-
   /** State of the cache (which variables are up to date) */
   int cache_flags_ = RemoteProcess::cache_none;
 
@@ -218,7 +204,7 @@ public:
    *  This is not used if the process is the current one:
    *  use `get_heap_info()` in order to use it.
    */
-  std::unique_ptr<s_xbt_mheap_t> heap;
+  std::unique_ptr<s_xbt_mheap_t> heap = std::make_unique<s_xbt_mheap_t>();
 
   /** Copy of the allocation info structure
    *
index e83a281..bf08566 100644 (file)
@@ -8,12 +8,6 @@
 
 // ***** Environment variables for passing context to the model-checked process
 
-/** Environment variable name used to pass the communication socket.
- *
- * It is set by `simgrid-mc` to enable MC support in the children processes
- */
-#define MC_ENV_SOCKET_FD "SIMGRID_MC_SOCKET_FD"
-
 #ifdef __cplusplus
 
 #include "src/kernel/actor/SimcallObserver.hpp"
@@ -31,8 +25,8 @@ namespace simgrid::mc {
 
 XBT_DECLARE_ENUM_CLASS(MessageType, NONE, INITIAL_ADDRESSES, CONTINUE, IGNORE_HEAP, UNIGNORE_HEAP, IGNORE_MEMORY,
                        STACK_REGION, REGISTER_SYMBOL, DEADLOCK_CHECK, DEADLOCK_CHECK_REPLY, WAITING, SIMCALL_EXECUTE,
-                       SIMCALL_EXECUTE_ANSWER, ASSERTION_FAILED, ACTOR_ENABLED, ACTOR_ENABLED_REPLY, FINALIZE);
-
+                       SIMCALL_EXECUTE_ANSWER, ASSERTION_FAILED, ACTORS_STATUS, ACTORS_STATUS_REPLY, FINALIZE,
+                       FINALIZE_REPLY);
 } // namespace simgrid::mc
 
 constexpr unsigned MC_MESSAGE_LENGTH = 512;
@@ -63,7 +57,6 @@ struct s_mc_message_initial_addresses_t {
   simgrid::mc::MessageType type;
   xbt_mheap_t mmalloc_default_mdp;
   unsigned long* maxpid;
-  xbt_dynar_t actors;
 };
 
 struct s_mc_message_ignore_heap_t {
@@ -108,9 +101,15 @@ struct s_mc_message_restore_t {
   int index;
 };
 
-struct s_mc_message_actor_enabled_t {
+struct s_mc_message_actors_status_answer_t {
   simgrid::mc::MessageType type;
-  aid_t aid; // actor ID
+  int count;
+};
+struct s_mc_message_actors_status_one_t { // an array of `s_mc_message_actors_status_one_t[count]` is sent right after
+                                          // after a s_mc_message_actors_status_answer_t
+  aid_t aid;
+  bool enabled;
+  int max_considered;
 };
 
 #endif // __cplusplus
index 6b07c1f..b36d8cd 100644 (file)
@@ -5,7 +5,6 @@
 
 #include "src/mc/sosp/Snapshot.hpp"
 #include "src/mc/mc_config.hpp"
-#include "src/mc/mc_hash.hpp"
 
 #include <cstddef> /* std::size_t */
 
@@ -173,40 +172,36 @@ void Snapshot::snapshot_stacks(RemoteProcess* process)
   }
 }
 
-static void snapshot_handle_ignore(Snapshot* snapshot)
+void Snapshot::handle_ignore()
 {
-  xbt_assert(snapshot->get_remote_process());
+  xbt_assert(get_remote_process());
 
   // Copy the memory:
-  for (auto const& region : snapshot->get_remote_process()->ignored_regions()) {
+  for (auto const& region : get_remote_process()->ignored_regions()) {
     s_mc_snapshot_ignored_data_t ignored_data;
     ignored_data.start = (void*)region.addr;
     ignored_data.data.resize(region.size);
     // TODO, we should do this once per privatization segment:
-    snapshot->get_remote_process()->read_bytes(ignored_data.data.data(), region.size, remote(region.addr));
-    snapshot->ignored_data_.push_back(std::move(ignored_data));
+    get_remote_process()->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 : snapshot->get_remote_process()->ignored_regions())
-    snapshot->get_remote_process()->clear_bytes(remote(region.addr), region.size);
+  for (auto const& region : get_remote_process()->ignored_regions())
+    get_remote_process()->clear_bytes(remote(region.addr), region.size);
 }
 
-static void snapshot_ignore_restore(const simgrid::mc::Snapshot* snapshot)
+void Snapshot::ignore_restore() const
 {
-  for (auto const& ignored_data : snapshot->ignored_data_)
-    snapshot->get_remote_process()->write_bytes(ignored_data.data.data(), ignored_data.data.size(),
-                                                remote(ignored_data.start));
+  for (auto const& ignored_data : ignored_data_)
+    get_remote_process()->write_bytes(ignored_data.data.data(), ignored_data.data.size(), remote(ignored_data.start));
 }
 
 Snapshot::Snapshot(long num_state, RemoteProcess* process) : AddressSpace(process), num_state_(num_state)
 {
   XBT_DEBUG("Taking snapshot %ld", num_state);
 
-  for (auto const& p : process->actors())
-    enabled_processes_.insert(p.copy.get_buffer()->get_pid());
-
-  snapshot_handle_ignore(this);
+  handle_ignore();
 
   /* Save the std heap and the writable mapped pages of libsimgrid and binary */
   snapshot_regions(process);
@@ -215,10 +210,10 @@ Snapshot::Snapshot(long num_state, RemoteProcess* process) : AddressSpace(proces
 
   if (_sg_mc_max_visited_states > 0 || not _sg_mc_property_file.get().empty()) {
     snapshot_stacks(process);
-    hash_ = simgrid::mc::hash(*this);
+    hash_ = this->do_hash();
   }
 
-  snapshot_ignore_restore(this);
+  ignore_restore();
 }
 
 void Snapshot::add_region(RegionType type, ObjectInformation* object_info, void* start_addr, std::size_t size)
@@ -284,8 +279,30 @@ void Snapshot::restore(RemoteProcess* process) const
       region.get()->restore();
   }
 
-  snapshot_ignore_restore(this);
+  ignore_restore();
   process->clear_cache();
 }
 
+/* ----------- Hashing logic -------------- */
+class djb_hash {
+  hash_type state_ = 5381LL;
+
+public:
+  template <class T> 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
index 412c7b9..90af292 100644 (file)
@@ -15,9 +15,8 @@
 
 /** Ignored data
  *
- *  Some parts of the snapshot are ignored by zeroing them out: the real
- *  values is stored here.
- * */
+ *  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<char> data;
@@ -56,6 +55,8 @@ 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 {
 public:
   /* Initialization */
@@ -74,11 +75,13 @@ public:
   Region* get_region(const void* addr, Region* hinted_region) const;
   void restore(RemoteProcess* process) const;
 
+  bool operator==(const Snapshot& other);
+  bool operator!=(const Snapshot& other) { return not(*this == other); }
+
   // To be private
   long num_state_;
   std::size_t heap_bytes_used_ = 0;
   std::vector<std::unique_ptr<Region>> snapshot_regions_;
-  std::set<pid_t> enabled_processes_;
   std::vector<std::size_t> stack_sizes_;
   std::vector<s_mc_snapshot_stack_t> stacks_;
   std::vector<simgrid::mc::IgnoredHeapRegion> to_ignore_;
@@ -89,6 +92,9 @@ private:
   void add_region(RegionType type, ObjectInformation* object_info, void* start_addr, std::size_t size);
   void snapshot_regions(RemoteProcess* process);
   void snapshot_stacks(RemoteProcess* process);
+  void handle_ignore();
+  void ignore_restore() const;
+  hash_type do_hash() const;
 };
 } // namespace simgrid::mc
 
index 3d9bb72..01081e3 100644 (file)
@@ -58,7 +58,7 @@ void snap_test_helper::Init()
   REQUIRE(1 << xbt_pagebits == xbt_pagesize);
 
   process = std::make_unique<simgrid::mc::RemoteProcess>(getpid());
-  process->init(nullptr, nullptr, nullptr);
+  process->init(nullptr, nullptr);
   mc_model_checker = new ::simgrid::mc::ModelChecker(std::move(process), -1);
 }
 
index d590c5f..9de469b 100644 (file)
@@ -8,7 +8,7 @@
 #include <simgrid/config.h>
 #if SIMGRID_HAVE_MC
 #include "src/mc/ModelChecker.hpp"
-#include "src/mc/Session.hpp"
+#include "src/mc/api/RemoteApp.hpp"
 #include "src/mc/api/State.hpp"
 #endif
 
index 916dd8b..0d48bcf 100644 (file)
@@ -8,7 +8,7 @@
 #include <simgrid/config.h>
 #if SIMGRID_HAVE_MC
 #include "src/mc/ModelChecker.hpp"
-#include "src/mc/Session.hpp"
+#include "src/mc/api/RemoteApp.hpp"
 #include "src/mc/api/State.hpp"
 #endif
 
index da2ee32..a2f21f9 100644 (file)
@@ -18,60 +18,60 @@ static simgrid::config::Flag<bool> cfg_tell{"cmonkey/tell", "Request the Chaos M
 static simgrid::config::Flag<double> cfg_time{"cmonkey/time", "When should the chaos monkey kill a resource", -1.};
 static simgrid::config::Flag<int> cfg_link{"cmonkey/link", "Which link should be killed (number)", -1};
 static simgrid::config::Flag<int> cfg_host{"cmonkey/host", "Which host should be killed (number)", -1};
-static void sg_chaos_monkey_plugin_init();
-// Makes sure that this plugin can be activated from the command line with ``--cfg=plugin:chaos_monkey``
-SIMGRID_REGISTER_PLUGIN(cmonkey, "Chaos monkey", &sg_chaos_monkey_plugin_init)
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(cmonkey, kernel, "Chaos Monkey plugin");
 
-static void sg_chaos_monkey_plugin_init()
+static void sg_chaos_monkey_plugin_run()
 {
-  XBT_INFO("Initializing the chaos monkey");
+  auto engine = sg4::Engine::get_instance();
+  auto hosts  = engine->get_all_hosts();
+  auto links  = engine->get_all_links();
 
-  // delay the initialization until after the parameter are parsed
-  sg4::Engine::on_simulation_start_cb([]() {
-    auto engine = sg4::Engine::get_instance();
-    auto hosts  = engine->get_all_hosts();
-    auto links  = engine->get_all_links();
+  sg4::Engine::on_deadlock_cb([]() { exit(2); });
 
-    sg4::Engine::on_deadlock_cb([]() { exit(2); });
+  if (cfg_tell) {
+    XBT_INFO("HOST_COUNT=%zu", hosts.size());
+    XBT_INFO("LINK_COUNT=%zu", links.size());
+    sg4::Engine::on_time_advance_cb([engine](double /* delta*/) { XBT_INFO("TIMESTAMP=%lf", engine->get_clock()); });
+  }
 
-    if (cfg_tell) {
-      XBT_INFO("HOST_COUNT=%zu", hosts.size());
-      XBT_INFO("LINK_COUNT=%zu", links.size());
-      sg4::Engine::on_time_advance_cb([engine](double /* delta*/) { XBT_INFO("TIMESTAMP=%lf", engine->get_clock()); });
+  if (cfg_time >= 0) {
+    int host = cfg_host;
+    int link = cfg_link;
+    xbt_assert(host >= 0 || link >= 0,
+               "If a kill time is given, you must also specify a resource to kill (either a link or an host)");
+    xbt_assert(host < 0 || link < 0, "Cannot specify both a link and an host to kill");
+    if (host >= 0) {
+      auto* h = hosts[host];
+      simgrid::kernel::timer::Timer::set(cfg_time, [h]() {
+        XBT_INFO("Kill host %s", h->get_cname());
+        h->turn_off();
+      });
+      simgrid::kernel::timer::Timer::set(cfg_time + 30, [h]() {
+        XBT_INFO("Restart host %s", h->get_cname());
+        h->turn_on();
+      });
     }
-
-    if (cfg_time >= 0) {
-      int host = cfg_host;
-      int link = cfg_link;
-      xbt_assert(host >= 0 || link >= 0,
-                 "If a kill time is given, you must also specify a resource to kill (either a link or an host)");
-      xbt_assert(host < 0 || link < 0, "Cannot specify both a link and an host to kill");
-      if (host >= 0) {
-        auto* h = hosts[host];
-        simgrid::kernel::timer::Timer::set(cfg_time, [h]() {
-          XBT_INFO("Kill host %s", h->get_cname());
-          h->turn_off();
-        });
-        simgrid::kernel::timer::Timer::set(cfg_time + 30, [h]() {
-          XBT_INFO("Restart host %s", h->get_cname());
-          h->turn_on();
-        });
-      }
-      if (link >= 0) {
-        auto* l = links[link];
-        simgrid::kernel::timer::Timer::set(cfg_time, [l]() {
-          XBT_INFO("Kill link %s", l->get_cname());
-          l->turn_off();
-        });
-        simgrid::kernel::timer::Timer::set(cfg_time + 30, [l]() {
-          XBT_INFO("Restart host %s", l->get_cname());
-          l->turn_on();
-        });
-      }
+    if (link >= 0) {
+      auto* l = links[link];
+      simgrid::kernel::timer::Timer::set(cfg_time, [l]() {
+        XBT_INFO("Kill link %s", l->get_cname());
+        l->turn_off();
+      });
+      simgrid::kernel::timer::Timer::set(cfg_time + 30, [l]() {
+        XBT_INFO("Restart host %s", l->get_cname());
+        l->turn_on();
+      });
     }
+  }
 
-    sg4::Engine::on_simulation_end_cb([]() { XBT_INFO("Chaos Monkey done!"); });
-  });
+  sg4::Engine::on_simulation_end_cb([]() { XBT_INFO("Chaos Monkey done!"); });
 }
+
+// Makes sure that this plugin can be activated from the command line with ``--cfg=plugin:chaos_monkey``
+SIMGRID_REGISTER_PLUGIN(cmonkey, "Chaos monkey", []() {
+  XBT_INFO("Initializing the chaos monkey");
+
+  // delay the initialization until after the parameter are parsed
+  sg4::Engine::on_simulation_start_cb(sg_chaos_monkey_plugin_run);
+})
index 20e5c27..1a7cccc 100644 (file)
@@ -86,7 +86,6 @@ File::File(const std::string& fullpath, const_sg_host_t host, void* userdata) :
     desc_id = ext->file_descriptor_table->back();
     ext->file_descriptor_table->pop_back();
 
-    XBT_DEBUG("\tOpen file '%s'", path_.c_str());
     std::map<std::string, sg_size_t, std::less<>>* content = nullptr;
     content = local_disk_->extension<FileSystemDiskExt>()->get_content();
 
@@ -95,6 +94,7 @@ File::File(const std::string& fullpath, const_sg_host_t host, void* userdata) :
       auto sz = content->find(path_);
       if (sz != content->end()) {
         size_ = sz->second;
+       XBT_DEBUG("\tOpen file '%s', size %llu", path_.c_str(), size_);
       } else {
         size_ = 0;
         content->insert({path_, size_});
@@ -186,25 +186,11 @@ sg_size_t File::write(sg_size_t size, bool write_inside)
   // If the disk is full before even starting to write
   if (sg_disk_get_size_used(local_disk_) >= sg_disk_get_size(local_disk_))
     return 0;
-  if (not write_inside) {
+  if (not write_inside)
     /* Subtract the part of the file that might disappear from the used sized on the storage element */
     local_disk_->extension<FileSystemDiskExt>()->decr_used_size(size_ - current_position_);
-    write_size = local_disk_->write(size);
-    local_disk_->extension<FileSystemDiskExt>()->incr_used_size(write_size);
-    current_position_ += write_size;
-    size_ = current_position_;
-  } else {
-    write_size = local_disk_->write(size);
-    current_position_ += write_size;
-    if (current_position_ > size_)
-      size_ = current_position_;
-  }
-  kernel::actor::simcall_answered([this] {
-    std::map<std::string, sg_size_t, std::less<>>* content = local_disk_->extension<FileSystemDiskExt>()->get_content();
-
-    content->erase(path_);
-    content->insert({path_, size_});
-  });
+  write_size = local_disk_->write(size);
+  update_position(current_position_ + write_size);
 
   return write_size;
 }
@@ -223,19 +209,36 @@ void File::seek(sg_offset_t offset, int origin)
 {
   switch (origin) {
     case SEEK_SET:
-      current_position_ = offset;
-      break;
+      update_position(offset);
+     break;
     case SEEK_CUR:
-      current_position_ += offset;
+      update_position(current_position_ + offset);
       break;
     case SEEK_END:
-      current_position_ = size_ + offset;
+      update_position(size_ + offset);
       break;
     default:
       break;
   }
 }
 
+void File::update_position(sg_offset_t position)
+{
+  xbt_assert(position >= 0, "Error in seek, cannot seek before file %s", get_path());
+  current_position_ = position;
+  if(current_position_>size_){
+    XBT_DEBUG("Updating size of file %s from %llu to %lld", path_.c_str(), size_, position);
+    local_disk_->extension<FileSystemDiskExt>()->incr_used_size(current_position_-size_);
+    size_ = current_position_;
+
+    kernel::actor::simcall_answered([this] {
+    std::map<std::string, sg_size_t, std::less<>>* content = local_disk_->extension<FileSystemDiskExt>()->get_content();
+    content->erase(path_);
+    content->insert({path_, size_});
+  });
+  }
+}
+
 sg_size_t File::tell() const
 {
   return current_position_;
@@ -274,10 +277,9 @@ int File::unlink() const
     XBT_WARN("File %s is not on disk %s. Impossible to unlink", path_.c_str(), name);
     return -1;
   } else {
-    XBT_DEBUG("UNLINK %s on disk '%s'", path_.c_str(), name);
+    XBT_DEBUG("UNLINK %s of size %llu on disk '%s'", path_.c_str(), size_, name);
 
     local_disk_->extension<FileSystemDiskExt>()->decr_used_size(size_);
-
     // Remove the file from storage
     content->erase(path_);
 
@@ -416,28 +418,28 @@ static void on_platform_created()
 {
   for (auto const& host : simgrid::s4u::Engine::get_instance()->get_all_hosts()) {
     const char* remote_disk_str = host->get_property("remote_disk");
-    if (remote_disk_str) {
-      std::vector<std::string> tokens;
-      boost::split(tokens, remote_disk_str, boost::is_any_of(":"));
-      std::string mount_point         = tokens[0];
-      simgrid::s4u::Host* remote_host = simgrid::s4u::Host::by_name_or_null(tokens[2]);
-      xbt_assert(remote_host, "You're trying to access a host that does not exist. Please check your platform file");
-
-      const simgrid::s4u::Disk* disk = nullptr;
-      for (auto const& d : remote_host->get_disks())
-        if (d->get_name() == tokens[1]) {
-          disk = d;
-          break;
-        }
-
-      xbt_assert(disk, "You're trying to mount a disk that does not exist. Please check your platform file");
-      disk->extension<FileSystemDiskExt>()->add_remote_mount(remote_host, mount_point);
-      host->add_disk(disk);
-
-      XBT_DEBUG("Host '%s' wants to mount a remote disk: %s of %s mounted on %s", host->get_cname(), disk->get_cname(),
-                remote_host->get_cname(), mount_point.c_str());
-      XBT_DEBUG("Host '%s' now has %zu disks", host->get_cname(), host->get_disks().size());
-    }
+    if (not remote_disk_str)
+      continue;
+    std::vector<std::string> tokens;
+    boost::split(tokens, remote_disk_str, boost::is_any_of(":"));
+    std::string mount_point         = tokens[0];
+    simgrid::s4u::Host* remote_host = simgrid::s4u::Host::by_name_or_null(tokens[2]);
+    xbt_assert(remote_host, "You're trying to access a host that does not exist. Please check your platform file");
+
+    const simgrid::s4u::Disk* disk = nullptr;
+    for (auto const& d : remote_host->get_disks())
+      if (d->get_name() == tokens[1]) {
+        disk = d;
+        break;
+      }
+
+    xbt_assert(disk, "You're trying to mount a disk that does not exist. Please check your platform file");
+    disk->extension<FileSystemDiskExt>()->add_remote_mount(remote_host, mount_point);
+    host->add_disk(disk);
+
+    XBT_DEBUG("Host '%s' wants to mount a remote disk: %s of %s mounted on %s", host->get_cname(), disk->get_cname(),
+              remote_host->get_cname(), mount_point.c_str());
+    XBT_DEBUG("Host '%s' now has %zu disks", host->get_cname(), host->get_disks().size());
   }
 }
 
index 27c0cf2..56ebcbb 100644 (file)
@@ -66,7 +66,7 @@ public:
 
 xbt::Extension<s4u::Link, LinkLoad> LinkLoad::EXTENSION_ID;
 
-LinkLoad::LinkLoad(s4u::Link* ptr) : link_(ptr), is_tracked_(false)
+LinkLoad::LinkLoad(s4u::Link* ptr) : link_(ptr)
 {
   XBT_DEBUG("Instantiating a LinkLoad for link '%s'", link_->get_cname());
 }
index d1fe6f6..1dbfef1 100644 (file)
@@ -81,8 +81,8 @@ void Comm::send(kernel::actor::ActorImpl* sender, const Mailbox* mbox, double ta
     comm = simgrid::kernel::actor::simcall_answered(
         [&send_observer] { return simgrid::kernel::activity::CommImpl::isend(&send_observer); }, &send_observer);
 
-    simgrid::kernel::actor::ActivityWaitSimcall wait_observer{sender, comm.get(), timeout};
-    if (simgrid::kernel::actor::simcall_blocking(
+    if (simgrid::kernel::actor::ActivityWaitSimcall wait_observer{sender, comm.get(), timeout};
+        simgrid::kernel::actor::simcall_blocking(
             [&wait_observer] {
               wait_observer.get_activity()->wait_for(wait_observer.get_issuer(), wait_observer.get_timeout());
             },
@@ -124,8 +124,8 @@ void Comm::recv(kernel::actor::ActorImpl* receiver, const Mailbox* mbox, void* d
     comm = simgrid::kernel::actor::simcall_answered(
         [&observer] { return simgrid::kernel::activity::CommImpl::irecv(&observer); }, &observer);
 
-    simgrid::kernel::actor::ActivityWaitSimcall wait_observer{receiver, comm.get(), timeout};
-    if (simgrid::kernel::actor::simcall_blocking(
+    if (simgrid::kernel::actor::ActivityWaitSimcall wait_observer{receiver, comm.get(), timeout};
+        simgrid::kernel::actor::simcall_blocking(
             [&wait_observer] {
               wait_observer.get_activity()->wait_for(wait_observer.get_issuer(), wait_observer.get_timeout());
             },
index 259ed33..a0e9182 100644 (file)
@@ -158,6 +158,11 @@ unsigned int Exec::get_host_number() const
   return static_cast<kernel::activity::ExecImpl*>(pimpl_.get())->get_host_number();
 }
 
+int Exec::get_thread_count() const
+{
+  return static_cast<kernel::activity::ExecImpl*>(pimpl_.get())->get_thread_count();
+}
+
 /** @brief Change the host on which this activity takes place.
  *
  * The activity cannot be terminated already (but it may be started). */
index e60efa3..10d160a 100644 (file)
@@ -10,6 +10,7 @@
 #include <xbt/config.hpp>
 
 #include "simgrid/sg_config.hpp"
+#include "src/include/xbt/mmalloc.h"
 #include "src/instr/instr_private.hpp"
 #include "src/internal_config.h"
 #include "src/kernel/context/Context.hpp"
@@ -327,9 +328,17 @@ void sg_config_init(int *argc, char **argv)
   static simgrid::config::Flag<int> cfg_context_guard_size{
       "contexts/guard-size", "Guard size for contexts stacks in memory pages", default_guard_size,
       [](int value) { simgrid::kernel::context::guard_size = value * xbt_pagesize; }};
-  static simgrid::config::Flag<int> cfg_context_nthreads{"contexts/nthreads",
-                                                         "Number of parallel threads used to execute user contexts", 1,
-                                                         &simgrid::kernel::context::set_nthreads};
+
+  static simgrid::config::Flag<int> cfg_context_nthreads{
+      "contexts/nthreads", "Number of parallel threads used to execute user contexts", 1, [](int nthreads) {
+#if HAVE_MMALLOC
+        xbt_assert(
+            nthreads == 1 || !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::set_nthreads(nthreads);
+      }};
 
   /* synchronization mode for parallel user contexts */
 #if HAVE_FUTEX_H
index 7a2578a..0cd9600 100644 (file)
@@ -568,10 +568,8 @@ void mpi_op_commutative_(int* op, int* commute, int* ierr)
 
 void mpi_group_free_(int* group, int* ierr)
 {
-  if (MPI_Group tmp = simgrid::smpi::Group::f2c(*group); tmp != MPI_COMM_WORLD->group() && tmp != MPI_GROUP_EMPTY) {
-    simgrid::smpi::Group::unref(tmp);
-  }
-  *ierr = MPI_SUCCESS;
+  MPI_Group tmp = simgrid::smpi::Group::f2c(*group);
+  *ierr         = MPI_Group_free(&tmp);
 }
 
 void mpi_group_size_(int* group, int* size, int* ierr)
index 0144bc6..5db772d 100644 (file)
@@ -395,6 +395,10 @@ WRAPPED_PMPI_CALL_ERRHANDLER_FILE(int, MPI_File_set_errhandler,( MPI_File fh, MP
 WRAPPED_PMPI_CALL_ERRHANDLER_FILE(int, MPI_File_get_errhandler,( MPI_File fh, MPI_Errhandler *errhandler), (fh, errhandler))
 WRAPPED_PMPI_CALL_ERRHANDLER_FILE(int, MPI_File_set_view,(MPI_File fh, MPI_Offset disp, MPI_Datatype etype, MPI_Datatype filetype, const char *datarep, MPI_Info info), (fh, disp, etype, filetype, datarep, info))
 WRAPPED_PMPI_CALL_ERRHANDLER_FILE(int, MPI_File_get_view,(MPI_File fh, MPI_Offset *disp, MPI_Datatype *etype, MPI_Datatype *filetype, char *datarep), (fh, disp, etype, filetype, datarep))
+WRAPPED_PMPI_CALL_ERRHANDLER_FILE(int, MPI_File_get_type_extent,(MPI_File fh, MPI_Datatype datatype, MPI_Aint *extent), (fh, datatype, extent))
+WRAPPED_PMPI_CALL_ERRHANDLER_FILE(int, MPI_File_set_atomicity,(MPI_File fh, int flag), (fh, flag))
+WRAPPED_PMPI_CALL_ERRHANDLER_FILE(int, MPI_File_get_atomicity,(MPI_File fh, int *flag), (fh, flag))
+WRAPPED_PMPI_CALL_ERRHANDLER_FILE(int, MPI_File_get_byte_offset,(MPI_File fh, MPI_Offset offset, MPI_Offset *disp), (fh, offset, disp))
 /*
   Unimplemented Calls - both PMPI and MPI calls are generated.
   When implementing, please move ahead, swap UNIMPLEMENTED_WRAPPED_PMPI_CALL for WRAPPED_PMPI_CALL,
@@ -433,7 +437,6 @@ UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_iread,(MPI_File fh, void *buf, int
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_iwrite,(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Request *request), (fh, buf, count, datatype, request))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_iread_all,(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Request *request), (fh, buf, count, datatype, request))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_iwrite_all,(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Request *request), (fh, buf, count, datatype, request))
-UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_get_byte_offset,(MPI_File fh, MPI_Offset offset, MPI_Offset *disp), (fh, offset, disp))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_iread_shared,(MPI_File fh, void *buf, int count,MPI_Datatype datatype, MPI_Request *request), (fh, buf, count, datatype, request))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_iwrite_shared,(MPI_File fh, const void *buf, int count, MPI_Datatype datatype, MPI_Request *request), (fh, buf, count, datatype, request))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_read_at_all_begin,(MPI_File fh, MPI_Offset offset, void *buf, int count, MPI_Datatype datatype), (fh, offset, buf, count, datatype))
@@ -448,9 +451,6 @@ UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_read_ordered_begin,(MPI_File fh, v
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_read_ordered_end,(MPI_File fh, void *buf, MPI_Status *status), (fh, buf, status))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_write_ordered_begin,(MPI_File fh, const void *buf, int count, MPI_Datatype datatype), (fh, buf, count, datatype))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_write_ordered_end,(MPI_File fh, const void *buf, MPI_Status *status), (fh, buf, status))
-UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_get_type_extent,(MPI_File fh, MPI_Datatype datatype, MPI_Aint *extent), (fh, datatype, extent))
-UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_set_atomicity,(MPI_File fh, int flag), (fh, flag))
-UNIMPLEMENTED_WRAPPED_PMPI_CALL(int, MPI_File_get_atomicity,(MPI_File fh, int *flag), (fh, flag))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int,MPI_Get_elements,(MPI_Status* status, MPI_Datatype datatype, int* elements) ,(status, datatype, elements))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int,MPI_Get_elements_x,(MPI_Status* status, MPI_Datatype datatype, MPI_Count* elements) ,(status, datatype, elements))
 UNIMPLEMENTED_WRAPPED_PMPI_CALL(int,MPI_Graph_create,(MPI_Comm comm_old, int nnodes, const int* index, const int* edges, int reorder, MPI_Comm* comm_graph) ,(comm_old, nnodes, index, edges, reorder, comm_graph))
index e87680f..e8dfd51 100644 (file)
@@ -65,7 +65,7 @@ int PMPI_File_close(MPI_File *fh){
 int PMPI_File_seek(MPI_File fh, MPI_Offset offset, int whence){
   CHECK_FILE(1, fh)
   const SmpiBenchGuard suspend_bench;
-  int ret = fh->seek(offset,whence);
+  int ret = fh->seek(offset*fh->etype()->get_extent(),whence);
   return ret;
 }
 
@@ -73,7 +73,7 @@ int PMPI_File_seek_shared(MPI_File fh, MPI_Offset offset, int whence){
   CHECK_FILE(1, fh)
   CHECK_COLLECTIVE(fh->comm(), __func__)
   const SmpiBenchGuard suspend_bench;
-  int ret = fh->seek_shared(offset,whence);
+  int ret = fh->seek_shared(offset*fh->etype()->get_extent(),whence);
   return ret;
 }
 
@@ -200,9 +200,12 @@ int PMPI_File_read_at(MPI_File fh, MPI_Offset offset, void *buf, int count,MPI_D
   const SmpiBenchGuard suspend_bench;
   aid_t rank_traced = simgrid::s4u::this_actor::get_pid();
   TRACE_smpi_comm_in(rank_traced, __func__, new simgrid::instr::CpuTIData("IO - read", count * datatype->size()));
+  MPI_Offset prev;
+  fh->get_position(&prev);
   int ret = fh->seek(offset,MPI_SEEK_SET);
   if (ret == MPI_SUCCESS)
     ret = simgrid::smpi::File::read(fh, buf, count, datatype, status);
+  fh->seek(prev,MPI_SEEK_SET);
   TRACE_smpi_comm_out(rank_traced);
   return ret;
 }
@@ -215,9 +218,12 @@ int PMPI_File_read_at_all(MPI_File fh, MPI_Offset offset, void *buf, int count,M
   aid_t rank_traced = simgrid::s4u::this_actor::get_pid();
   TRACE_smpi_comm_in(rank_traced, __func__,
                      new simgrid::instr::CpuTIData("IO - read_at_all", count * datatype->size()));
+  MPI_Offset prev;
+  fh->get_position(&prev);
   int ret = fh->seek(offset,MPI_SEEK_SET);
   if (ret == MPI_SUCCESS)
     ret = fh->op_all<simgrid::smpi::File::read>(buf, count, datatype, status);
+  fh->seek(prev,MPI_SEEK_SET);
   TRACE_smpi_comm_out(rank_traced);
   return ret;
 }
@@ -229,9 +235,12 @@ int PMPI_File_write_at(MPI_File fh, MPI_Offset offset, const void *buf, int coun
   const SmpiBenchGuard suspend_bench;
   aid_t rank_traced = simgrid::s4u::this_actor::get_pid();
   TRACE_smpi_comm_in(rank_traced, __func__, new simgrid::instr::CpuTIData("IO - write", count * datatype->size()));
+  MPI_Offset prev;
+  fh->get_position(&prev);
   int ret = fh->seek(offset,MPI_SEEK_SET);
   if (ret == MPI_SUCCESS)
     ret = simgrid::smpi::File::write(fh, const_cast<void*>(buf), count, datatype, status);
+  fh->seek(prev,MPI_SEEK_SET);
   TRACE_smpi_comm_out(rank_traced);
   return ret;
 }
@@ -244,16 +253,18 @@ int PMPI_File_write_at_all(MPI_File fh, MPI_Offset offset, const void *buf, int
   aid_t rank_traced = simgrid::s4u::this_actor::get_pid();
   TRACE_smpi_comm_in(rank_traced, __func__,
                      new simgrid::instr::CpuTIData("IO - write_at_all", count * datatype->size()));
+  MPI_Offset prev;
+  fh->get_position(&prev);
   int ret = fh->seek(offset,MPI_SEEK_SET);
   if (ret == MPI_SUCCESS)
     ret = fh->op_all<simgrid::smpi::File::write>(const_cast<void*>(buf), count, datatype, status);
+  fh->seek(prev,MPI_SEEK_SET);
   TRACE_smpi_comm_out(rank_traced);
   return ret;
 }
 
 int PMPI_File_delete(const char *filename, MPI_Info info){
-  if (filename == nullptr)
-    return MPI_ERR_FILE;
+  CHECK_NULL(1, MPI_ERR_FILE, filename)
   const SmpiBenchGuard suspend_bench;
   int ret = simgrid::smpi::File::del(filename, info);
   return ret;
@@ -359,11 +370,37 @@ int PMPI_File_set_errhandler(MPI_File file, MPI_Errhandler errhandler){
 }
 
 int PMPI_File_call_errhandler(MPI_File file,int errorcode){
-  if (file == nullptr) {
-    return MPI_ERR_WIN;
-  }
+  CHECK_FILE(1, file)
   MPI_Errhandler err = file->errhandler();
   err->call(file, errorcode);
   simgrid::smpi::Errhandler::unref(err);
   return MPI_SUCCESS;
 }
+
+int PMPI_File_get_type_extent(MPI_File fh, MPI_Datatype
+    datatype, MPI_Aint *extent){
+  CHECK_FILE(1, fh)
+  CHECK_TYPE(2, datatype)
+  CHECK_NULL(3, MPI_ERR_OTHER, extent)
+  *extent = datatype->get_extent();
+  return MPI_SUCCESS;
+}
+
+int PMPI_File_set_atomicity(MPI_File fh, int a){
+  CHECK_FILE(1, fh)
+  fh->set_atomicity(a != 0);
+  return MPI_SUCCESS;
+}
+
+int PMPI_File_get_atomicity(MPI_File fh, int* a){
+  CHECK_FILE(1, fh)
+  *a = fh->get_atomicity();
+  return MPI_SUCCESS;
+}
+
+int PMPI_File_get_byte_offset(MPI_File fh, MPI_Offset offset, MPI_Offset *disp){
+  CHECK_FILE(1, fh)
+  CHECK_NULL(3, MPI_ERR_OTHER, disp)
+  *disp = offset * fh->etype()->get_extent();
+  return MPI_SUCCESS;
+}
index b79164b..60ab2fd 100644 (file)
@@ -14,7 +14,7 @@
 #include "smpi_info.hpp"
 #include  <algorithm>
 
-XBT_LOG_EXTERNAL_CATEGORY(smpi_pmpi);
+XBT_LOG_EXTERNAL_CATEGORY(smpi_io);
 
 namespace simgrid::smpi {
 class File : public F2C{
@@ -30,6 +30,8 @@ class File : public F2C{
   MPI_Datatype etype_;
   MPI_Datatype filetype_;
   std::string datarep_;
+  MPI_Offset disp_;
+  bool atomicity_;
 
   public:
   File(MPI_Comm comm, const char *filename, int amode, MPI_Info info);
@@ -40,6 +42,7 @@ class File : public F2C{
   int get_position(MPI_Offset* offset) const;
   int get_position_shared(MPI_Offset* offset) const;
   int flags() const;
+  MPI_Datatype etype() const;
   MPI_Comm comm() const;
   std::string name() const override {return file_ ? std::string("MPI_File: ")+ std::string(file_->get_path()): std::string("MPI_File");}
 
@@ -63,6 +66,8 @@ class File : public F2C{
   static int del(const char* filename, const Info* info);
   MPI_Errhandler errhandler();
   void set_errhandler( MPI_Errhandler errhandler);
+  void set_atomicity(bool a);
+  bool get_atomicity() const;
   static File* f2c(int id);
 };
 
@@ -102,24 +107,27 @@ int File::op_all(void* buf, int count, const Datatype* datatype, MPI_Status* sta
       max = max_offsets[i];
   }
 
-  XBT_CDEBUG(smpi_pmpi, "my offsets to read : %lld:%lld, global min and max %lld:%lld", min_offset, max_offset, min,
+  XBT_CDEBUG(smpi_io, "my offsets to read : %lld:%lld, global min and max %lld:%lld", min_offset, max_offset, min,
              max);
   if (empty == 1) {
     if (status != MPI_STATUS_IGNORE)
       status->count = 0;
     return MPI_SUCCESS;
   }
-  if (max - min == tot && (datatype->flags() & DT_FLAG_CONTIGUOUS)) {
+  XBT_CDEBUG(smpi_io, "min:max : %lld:%lld, tot %lld contig %u", min, max, tot, (datatype->flags() & DT_FLAG_CONTIGUOUS));
+  if ( size==1 || (max - min == tot && (datatype->flags() & DT_FLAG_CONTIGUOUS))) {
     // contiguous. Just have each proc perform its read
     if (status != MPI_STATUS_IGNORE)
       status->count = count * datatype->size();
-    return T(this, buf, count, datatype, status);
+    int ret = T(this, buf, count, datatype, status);
+    seek(max_offset, MPI_SEEK_SET);
+    return ret;
   }
 
   // Interleaved case : How much do I need to read, and whom to send it ?
-  MPI_Offset my_chunk_start = (max - min + 1) / size * rank;
-  MPI_Offset my_chunk_end   = ((max - min + 1) / size * (rank + 1));
-  XBT_CDEBUG(smpi_pmpi, "my chunks to read : %lld:%lld", my_chunk_start, my_chunk_end);
+  MPI_Offset my_chunk_start = min + (max - min + 1) / size * rank;
+  MPI_Offset my_chunk_end   = min + ((max - min + 1) / size * (rank + 1)) +1;
+  XBT_CDEBUG(smpi_io, "my chunks to read : %lld:%lld", my_chunk_start, my_chunk_end);
   std::vector<int> send_sizes(size);
   std::vector<int> recv_sizes(size);
   std::vector<int> send_disps(size);
@@ -130,11 +138,14 @@ int File::op_all(void* buf, int count, const Datatype* datatype, MPI_Status* sta
     send_disps[i] = 0; // cheat to avoid issues when send>recv as we use recv buffer
     if ((my_chunk_start >= min_offsets[i] && my_chunk_start < max_offsets[i]) ||
         ((my_chunk_end <= max_offsets[i]) && my_chunk_end > min_offsets[i])) {
-      send_sizes[i] = (std::min(max_offsets[i] - 1, my_chunk_end - 1) - std::max(min_offsets[i], my_chunk_start));
+      send_sizes[i] = (std::min(max_offsets[i], my_chunk_end) - std::max(min_offsets[i], my_chunk_start));
+      //we want to send only useful data, so let's pretend we pack it
+      send_sizes[i]=send_sizes[i]/datatype->get_extent()*datatype->size();
       // store min and max offset to actually read
+  
       min_offset = std::min(min_offset, min_offsets[i]);
       total_sent += send_sizes[i];
-      XBT_CDEBUG(smpi_pmpi, "will have to send %d bytes to %d", send_sizes[i], i);
+      XBT_CDEBUG(smpi_io, "will have to send %d bytes to %d", send_sizes[i], i);
     }
   }
   min_offset = std::max(min_offset, my_chunk_start);
@@ -169,15 +180,16 @@ int File::op_all(void* buf, int count, const Datatype* datatype, MPI_Status* sta
     else if (chunk_start > my_chunk_end)
       continue;
     else
-      totreads += (std::min(chunk_end, my_chunk_end - 1) - std::max(chunk_start, my_chunk_start));
+      totreads += (std::min(chunk_end, my_chunk_end) - std::max(chunk_start, my_chunk_start));
   }
-  XBT_CDEBUG(smpi_pmpi, "will have to access %lld from my chunk", totreads);
+  XBT_CDEBUG(smpi_io, "will have to access %lld from my chunk", totreads);
 
   unsigned char* sendbuf = smpi_get_tmp_sendbuffer(total_sent);
 
   if (totreads > 0) {
     seek(min_offset, MPI_SEEK_SET);
-    T(this, sendbuf, totreads / datatype->size(), datatype, status);
+    T(this, sendbuf, totreads / datatype->get_extent(), datatype, status);
+    seek(max_offset, MPI_SEEK_SET);
   }
   simgrid::smpi::colls::alltoall(send_sizes.data(), 1, MPI_INT, recv_sizes.data(), 1, MPI_INT, comm_);
   int total_recv = 0;
index 1f00a19..d831ae9 100644 (file)
@@ -58,11 +58,11 @@ public:
   void parse(xbt::ReplayAction& action, const std::string& name) override;
 };
 
-class SendRecvParser : public ActionArgParser {
+class SendOrRecvParser : public ActionArgParser {
 public:
   /* communication partner; if we send, this is the receiver and vice versa */
   int partner;
-  size_t size;
+  ssize_t size;
   int tag;
   MPI_Datatype datatype1;
 
@@ -103,6 +103,18 @@ public:
   MPI_Datatype datatype2;
 };
 
+class SendRecvParser : public ActionArgParser {
+public:
+  int dst;
+  int src;
+  int sendcount;
+  int recvcount;
+  MPI_Datatype datatype1;
+  MPI_Datatype datatype2;
+
+  void parse(xbt::ReplayAction& action, const std::string& name) override;
+};
+
 class BcastArgParser : public CollCommParser {
 public:
   void parse(xbt::ReplayAction& action, const std::string& name) override;
@@ -185,7 +197,7 @@ public:
 template <class T> class ReplayAction {
   const std::string name_;
   const aid_t my_proc_id_ = s4u::this_actor::get_pid();
-  T args_;
+  T args_{};
 
 protected:
   const std::string& get_name() const { return name_; }
@@ -219,7 +231,7 @@ public:
   void kernel(xbt::ReplayAction& action) override;
 };
 
-class SendAction : public ReplayAction<SendRecvParser> {
+class SendAction : public ReplayAction<SendOrRecvParser> {
   RequestStorage& req_storage;
 
 public:
@@ -227,7 +239,7 @@ public:
   void kernel(xbt::ReplayAction& action) override;
 };
 
-class RecvAction : public ReplayAction<SendRecvParser> {
+class RecvAction : public ReplayAction<SendOrRecvParser> {
   RequestStorage& req_storage;
 
 public:
@@ -282,6 +294,12 @@ public:
   void kernel(xbt::ReplayAction& action) override;
 };
 
+class SendRecvAction : public ReplayAction<SendRecvParser> {
+public:
+  explicit SendRecvAction() : ReplayAction("sendrecv") {}
+  void kernel(xbt::ReplayAction& action) override;
+};
+
 class BarrierAction : public ReplayAction<ActionArgParser> {
 public:
   explicit BarrierAction() : ReplayAction("barrier") {}
index f4687af..e398719 100644 (file)
@@ -483,3 +483,7 @@ int smpi_getopt (int argc,  char *const *argv,  const char *options)
     smpi_process()->set_optind(optind);
   return ret;
 }
+
+pid_t smpi_getpid(){
+  return static_cast<pid_t>(simgrid::s4u::this_actor::get_pid());
+}
index acd32c6..a0c13a9 100644 (file)
@@ -2,6 +2,25 @@
 
 /* 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. */
+
+#if defined(_GNU_SOURCE)
+  #define DEFINED_GNUSOURCE 1
+#else
+  #define _GNU_SOURCE
+#endif
+
+#if defined(__linux__)
+  #include <features.h>
+//inspired by https://stackoverflow.com/a/70211227
+  #if not defined(__USE_GNU)
+    #define __MUSL__
+  #endif
+#endif
+
+#ifndef DEFINED_GNUSOURCE
+  #undef _GNU_SOURCE
+#endif
+
 #include "smpi_config.hpp"
 #include "include/xbt/config.hpp"
 #include "mc/mc.h"
@@ -23,8 +42,9 @@
 # ifndef MAC_OS_X_VERSION_10_12
 #   define MAC_OS_X_VERSION_10_12 101200
 # endif
+
 constexpr bool HAVE_WORKING_MMAP = (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12);
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__sun) || defined(__HAIKU__)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__sun) || defined(__HAIKU__) || defined(__MUSL__)
 constexpr bool HAVE_WORKING_MMAP = false;
 #else
 constexpr bool HAVE_WORKING_MMAP = true;
index 218f14d..8c6a3a5 100644 (file)
@@ -162,12 +162,12 @@ void WaitTestParser::parse(simgrid::xbt::ReplayAction& action, const std::string
   tag = std::stoi(action[4]);
 }
 
-void SendRecvParser::parse(simgrid::xbt::ReplayAction& action, const std::string&)
+void SendOrRecvParser::parse(simgrid::xbt::ReplayAction& action, const std::string&)
 {
   CHECK_ACTION_PARAMS(action, 3, 1)
   partner = std::stoi(action[2]);
   tag     = std::stoi(action[3]);
-  size      = parse_integer<size_t>(action[4]);
+  size      = parse_integer<ssize_t>(action[4]);
   datatype1 = parse_datatype(action, 5);
 }
 
@@ -190,6 +190,17 @@ void LocationParser::parse(simgrid::xbt::ReplayAction& action, const std::string
   line = std::stoi(action[3]);
 }
 
+void SendRecvParser::parse(simgrid::xbt::ReplayAction& action, const std::string&)
+{
+  CHECK_ACTION_PARAMS(action, 6, 0)
+  sendcount = parse_integer<int>(action[2]);
+  dst = std::stoi(action[3]);
+  recvcount = parse_integer<int>(action[4]);
+  src = std::stoi(action[5]);
+  datatype1 = parse_datatype(action, 6);
+  datatype2 = parse_datatype(action, 7);
+}
+
 void BcastArgParser::parse(simgrid::xbt::ReplayAction& action, const std::string&)
 {
   CHECK_ACTION_PARAMS(action, 1, 2)
@@ -445,7 +456,7 @@ void WaitAction::kernel(simgrid::xbt::ReplayAction& action)
 
 void SendAction::kernel(simgrid::xbt::ReplayAction&)
 {
-  const SendRecvParser& args = get_args();
+  const SendOrRecvParser& args = get_args();
   aid_t dst_traced           = MPI_COMM_WORLD->group()->actor(args.partner);
 
   TRACE_smpi_comm_in(
@@ -468,15 +479,15 @@ void SendAction::kernel(simgrid::xbt::ReplayAction&)
 
 void RecvAction::kernel(simgrid::xbt::ReplayAction&)
 {
-  const SendRecvParser& args = get_args();
+  const SendOrRecvParser& args = get_args();
   TRACE_smpi_comm_in(
       get_pid(), __func__,
       new simgrid::instr::Pt2PtTIData(get_name(), args.partner, args.size, args.tag, Datatype::encode(args.datatype1)));
 
   MPI_Status status;
   // unknown size from the receiver point of view
-  size_t arg_size = args.size;
-  if (arg_size == 0) {
+  ssize_t arg_size = args.size;
+  if (arg_size < 0) {
     Request::probe(args.partner, args.tag, MPI_COMM_WORLD, &status);
     arg_size = status.count;
   }
@@ -499,6 +510,39 @@ void RecvAction::kernel(simgrid::xbt::ReplayAction&)
   }
 }
 
+void SendRecvAction::kernel(simgrid::xbt::ReplayAction&)
+{
+  XBT_DEBUG("Enters SendRecv");
+  const SendRecvParser& args = get_args();
+  aid_t my_proc_id = simgrid::s4u::this_actor::get_pid();
+  aid_t src_traced = MPI_COMM_WORLD->group()->actor(args.src);
+  aid_t dst_traced = MPI_COMM_WORLD->group()->actor(args.dst);
+
+  MPI_Status status;
+  int sendtag=0;
+  int recvtag=0;
+
+  // FIXME: Hack the way to trace this one
+  auto dst_hack = std::make_shared<std::vector<int>>();
+  auto src_hack = std::make_shared<std::vector<int>>();
+  dst_hack->push_back(dst_traced);
+  src_hack->push_back(src_traced);
+  TRACE_smpi_comm_in(my_proc_id, __func__,
+                       new simgrid::instr::VarCollTIData(
+                           "sendRecv", -1, args.sendcount,
+                        dst_hack, args.recvcount, src_hack,
+                           simgrid::smpi::Datatype::encode(args.datatype1), simgrid::smpi::Datatype::encode(args.datatype2)));
+
+  TRACE_smpi_send(my_proc_id, my_proc_id, dst_traced, sendtag, args.sendcount * args.datatype1->size());
+
+  simgrid::smpi::Request::sendrecv(nullptr, args.sendcount, args.datatype1, args.dst, sendtag, nullptr, args.recvcount, args.datatype2, args.src,
+                                     recvtag, MPI_COMM_WORLD, &status);
+
+  TRACE_smpi_recv(src_traced, my_proc_id, recvtag);
+  TRACE_smpi_comm_out(my_proc_id);
+  XBT_DEBUG("Exits SendRecv");
+}
+
 void ComputeAction::kernel(simgrid::xbt::ReplayAction&)
 {
   const ComputeParser& args = get_args();
@@ -824,6 +868,7 @@ void smpi_replay_init(const char* instance_id, int rank, double start_delay_flop
   xbt_replay_action_register("recv",  [](simgrid::xbt::ReplayAction& action) { simgrid::smpi::replay::RecvAction("recv", storage[simgrid::s4u::this_actor::get_pid()]).execute(action); });
   xbt_replay_action_register("irecv", [](simgrid::xbt::ReplayAction& action) { simgrid::smpi::replay::RecvAction("irecv", storage[simgrid::s4u::this_actor::get_pid()]).execute(action); });
   xbt_replay_action_register("test",  [](simgrid::xbt::ReplayAction& action) { simgrid::smpi::replay::TestAction(storage[simgrid::s4u::this_actor::get_pid()]).execute(action); });
+  xbt_replay_action_register("sendRecv", [](simgrid::xbt::ReplayAction& action) { simgrid::smpi::replay::SendRecvAction().execute(action); });
   xbt_replay_action_register("wait",  [](simgrid::xbt::ReplayAction& action) { simgrid::smpi::replay::WaitAction(storage[simgrid::s4u::this_actor::get_pid()]).execute(action); });
   xbt_replay_action_register("waitall", [](simgrid::xbt::ReplayAction& action) { simgrid::smpi::replay::WaitAllAction(storage[simgrid::s4u::this_actor::get_pid()]).execute(action); });
   xbt_replay_action_register("barrier", [](simgrid::xbt::ReplayAction& action) { simgrid::smpi::replay::BarrierAction().execute(action); });
index b832510..2b77328 100644 (file)
@@ -49,9 +49,12 @@ File::File(MPI_Comm comm, const char* filename, int amode, MPI_Info info) : comm
       fullname.insert(0, mount);
     }
   }
-
+  XBT_DEBUG("Opening %s", fullname.c_str());
   file_ = simgrid::s4u::File::open(fullname, nullptr);
   list_ = nullptr;
+  disp_ = 0;
+  etype_ = MPI_BYTE;
+  atomicity_ = true;
   if (comm_->rank() == 0) {
     int size    = comm_->size() + FP_SIZE;
     list_       = new char[size];
@@ -108,14 +111,14 @@ int File::del(const char* filename, const Info*)
 
 int File::get_position(MPI_Offset* offset) const
 {
-  *offset = file_->tell();
+  *offset = file_->tell()/etype_->get_extent();
   return MPI_SUCCESS;
 }
 
 int File::get_position_shared(MPI_Offset* offset) const
 {
   shared_mutex_->lock();
-  *offset = *shared_file_pointer_;
+  *offset = *shared_file_pointer_/etype_->get_extent();
   shared_mutex_->unlock();
   return MPI_SUCCESS;
 }
@@ -156,9 +159,9 @@ int File::read(MPI_File fh, void* /*buf*/, int count, const Datatype* datatype,
   MPI_Offset position = fh->file_->tell();
   MPI_Offset movesize = datatype->get_extent() * count;
   MPI_Offset readsize = datatype->size() * count;
-  XBT_DEBUG("Position before read in MPI_File %s : %llu", fh->file_->get_path(), fh->file_->tell());
+  XBT_DEBUG("Position before read in MPI_File %s : %llu, size %llu", fh->file_->get_path(), fh->file_->tell(), fh->file_->size());
   MPI_Offset read = fh->file_->read(readsize);
-  XBT_VERB("Read in MPI_File %s, %lld bytes read, readsize %lld bytes, movesize %lld", fh->file_->get_path(), read,
+  XBT_VERB("Read in MPI_File %s, %lld bytes read, count %d, readsize %lld bytes, movesize %lld", fh->file_->get_path(), read, count,
            readsize, movesize);
   if (readsize != movesize) {
     fh->file_->seek(position + movesize, SEEK_SET);
@@ -186,6 +189,7 @@ int File::read_shared(MPI_File fh, void* buf, int count, const Datatype* datatyp
   read(fh, buf, count, datatype, status);
   *(fh->shared_file_pointer_) = fh->file_->tell();
   fh->shared_mutex_->unlock();
+  fh->seek(*(fh->shared_file_pointer_), MPI_SEEK_SET);
   return MPI_SUCCESS;
 }
 
@@ -201,6 +205,8 @@ int File::read_ordered(MPI_File fh, void* buf, int count, const Datatype* dataty
 
   MPI_Offset result;
   simgrid::smpi::colls::scan(&val, &result, 1, MPI_OFFSET, MPI_SUM, fh->comm_);
+  MPI_Offset prev;
+  fh->get_position(&prev);
   fh->seek(result, MPI_SEEK_SET);
   int ret = fh->op_all<simgrid::smpi::File::read>(buf, count, datatype, status);
   if (fh->comm_->rank() == fh->comm_->size() - 1) {
@@ -210,6 +216,7 @@ int File::read_ordered(MPI_File fh, void* buf, int count, const Datatype* dataty
   }
   char c;
   simgrid::smpi::colls::bcast(&c, 1, MPI_BYTE, fh->comm_->size() - 1, fh->comm_);
+  fh->seek(prev, MPI_SEEK_SET);
   return ret;
 }
 
@@ -219,10 +226,10 @@ int File::write(MPI_File fh, void* /*buf*/, int count, const Datatype* datatype,
   MPI_Offset position  = fh->file_->tell();
   MPI_Offset movesize  = datatype->get_extent() * count;
   MPI_Offset writesize = datatype->size() * count;
-  XBT_DEBUG("Position before write in MPI_File %s : %llu", fh->file_->get_path(), fh->file_->tell());
+  XBT_DEBUG("Position before write in MPI_File %s : %llu, size %llu", fh->file_->get_path(), fh->file_->tell(), fh->file_->size());
   MPI_Offset write = fh->file_->write(writesize, true);
-  XBT_VERB("Write in MPI_File %s, %lld bytes written, readsize %lld bytes, movesize %lld", fh->file_->get_path(), write,
-           writesize, movesize);
+  XBT_VERB("Write in MPI_File %s, %lld bytes written, count %d, writesize %lld bytes, movesize %lld", fh->file_->get_path(), write,
+           count, writesize, movesize);
   if (writesize != movesize) {
     fh->file_->seek(position + movesize, SEEK_SET);
   }
@@ -240,6 +247,7 @@ int File::write_shared(MPI_File fh, const void* buf, int count, const Datatype*
   write(fh, const_cast<void*>(buf), count, datatype, status);
   *(fh->shared_file_pointer_) = fh->file_->tell();
   XBT_DEBUG("Write shared on %s - Shared ptr after : %lld", fh->file_->get_path(), *(fh->shared_file_pointer_));
+  fh->seek(*(fh->shared_file_pointer_), MPI_SEEK_SET);
   fh->shared_mutex_->unlock();
   return MPI_SUCCESS;
 }
@@ -255,6 +263,8 @@ int File::write_ordered(MPI_File fh, const void* buf, int count, const Datatype*
   }
   MPI_Offset result;
   simgrid::smpi::colls::scan(&val, &result, 1, MPI_OFFSET, MPI_SUM, fh->comm_);
+  MPI_Offset prev;
+  fh->get_position(&prev);
   fh->seek(result, MPI_SEEK_SET);
   int ret = fh->op_all<simgrid::smpi::File::write>(const_cast<void*>(buf), count, datatype, status);
   if (fh->comm_->rank() == fh->comm_->size() - 1) {
@@ -264,20 +274,29 @@ int File::write_ordered(MPI_File fh, const void* buf, int count, const Datatype*
   }
   char c;
   simgrid::smpi::colls::bcast(&c, 1, MPI_BYTE, fh->comm_->size() - 1, fh->comm_);
+  fh->seek(prev, MPI_SEEK_SET);
   return ret;
 }
 
-int File::set_view(MPI_Offset /*disp*/, MPI_Datatype etype, MPI_Datatype filetype, const char* datarep, const Info*)
+int File::set_view(MPI_Offset disp, MPI_Datatype etype, MPI_Datatype filetype, const char* datarep, const Info*)
 {
   etype_    = etype;
   filetype_ = filetype;
   datarep_  = std::string(datarep);
-  seek_shared(0, MPI_SEEK_SET);
+  disp_     = disp;
+  if (comm_->rank() == 0){
+    if(disp != MPI_DISPLACEMENT_CURRENT)
+      seek_shared(disp, MPI_SEEK_SET);
+    else
+      seek_shared(0, MPI_SEEK_CUR);
+  }
+  sync();
   return MPI_SUCCESS;
 }
 
-int File::get_view(MPI_Offset* /*disp*/, MPI_Datatype* etype, MPI_Datatype* filetype, char* datarep) const
+int File::get_view(MPI_Offset* disp, MPI_Datatype* etype, MPI_Datatype* filetype, char* datarep) const
 {
+  *disp     = disp_;
   *etype    = etype_;
   *filetype = filetype_;
   snprintf(datarep, MPI_MAX_NAME_STRING + 1, "%s", datarep_.c_str());
@@ -299,6 +318,11 @@ int File::flags() const
   return flags_;
 }
 
+MPI_Datatype File::etype() const
+{
+  return etype_;
+}
+
 int File::sync()
 {
   // no idea
@@ -344,4 +368,14 @@ File* File::f2c(int id)
 {
   return static_cast<File*>(F2C::f2c(id));
 }
+
+void File::set_atomicity(bool a){
+  atomicity_ = a;
+}
+
+bool File::get_atomicity() const
+{
+  return atomicity_;
+}
+
 } // namespace simgrid::smpi
index 0ceb1a3..723be24 100644 (file)
@@ -1291,8 +1291,6 @@ void Request::free_f(int id)
 
 int Request::get_status(const Request* req, int* flag, MPI_Status* status)
 {
-  *flag=0;
-
   if(req != MPI_REQUEST_NULL && req->action_ != nullptr) {
     req->iprobe(req->comm_->group()->rank(req->src_), req->tag_, req->comm_, flag, status);
     if(*flag)
index 6463ec8..0c16eeb 100755 (executable)
@@ -29,7 +29,6 @@ if [ "x@WIN32@" = "x1" ]; then
     list_add CFLAGS "-include" "@includedir@/smpi/smpi_main.h"
     list_add LINKARGS "@libdir@\libsimgrid.dll"
 elif [ "x@APPLE@" = "x1" ]; then
-    list_add CFLAGS "-fPIC"
     if [ "x${SMPI_PRETEND_CC}" = "x" ]; then
        list_add CFLAGS "-include" "@includedir@/smpi/smpi_helpers.h"
        list_add LINKARGS "-shared"
@@ -40,7 +39,6 @@ elif [ "x@APPLE@" = "x1" ]; then
       list_add LINKARGS "-lsimgrid" "-lm" ${LINKER_UNDEFINED_ERROR:+"-Wl,-undefined,error"}
     fi
 else
-    list_add CFLAGS "-fPIC"
     if [ "x${SMPI_PRETEND_CC}" = "x" ]; then
        list_add CFLAGS "-include" "@includedir@/smpi/smpi_helpers.h"
        list_add LINKARGS "-shared"
@@ -78,7 +76,7 @@ while [ $# -gt 0 ]; do
             exit 0
             ;;
         '-trace-call-location')
-            list_add_not_empty CMDARGS "-DTRACE_CALL_LOCATION"
+            list_add CMDARGS "-DTRACE_CALL_LOCATION"
             ;;
         '-compiler-version' | '--compiler-version')
             ${CC} --version
@@ -93,6 +91,10 @@ while [ $# -gt 0 ]; do
     esac
 done
 
+if [ "x@WIN32@" != "x1" ]; then
+    list_add CMDARGS "-fPIC"
+fi
+
 list_set CMDLINE "${CC}"
 list_add_not_empty CMDLINE "${CFLAGS}"
 list_add_not_empty CMDLINE "${INCLUDEARGS}"
index 944870c..c88cae1 100755 (executable)
@@ -29,7 +29,6 @@ if [ "x@WIN32@" = "x1" ]; then
     list_add CXXFLAGS "-include" "@includedir@/smpi/smpi_main.h"
     list_add LINKARGS "@libdir@\libsimgrid.dll"
 elif [ "x@APPLE@" = "x1" ]; then
-    list_add CXXFLAGS "-fPIC"
     if [ "x${SMPI_PRETEND_CC}" = "x" ]; then
        list_add CXXFLAGS "-include" "@includedir@/smpi/smpi_helpers.h"
        list_add LINKARGS "-shared"
@@ -40,7 +39,6 @@ elif [ "x@APPLE@" = "x1" ]; then
       list_add LINKARGS "-lsimgrid" "-lm" ${LINKER_UNDEFINED_ERROR:+"-Wl,-undefined,error"}
     fi
 else
-    list_add CXXFLAGS "-fPIC"
     if [ "x${SMPI_PRETEND_CC}" = "x" ]; then
        list_add CXXFLAGS "-include" "@includedir@/smpi/smpi_helpers.h"
        list_add LINKARGS "-shared"
@@ -90,6 +88,10 @@ while [ $# -gt 0 ]; do
   esac
 done
 
+if [ "x@WIN32@" != "x1" ]; then
+    list_add CMDARGS "-fPIC"
+fi
+
 list_set CMDLINE "${CXX}"
 list_add_not_empty CMDLINE "${CXXFLAGS}"
 list_add_not_empty CMDLINE "${INCLUDEARGS}"
index a5e8ccf..805fe0f 100644 (file)
@@ -128,7 +128,7 @@ while [ $# -gt 0 ]; do
             TRACE_CALL_LOCATION=1
             # This should be list_add FFLAGS but it's not possible
             # anymore: FFLAGS was already moved into CMDLINE above.
-            list_add_not_empty CMDLINE "-ffixed-line-length-none" "-cpp"
+            list_add CMDLINE "-ffixed-line-length-none" "-cpp"
             ;;
         -o)
             list_add CMDLINE "-o$1"
index 24213e0..a52fec8 100644 (file)
@@ -1,12 +1,13 @@
 /* SimGrid's pthread interposer. Redefinition of the pthread symbols (see the comment in sthread.h) */
 
 #define _GNU_SOURCE
-#include "src/internal_config.h"
 #include "src/sthread/sthread.h"
+#include "src/internal_config.h"
 #include <dlfcn.h>
 #include <pthread.h>
 #include <semaphore.h>
 #include <stdio.h>
+#include <unistd.h>
 
 #if HAVE_VALGRIND_H
 #include <stdlib.h>
@@ -21,10 +22,16 @@ static int (*raw_mutex_lock)(pthread_mutex_t*)                             = NUL
 static int (*raw_mutex_trylock)(pthread_mutex_t*)                          = NULL;
 static int (*raw_mutex_unlock)(pthread_mutex_t*)                           = NULL;
 static int (*raw_mutex_destroy)(pthread_mutex_t*)                          = NULL;
+
+static unsigned int (*raw_sleep)(unsigned int)         = NULL;
+static int (*raw_usleep)(useconds_t)                   = NULL;
+static int (*raw_gettimeofday)(struct timeval*, void*) = NULL;
+
 static sem_t* (*raw_sem_open)(const char*, int)                            = NULL;
 static int (*raw_sem_init)(sem_t*, int, unsigned int)                      = NULL;
 static int (*raw_sem_wait)(sem_t*)                                         = NULL;
 static int (*raw_sem_post)(sem_t*)                                         = NULL;
+
 static void intercepter_init()
 {
   raw_pthread_create = (typeof(raw_pthread_create))dlsym(RTLD_NEXT, "pthread_create");
@@ -35,6 +42,10 @@ static void intercepter_init()
   raw_mutex_unlock  = (int (*)(pthread_mutex_t*))dlsym(RTLD_NEXT, "pthread_mutex_unlock");
   raw_mutex_destroy = (int (*)(pthread_mutex_t*))dlsym(RTLD_NEXT, "pthread_mutex_destroy");
 
+  raw_sleep        = (unsigned int (*)(unsigned int))dlsym(RTLD_NEXT, "sleep");
+  raw_usleep       = (int (*)(useconds_t usec))dlsym(RTLD_NEXT, "usleep");
+  raw_gettimeofday = (int (*)(struct timeval*, void*))dlsym(RTLD_NEXT, "gettimeofday");
+
   raw_sem_open = (sem_t * (*)(const char*, int)) dlsym(RTLD_NEXT, "sem_open");
   raw_sem_init = (int (*)(sem_t*, int, unsigned int))dlsym(RTLD_NEXT, "sem_init");
   raw_sem_wait = (int (*)(sem_t*))dlsym(RTLD_NEXT, "sem_wait");
@@ -59,7 +70,7 @@ int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_
     return raw_pthread_create(thread, attr, start_routine, arg);
 
   sthread_inside_simgrid = 1;
-  int res                = sthread_create(thread, attr, start_routine, arg);
+  int res                = sthread_create((sthread_t*)thread, attr, start_routine, arg);
   sthread_inside_simgrid = 0;
   return res;
 }
@@ -72,7 +83,7 @@ int pthread_join(pthread_t thread, void** retval)
     return raw_pthread_join(thread, retval);
 
   sthread_inside_simgrid = 1;
-  int res                = sthread_join(thread, retval);
+  int res                = sthread_join((sthread_t)thread, retval);
   sthread_inside_simgrid = 0;
   return res;
 }
@@ -146,6 +157,59 @@ int pthread_mutex_destroy(pthread_mutex_t* mutex)
   return res;
 }
 
+/* Glibc < 2.31 uses type "struct timezone *" for the second parameter of gettimeofday.
+   Other implementations use "void *" instead. */
+#ifdef __GLIBC__
+#if !__GLIBC_PREREQ(2, 31)
+#define TIMEZONE_TYPE struct timezone
+#endif
+#endif
+#ifndef TIMEZONE_TYPE
+#define TIMEZONE_TYPE void
+#endif
+
+int gettimeofday(struct timeval* tv, XBT_ATTRIB_UNUSED TIMEZONE_TYPE* tz)
+{
+  if (raw_gettimeofday == NULL)
+    intercepter_init();
+
+  if (sthread_inside_simgrid)
+    return raw_gettimeofday(tv, tz);
+
+  sthread_inside_simgrid = 1;
+  int res                = sthread_gettimeofday(tv);
+  sthread_inside_simgrid = 0;
+  return res;
+}
+
+unsigned int sleep(unsigned int seconds)
+{
+  if (raw_sleep == NULL)
+    intercepter_init();
+
+  if (sthread_inside_simgrid)
+    return raw_sleep(seconds);
+
+  sthread_inside_simgrid = 1;
+  sthread_sleep(seconds);
+  sthread_inside_simgrid = 0;
+  return 0;
+}
+
+int usleep(useconds_t usec)
+{
+  if (raw_usleep == NULL)
+    intercepter_init();
+
+  if (sthread_inside_simgrid)
+    return raw_usleep(usec);
+
+  sthread_inside_simgrid = 1;
+  sthread_sleep(((double)usec) / 1000000.);
+  sthread_inside_simgrid = 0;
+  return 0;
+}
+
 #if 0
 int sem_init(sem_t *sem, int pshared, unsigned int value) {
        int res;
@@ -165,11 +229,6 @@ int sem_post(sem_t *sem) {
        return raw_sem_post(sem);
 }
 
-int pthread_join(pthread_t thread, void **retval) {
-       sg_actor_join(thread, -1);
-    return 0;
-}
-
 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr) {
     *cond = sg_cond_init();
     return 0;
index 9bc6c50..e13357b 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef SIMGRID_STHREAD_H
 #define SIMGRID_STHREAD_H
 
+#include <sys/time.h>
+
 #if defined(__ELF__)
 #define XBT_PUBLIC __attribute__((visibility("default")))
 #else
@@ -38,8 +40,11 @@ int sthread_mutex_trylock(sthread_mutex_t* mutex);
 int sthread_mutex_unlock(sthread_mutex_t* mutex);
 int sthread_mutex_destroy(sthread_mutex_t* mutex);
 
+int sthread_gettimeofday(struct timeval* tv);
+void sthread_sleep(double seconds);
+
 #if defined(__cplusplus)
 }
 #endif
 
-#endif
\ No newline at end of file
+#endif
index d1a88a7..7721982 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/internal_config.h"
 #include "src/sthread/sthread.h"
 
+#include <cmath>
 #include <dlfcn.h>
 #include <pthread.h>
 #include <semaphore.h>
@@ -129,6 +130,23 @@ int sthread_mutex_destroy(sthread_mutex_t* mutex)
   return 0;
 }
 
+int sthread_gettimeofday(struct timeval* tv)
+{
+  if (tv) {
+    double now   = simgrid::s4u::Engine::get_clock();
+    double secs  = trunc(now);
+    double usecs = (now - secs) * 1e6;
+    tv->tv_sec   = static_cast<time_t>(secs);
+    tv->tv_usec  = static_cast<decltype(tv->tv_usec)>(usecs); // suseconds_t (or useconds_t on WIN32)
+  }
+  return 0;
+}
+
+void sthread_sleep(double seconds)
+{
+  simgrid::s4u::this_actor::sleep_for(seconds);
+}
+
 #if 0
 int sem_init(sem_t *sem, int pshared, unsigned int value) {
        int res;
@@ -148,11 +166,6 @@ int sem_post(sem_t *sem) {
        return raw_sem_post(sem);
 }
 
-int pthread_join(pthread_t thread, void **retval) {
-       sg_actor_join(thread, -1);
-    return 0;
-}
-
 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr) {
     *cond = sg_cond_init();
     return 0;
index 82b2f92..d646288 100644 (file)
@@ -159,11 +159,12 @@ s4u::VirtualMachine* HostImpl::create_vm(const std::string& name, s4u::VirtualMa
   auto* cpu =
       englobing_zone_->get_cpu_vm_model()->create_cpu(vm, speeds)->set_core_count(vm->get_vm_impl()->get_core_amount());
 
-  if (get_iface()->get_pstate() != 0)
-    cpu->set_pstate(get_iface()->get_pstate());
-
   cpu->seal();
 
+  if (get_iface()->get_pstate() != 0) {
+    cpu->set_pstate(get_iface()->get_pstate());
+  }
+
   /* Currently, a VM uses the network resource of its physical host */
   vm->set_netpoint(get_iface()->get_netpoint());
 
index 8112b6a..62e8aef 100644 (file)
@@ -68,7 +68,7 @@ CpuCas01Model::CpuCas01Model(const std::string& name) : CpuModel(name)
     select = true;
   }
 
-  set_maxmin_system(lmm::System::build(cfg_cpu_solver, select));
+  set_maxmin_system(lmm::System::build(cfg_cpu_solver.get(), select));
 }
 
 CpuImpl* CpuCas01Model::create_cpu(s4u::Host* host, const std::vector<double>& speed_per_pstate)
index c7f15ec..8ef4943 100644 (file)
@@ -93,7 +93,7 @@ NetworkCm02Model::NetworkCm02Model(const std::string& name) : NetworkModel(name)
     select = true;
   }
 
-  set_maxmin_system(lmm::System::build(cfg_network_solver, select));
+  set_maxmin_system(lmm::System::build(cfg_network_solver.get(), select));
 
   loopback_.reset(create_link("__loopback__", {config::get_value<double>("network/loopback-bw")}));
   loopback_->set_sharing_policy(s4u::Link::SharingPolicy::FATPIPE, {});
index 209639d..60dddcd 100644 (file)
@@ -36,7 +36,7 @@ void surf_host_model_init_ptask_L07()
   XBT_CINFO(xbt_cfg, "Switching to the L07 model to handle parallel tasks.");
   xbt_assert(cfg_ptask_solver != "maxmin", "Invalid configuration. Cannot use maxmin solver with parallel tasks.");
 
-  auto* system    = simgrid::kernel::lmm::System::build(cfg_ptask_solver, true /* selective update */);
+  auto* system    = simgrid::kernel::lmm::System::build(cfg_ptask_solver.get(), true /* selective update */);
   auto host_model = std::make_shared<simgrid::kernel::resource::HostL07Model>("Host_Ptask", system);
   auto* engine    = simgrid::kernel::EngineImpl::get_instance();
   engine->add_model(host_model);
@@ -205,7 +205,7 @@ L07Action::L07Action(Model* model, const std::vector<s4u::Host*>& host_list, con
    * communication either */
   for (size_t i = 0; i < host_nb; i++) {
     model->get_maxmin_system()->expand(host_list[i]->get_cpu()->get_constraint(), get_variable(),
-                                       (flops_amount == nullptr ? 0.0 : flops_amount[i]));
+                                       (flops_amount == nullptr ? 0.0 : flops_amount[i]), true);
   }
 
   if (bytes_amount != nullptr) {
index 8e1598b..7d42393 100644 (file)
@@ -172,30 +172,33 @@ void ETag_surfxml_include()
 
 /* Stag and Etag parse functions */
 void STag_surfxml_platform() {
-  double version = surf_parse_get_double(A_surfxml_platform_version);
-
-  surf_parse_assert((version >= 1.0), "******* BIG FAT WARNING *********\n "
-      "You're using an ancient XML file.\n"
-      "Since SimGrid 3.1, units are Bytes, Flops, and seconds "
-      "instead of MBytes, MFlops and seconds.\n"
-
-      "Use simgrid_update_xml to update your file automatically. "
-      "This program is installed automatically with SimGrid, or "
-      "available in the tools/ directory of the source archive.\n"
-
-      "Please check also out the SURF section of the ChangeLog for "
-      "the 3.1 version for more information. \n"
-
-      "Last, do not forget to also update your values for "
-      "the calls to MSG_task_create (if any).");
-  surf_parse_assert((version >= 3.0), "******* BIG FAT WARNING *********\n "
-      "You're using an old XML file.\n"
-      "Use simgrid_update_xml to update your file automatically. "
-      "This program is installed automatically with SimGrid, or "
-      "available in the tools/ directory of the source archive.");
+  /* Use fixed point arithmetic to avoid rounding errors ("4.1" for example cannot be represented exactly as a floating
+   * point number) */
+  const long int version           = lround(100.0 * surf_parse_get_double(A_surfxml_platform_version));
+  const std::string version_string = std::to_string(version / 100) + "." + std::to_string(version % 100);
+
+  surf_parse_assert(version >= 100L, "******* BIG FAT WARNING *********\n "
+                                     "You're using an ancient XML file.\n"
+                                     "Since SimGrid 3.1, units are Bytes, Flops, and seconds "
+                                     "instead of MBytes, MFlops and seconds.\n"
+
+                                     "Use simgrid_update_xml to update your file automatically. "
+                                     "This program is installed automatically with SimGrid, or "
+                                     "available in the tools/ directory of the source archive.\n"
+
+                                     "Please check also out the SURF section of the ChangeLog for "
+                                     "the 3.1 version for more information. \n"
+
+                                     "Last, do not forget to also update your values for "
+                                     "the calls to MSG_task_create (if any).");
+  surf_parse_assert(version >= 300L, "******* BIG FAT WARNING *********\n "
+                                     "You're using an old XML file.\n"
+                                     "Use simgrid_update_xml to update your file automatically. "
+                                     "This program is installed automatically with SimGrid, or "
+                                     "available in the tools/ directory of the source archive.");
   surf_parse_assert(
-      (version >= 4.0),
-      std::string("******* THIS FILE IS TOO OLD (v:") + std::to_string(version) +
+      version >= 400L,
+      std::string("******* THIS FILE IS TOO OLD (v:") + version_string +
           ") *********\n "
           "Changes introduced in SimGrid 3.13:\n"
           "  - 'power' attribute of hosts (and others) got renamed to 'speed'.\n"
@@ -206,18 +209,18 @@ void STag_surfxml_platform() {
           "Use simgrid_update_xml to update your file automatically. "
           "This program is installed automatically with SimGrid, or "
           "available in the tools/ directory of the source archive.");
-  if (version < 4.1) {
-    XBT_INFO("You're using a v%.1f XML file (%s) while the current standard is v4.1 "
+  if (version < 410L) {
+    XBT_INFO("You're using a v%s XML file (%s) while the current standard is v4.1 "
              "That's fine, the new version is backward compatible. \n\n"
              "Use simgrid_update_xml to update your file automatically to get rid of this warning. "
              "This program is installed automatically with SimGrid, or "
              "available in the tools/ directory of the source archive.",
-             version, surf_parsed_filename.c_str());
+             version_string.c_str(), surf_parsed_filename.c_str());
   }
-  surf_parse_assert(version <= 4.1,
-             std::string("******* THIS FILE COMES FROM THE FUTURE (v:")+std::to_string(version)+") *********\n "
-             "The most recent formalism that this version of SimGrid understands is v4.1.\n"
-             "Please update your code, or use another, more adapted, file.");
+  surf_parse_assert(version <= 410L, std::string("******* THIS FILE COMES FROM THE FUTURE (v:") + version_string +
+                                         ") *********\n "
+                                         "The most recent formalism that this version of SimGrid understands is v4.1.\n"
+                                         "Please update your code, or use another, more adapted, file.");
 }
 void ETag_surfxml_platform(){
   simgrid::s4u::Engine::on_platform_created();
index 8592ad6..32d1d41 100644 (file)
@@ -93,21 +93,6 @@ static void search_not_found(const_xbt_dict_t head, const char* data)
   REQUIRE(xbt_dict_get_or_null(head, data) == nullptr);
 }
 
-static void count(const_xbt_dict_t dict, int length)
-{
-  INFO("Count elements (expecting " << length << ")");
-  REQUIRE(xbt_dict_length(dict) == length); // Announced length differs
-
-  xbt_dict_cursor_t cursor;
-  char* key;
-  void* data;
-  int effective = 0;
-  xbt_dict_foreach (dict, cursor, key, data)
-    effective++;
-
-  REQUIRE(effective == length); // Effective length differs
-}
-
 static int countelems(const_xbt_dict_t head)
 {
   xbt_dict_cursor_t cursor;
@@ -121,6 +106,13 @@ static int countelems(const_xbt_dict_t head)
   return res;
 }
 
+static void count(const_xbt_dict_t dict, int length)
+{
+  INFO("Count elements (expecting " << length << ")");
+  REQUIRE(xbt_dict_length(dict) == length); // Announced length differs
+  REQUIRE(countelems(dict) == length);      // Effective length differs
+}
+
 TEST_CASE("xbt::dict: dict data container", "dict")
 {
   SECTION("Basic usage: change, retrieve and traverse homogeneous dicts")
index 10c47ff..c6c5a84 100644 (file)
@@ -11,7 +11,6 @@
    Heavily modified Mar 1992 by Fred Fish.  (fnf@cygnus.com) */
 
 #include "mmprivate.h"
-#include "xbt/ex.h"
 #include "mc/mc.h"
 
 /* Return memory to the heap.
@@ -30,6 +29,11 @@ void mfree(struct mdesc *mdp, void *ptr)
   size_t block = BLOCK(ptr);
 
   if ((char *) ptr < (char *) mdp->heapbase || block > mdp->heapsize) {
+    if ((char*)ptr <= (char*)mmalloc_preinit_buffer + mmalloc_preinit_buffer_size &&
+        (char*)ptr >= (char*)mmalloc_preinit_buffer)
+      /* This points to the static buffer for fake mallocs done by dlsym before mmalloc initialization, ignore it */
+      return;
+
     fprintf(stderr,"Ouch, this pointer is not mine, I refuse to free it. Give me valid pointers, or give me death!!\n");
     abort();
   }
@@ -38,13 +42,13 @@ void mfree(struct mdesc *mdp, void *ptr)
 
   switch (type) {
   case MMALLOC_TYPE_HEAPINFO:
-    UNLOCK(mdp);
-    THROW("Asked to free a fragment in a heapinfo block. I'm confused.\n");
+    fprintf(stderr, "Asked to free a fragment in a heapinfo block. I'm confused.\n");
+    abort();
     break;
 
   case MMALLOC_TYPE_FREE: /* Already free */
-    UNLOCK(mdp);
-    THROW("Asked to free a fragment in a block that is already free. I'm puzzled.\n");
+    fprintf(stderr, "Asked to free a fragment in a block that is already free. I'm puzzled.\n");
+    abort();
     break;
 
   case MMALLOC_TYPE_UNFRAGMENTED:
@@ -166,8 +170,8 @@ void mfree(struct mdesc *mdp, void *ptr)
     frag_nb = RESIDUAL(ptr, BLOCKSIZE) >> type;
 
     if( mdp->heapinfo[block].busy_frag.frag_size[frag_nb] == -1){
-      UNLOCK(mdp);
-      THROW("Asked to free a fragment that is already free. I'm puzzled\n");
+      fprintf(stderr, "Asked to free a fragment that is already free. I'm puzzled\n");
+      abort();
     }
 
     if (MC_is_active() && mdp->heapinfo[block].busy_frag.ignore[frag_nb] > 0)
diff --git a/src/xbt/mmalloc/mm_interface.c b/src/xbt/mmalloc/mm_interface.c
new file mode 100644 (file)
index 0000000..5f03243
--- /dev/null
@@ -0,0 +1,53 @@
+/* External interface to a mmap'd malloc managed region. */
+
+/* Copyright (c) 2012-2022. 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. */
+
+/* Copyright 1992, 2000 Free Software Foundation, Inc.
+
+   Contributed by Fred Fish at Cygnus Support.   fnf@cygnus.com
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <fcntl.h> /* After sys/types.h, at least for dpx/2.  */
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "mmprivate.h"
+
+// This is the underlying implementation of mmalloc_get_bytes_used_remote.
+// Is it used directly to evaluate the bytes used from a different process.
+size_t mmalloc_get_bytes_used_remote(size_t heaplimit, const malloc_info* heapinfo)
+{
+  int bytes = 0;
+  for (size_t i = 0; i < heaplimit; ++i) {
+    if (heapinfo[i].type == MMALLOC_TYPE_UNFRAGMENTED) {
+      if (heapinfo[i].busy_block.busy_size > 0)
+        bytes += heapinfo[i].busy_block.busy_size;
+    } else if (heapinfo[i].type > 0) {
+      for (size_t j = 0; j < (size_t)(BLOCKSIZE >> heapinfo[i].type); j++) {
+        if (heapinfo[i].busy_frag.frag_size[j] > 0)
+          bytes += heapinfo[i].busy_frag.frag_size[j];
+      }
+    }
+  }
+  return bytes;
+}
index 3228074..ee822fd 100644 (file)
@@ -1,5 +1,4 @@
-/* Copyright (c) 2010-2022. The SimGrid Team.
- * All rights reserved.                                                     */
+/* Copyright (c) 2010-2022. 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. */
@@ -7,19 +6,16 @@
 /* Redefine the classical malloc/free/realloc functions so that they fit well in the mmalloc framework */
 #define _GNU_SOURCE
 
-#include <stdlib.h>
+#include "mmprivate.h"
 
 #include <dlfcn.h>
-
-#include "mmprivate.h"
-#include "src/internal_config.h"
-#include "src/mc/remote/mc_protocol.h"
-#include "xbt/xbt_modinter.h"
 #include <math.h>
+#include <stdlib.h>
 
 /* ***** Whether to use `mmalloc` of the underlying malloc ***** */
 
 static int __malloc_use_mmalloc;
+int mmalloc_pagesize = 0;
 
 int malloc_use_mmalloc(void)
 {
@@ -43,20 +39,14 @@ xbt_mheap_t mmalloc_get_current_heap(void)
 }
 
 /* Override the malloc-like functions if MC is activated at compile time */
-#if SIMGRID_HAVE_MC
-
 /* ***** Temporary allocator
  *
  * This is used before we have found the real malloc implementation with dlsym.
  */
 
-#ifdef __FreeBSD__ /* FreeBSD require more memory, other might */
-# define BUFFER_SIZE 256
-#else /* Valid on: Linux */
-# define BUFFER_SIZE 32
-#endif
 static size_t fake_alloc_index;
-static uint64_t buffer[BUFFER_SIZE];
+static uint64_t buffer[mmalloc_preinit_buffer_size];
+uint64_t* mmalloc_preinit_buffer = buffer;
 
 /* Fake implementations, they are used to fool dlsym:
  * dlsym used calloc and falls back to some other mechanism
@@ -64,13 +54,18 @@ static uint64_t buffer[BUFFER_SIZE];
  */
 static void* mm_fake_malloc(size_t n)
 {
+  mmalloc_preinit_buffer = buffer;
+
   // How many uint64_t do w need?
   size_t count = n / sizeof(uint64_t);
   if (n % sizeof(uint64_t))
     count++;
   // Check that we have enough available memory:
-  if (fake_alloc_index + count >= BUFFER_SIZE)
+  if (fake_alloc_index + count >= mmalloc_preinit_buffer_size) {
+    puts("mmalloc is not initialized yet, but the static buffer used as malloc replacement is already exhausted. "
+         "Please increase `mmalloc_preinit_buffer_size` in mm_legacy.c\n");
     exit(127);
+  }
   // Allocate it:
   uint64_t* res = buffer + fake_alloc_index;
   fake_alloc_index += count;
@@ -132,6 +127,8 @@ XBT_ATTRIB_CONSTRUCTOR(101) static void mm_legacy_constructor()
     mm_real_calloc   = dlsym(RTLD_NEXT, "calloc");
 #endif
   }
+  mmalloc_pagesize = getpagesize();
+
   mm_initializing = 0;
   mm_initialized = 1;
 }
@@ -163,10 +160,7 @@ void *malloc(size_t n)
   if (!mdp)
     return NULL;
 
-  LOCK(mdp);
-  void *ret = mmalloc(mdp, n);
-  UNLOCK(mdp);
-  return ret;
+  return mmalloc(mdp, n);
 }
 
 void *calloc(size_t nmemb, size_t size)
@@ -185,9 +179,7 @@ void *calloc(size_t nmemb, size_t size)
   if (!mdp)
     return NULL;
 
-  LOCK(mdp);
   void *ret = mmalloc(mdp, nmemb*size);
-  UNLOCK(mdp);
   // This was already done in the callee:
   if(!(mdp->options & XBT_MHEAP_OPTION_MEMSET)) {
     memset(ret, 0, nmemb * size);
@@ -211,10 +203,7 @@ void *realloc(void *p, size_t s)
   if (!mdp)
     return NULL;
 
-  LOCK(mdp);
-  void* ret = mrealloc(mdp, p, s);
-  UNLOCK(mdp);
-  return ret;
+  return mrealloc(mdp, p, s);
 }
 
 void free(void *p)
@@ -234,8 +223,5 @@ void free(void *p)
     return;
 
   xbt_mheap_t mdp = GET_HEAP();
-  LOCK(mdp);
   mfree(mdp, p);
-  UNLOCK(mdp);
 }
-#endif /* SIMGRID_HAVE_MC */
index 8358d43..1eca509 100644 (file)
@@ -1,7 +1,6 @@
 /* Initialization for access to a mmap'd malloc managed region. */
 
-/* Copyright (c) 2012-2022. The SimGrid Team.
- * All rights reserved.                                                     */
+/* Copyright (c) 2012-2022. 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. */
    not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include "src/internal_config.h"
 #include <sys/types.h>
 #include <fcntl.h>              /* After sys/types.h, at least for dpx/2.  */
 #include <sys/stat.h>
 #include <string.h>
 #include "mmprivate.h"
-#include "xbt/ex.h"
-#include "xbt/xbt_modinter.h" /* declarations of mmalloc_preinit and friends that live here */
 
 /* Initialize access to a mmalloc managed region.
 
@@ -49,7 +45,7 @@
    so that users of the package don't have to worry about the actual
    implementation details.
 
-   On failure returns NULL. */
+   On failure, returns NULL. */
 
 xbt_mheap_t xbt_mheap_new(void* baseaddr, int options)
 {
@@ -71,7 +67,6 @@ xbt_mheap_t xbt_mheap_new(void* baseaddr, int options)
   mdp->next_mdesc = NULL;
   mdp->options = options;
 
-  pthread_mutex_init(&mdp->mutex, NULL);
   /* If we have not been passed a valid open file descriptor for the file
      to map to, then open /dev/zero and use that to map to. */
 
@@ -92,28 +87,12 @@ xbt_mheap_t xbt_mheap_new(void* baseaddr, int options)
     while(mdp->next_mdesc)
       mdp = mdp->next_mdesc;
 
-    LOCK(mdp);
     mdp->next_mdesc = (struct mdesc *)mbase;
-    UNLOCK(mdp);
   }
 
   return mbase;
 }
 
-
-
-/** Terminate access to a mmalloc managed region, but do not free its content.
- *
- * This is for example useful for the base region where ldl stores its data
- *   because it leaves the place after us.
- */
-void xbt_mheap_destroy_no_free(xbt_mheap_t md)
-{
-  struct mdesc *mdp = md;
-
-  pthread_mutex_destroy(&mdp->mutex);
-}
-
 /** Terminate access to a mmalloc managed region by unmapping all memory pages associated with the region, and closing
  *  the file descriptor if it is one that we opened.
 
@@ -135,7 +114,6 @@ void *xbt_mheap_destroy(xbt_mheap_t mdp)
 
     mdptemp->next_mdesc = mdp->next_mdesc;
 
-    xbt_mheap_destroy_no_free(mdp);
     struct mdesc mtemp = *mdp;
 
     /* Now unmap all the pages associated with this region by asking for a
@@ -156,81 +134,20 @@ void *xbt_mheap_destroy(xbt_mheap_t mdp)
  * Try to increase this first if you experience strange errors under valgrind. */
 #define HEAP_OFFSET   (128UL<<20)
 
-static void mmalloc_fork_prepare(void)
-{
-  xbt_mheap_t mdp = NULL;
-  if ((mdp =__mmalloc_default_mdp)){
-    while(mdp){
-      LOCK(mdp);
-      mdp = mdp->next_mdesc;
-    }
-  }
-}
-
-static void mmalloc_fork_parent(void)
-{
-  xbt_mheap_t mdp = NULL;
-  if ((mdp =__mmalloc_default_mdp)){
-    while(mdp){
-      UNLOCK(mdp);
-      mdp = mdp->next_mdesc;
-    }
-  }
-}
-
-static void mmalloc_fork_child(void)
-{
-  struct mdesc* mdp = NULL;
-  if ((mdp =__mmalloc_default_mdp)){
-    while(mdp){
-      UNLOCK(mdp);
-      mdp = mdp->next_mdesc;
-    }
-  }
-}
-
-/* Initialize the default malloc descriptor. */
+/* Initialize the default malloc descriptor.
+ *
+ * There is no malloc_postexit() destroying the default mdp, because it would break ldl trying to free its memory
+ */
 xbt_mheap_t mmalloc_preinit(void)
 {
   if (__mmalloc_default_mdp == NULL) {
-    if(!xbt_pagesize)
-      xbt_pagesize = getpagesize();
-    unsigned long mask = ~((unsigned long)xbt_pagesize - 1);
-    void *addr = (void*)(((unsigned long)sbrk(0) + HEAP_OFFSET) & mask);
+    if (!mmalloc_pagesize)
+      mmalloc_pagesize = getpagesize();
+    unsigned long mask    = ~((unsigned long)mmalloc_pagesize - 1);
+    void* addr            = (void*)(((unsigned long)sbrk(0) + HEAP_OFFSET) & mask);
     __mmalloc_default_mdp = xbt_mheap_new(addr, XBT_MHEAP_OPTION_MEMSET);
-
-    // atfork mandated at least on FreeBSD, or simgrid-mc will fail to fork the verified app
-    int res = pthread_atfork(mmalloc_fork_prepare, mmalloc_fork_parent, mmalloc_fork_child);
-    xbt_assert(res == 0, "pthread_atfork() failed: return value %d", res);
   }
-  xbt_assert(__mmalloc_default_mdp != NULL);
+  mmalloc_assert(__mmalloc_default_mdp != NULL, "__mmalloc_default_mdp cannot be NULL");
 
   return __mmalloc_default_mdp;
 }
-
-void mmalloc_postexit(void)
-{
-  /* Do not destroy the default mdp or ldl won't be able to free the memory it
-   * allocated since we're in memory */
-  // xbt_mheap_destroy_no_free(__mmalloc_default_mdp)
-}
-
-// This is the underlying implementation of mmalloc_get_bytes_used_remote.
-// Is it used directly in order to evaluate the bytes used from a different
-// process.
-size_t mmalloc_get_bytes_used_remote(size_t heaplimit, const malloc_info* heapinfo)
-{
-  int bytes = 0;
-  for (size_t i=0; i < heaplimit; ++i){
-    if (heapinfo[i].type == MMALLOC_TYPE_UNFRAGMENTED){
-      if (heapinfo[i].busy_block.busy_size > 0)
-        bytes += heapinfo[i].busy_block.busy_size;
-    } else if (heapinfo[i].type > 0) {
-      for (size_t j=0; j < (size_t) (BLOCKSIZE >> heapinfo[i].type); j++){
-        if(heapinfo[i].busy_frag.frag_size[j] > 0)
-          bytes += heapinfo[i].busy_frag.frag_size[j];
-      }
-    }
-  }
-  return bytes;
-}
index 5b48368..be0070f 100644 (file)
 
 static void initialize(xbt_mheap_t mdp);
 static void *register_morecore(xbt_mheap_t mdp, size_t size);
-static void *align(xbt_mheap_t mdp, size_t size);
+static void* mmalloc_aligned(xbt_mheap_t mdp, size_t size);
 
 /* Allocation aligned on block boundary.
  *
  * It never returns NULL, but dies verbosely on error.
  */
-static void *align(struct mdesc *mdp, size_t size)
+static void* mmalloc_aligned(struct mdesc* mdp, size_t size)
 {
   void *result;
   unsigned long int adj;
@@ -47,13 +47,11 @@ static void *align(struct mdesc *mdp, size_t size)
   return result;
 }
 
-/** Initialize heapinfo about the heapinfo pages :)
- *
- */
+/** Initialize heapinfo about the heapinfo pages :) */
 static void initialize_heapinfo_heapinfo(const s_xbt_mheap_t* mdp)
 {
   // Update heapinfo about the heapinfo pages (!):
-  xbt_assert((uintptr_t) mdp->heapinfo % BLOCKSIZE == 0);
+  mmalloc_assert((uintptr_t)mdp->heapinfo % BLOCKSIZE == 0, "Failed assert in initialize_heapinfo_heapinfo()");
   size_t block   = BLOCK(mdp->heapinfo);
   size_t nblocks = mdp->heapsize * sizeof(malloc_info) / BLOCKSIZE;
   // Mark them as free:
@@ -67,13 +65,12 @@ static void initialize_heapinfo_heapinfo(const s_xbt_mheap_t* mdp)
 }
 
 /* Finish the initialization of the mheap. If we want to inline it
- * properly, we need to make the align function publicly visible, too  */
+ * properly, we need to make the mmalloc_aligned function publicly visible, too  */
 static void initialize(xbt_mheap_t mdp)
 {
   // Update mdp meta-data:
   mdp->heapsize = HEAP / BLOCKSIZE;
-  mdp->heapinfo = (malloc_info *)
-    align(mdp, mdp->heapsize * sizeof(malloc_info));
+  mdp->heapinfo = (malloc_info*)mmalloc_aligned(mdp, mdp->heapsize * sizeof(malloc_info));
   mdp->heapbase = (void *) mdp->heapinfo;
   mdp->flags |= MMALLOC_INITIALIZED;
 
@@ -102,7 +99,7 @@ static inline void update_hook(void **a, size_t offset)
  * into the heap info table as necessary. */
 static void *register_morecore(struct mdesc *mdp, size_t size)
 {
-  void* result = align(mdp, size); // Never returns NULL
+  void* result = mmalloc_aligned(mdp, size); // Never returns NULL
 
   /* Check if we need to grow the info table (in a multiplicative manner)  */
   if ((size_t) BLOCK((char *) result + size) > mdp->heapsize) {
@@ -112,7 +109,7 @@ static void *register_morecore(struct mdesc *mdp, size_t size)
 
     /* Copy old info into new location */
     malloc_info* oldinfo = mdp->heapinfo;
-    malloc_info* newinfo = (malloc_info*)align(mdp, newsize * sizeof(malloc_info));
+    malloc_info* newinfo = (malloc_info*)mmalloc_aligned(mdp, newsize * sizeof(malloc_info));
     memcpy(newinfo, oldinfo, mdp->heapsize * sizeof(malloc_info));
 
     /* Initialize the new blockinfo : */
@@ -217,8 +214,9 @@ void *mmalloc_no_memset(xbt_mheap_t mdp, size_t size)
       for (candidate_frag=0;candidate_frag<(size_t) (BLOCKSIZE >> log);candidate_frag++)
         if (candidate_info->busy_frag.frag_size[candidate_frag] == -1)
           break;
-      xbt_assert(candidate_frag < (size_t) (BLOCKSIZE >> log),
-          "Block %zu was registered as containing free fragments of type %zu, but I can't find any",candidate_block,log);
+      mmalloc_assert(candidate_frag < (size_t)(BLOCKSIZE >> log),
+                     "Block %zu was registered as containing free fragments of type %zu, but I can't find any",
+                     candidate_block, log);
 
       result = (void*) (((char*)ADDRESS(candidate_block)) + (candidate_frag << log));
 
index 828e2f5..fcb2fa0 100644 (file)
@@ -10,7 +10,6 @@
 
    Contributed by Fred Fish at Cygnus Support.   fnf@cygnus.com */
 
-#include "src/internal_config.h"
 #include <stdio.h>
 #include <fcntl.h>
 #include <sys/mman.h>
@@ -23,8 +22,7 @@
 #define MAP_ANONYMOUS MAP_ANON
 #endif
 
-#define PAGE_ALIGN(addr) (void*) (((long)(addr) + xbt_pagesize - 1) &   \
-                                  ~((long)xbt_pagesize - 1))
+#define PAGE_ALIGN(addr) (void*)(((long)(addr) + mmalloc_pagesize - 1) & ~((long)mmalloc_pagesize - 1))
 
 /** @brief Add memory to this heap
  *
@@ -49,6 +47,10 @@ void *mmorecore(struct mdesc *mdp, ssize_t size)
     return mdp->breakval;
   }
 
+  if (mmalloc_pagesize == 0) { // Not initialized yet
+    mmalloc_pagesize = (int)sysconf(_SC_PAGESIZE);
+  }
+
   if (size < 0) {
     /* We are deallocating memory.  If the amount requested would cause us to try to deallocate back past the base of
      * the mmap'd region then die verbosely.  Otherwise, deallocate the memory and return the old break value. */
@@ -76,7 +78,8 @@ void *mmorecore(struct mdesc *mdp, ssize_t size)
 
     if (mapto == MAP_FAILED) {
       char buff[1024];
-      fprintf(stderr, "Internal error: mmap returned MAP_FAILED! error: %s\n", strerror(errno));
+      fprintf(stderr, "Internal error: mmap returned MAP_FAILED! pagesize:%d error: %s\n", mmalloc_pagesize,
+              strerror(errno));
       snprintf(buff, 1024, "cat /proc/%d/maps", getpid());
       int status = system(buff);
       if (status == -1 || !(WIFEXITED(status) && WEXITSTATUS(status) == 0))
index 648bd1f..5e380cc 100644 (file)
 #ifndef XBT_MMPRIVATE_H
 #define XBT_MMPRIVATE_H 1
 
-#include <xbt/base.h>
-#include <xbt/misc.h>
-
 #include "swag.h"
 #include "src/internal_config.h"
 #include "xbt/mmalloc.h"
-#include "xbt/ex.h"
-#include "xbt/dynar.h"
 
-#include <pthread.h>
+#include <limits.h>
 #include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
 
-#include <limits.h>
+// This macro is veery similar to xbt_assert, but with no dependency on XBT
+#define mmalloc_assert(cond, ...)                                                                                      \
+  do {                                                                                                                 \
+    if (!(cond)) {                                                                                                     \
+      fprintf(stderr, __VA_ARGS__);                                                                                    \
+      abort();                                                                                                         \
+    }                                                                                                                  \
+  } while (0)
+
+XBT_PUBLIC_DATA int mmalloc_pagesize;
+XBT_PRIVATE xbt_mheap_t mmalloc_preinit(void);
 
 #define MMALLOC_MAGIC    "mmalloc"       /* Mapped file magic number */
 #define MMALLOC_MAGIC_SIZE  8       /* Size of magic number buf */
  * information are kept in fixed length arrays. Here is the computation of
  * that size.
  *
- * Never make SMALLEST_POSSIBLE_MALLOC smaller than sizeof(list) because we
- * need to enlist the free fragments.
+ * Never make SMALLEST_POSSIBLE_MALLOC too small because we need to enlist
+ * the free fragments.
+ *
+ * FIXME: what's the correct size, actually? The used one is a guess.
  */
 
-#define SMALLEST_POSSIBLE_MALLOC (16*sizeof(struct list))
+#define SMALLEST_POSSIBLE_MALLOC (32 * sizeof(void*))
 #define MAX_FRAGMENT_PER_BLOCK (BLOCKSIZE / SMALLEST_POSSIBLE_MALLOC)
 
 /* The difference between two pointers is a signed int.  On machines where
 
 SG_BEGIN_DECL
 
-/* Doubly linked lists of free fragments.  */
-struct list {
-  struct list *next;
-  struct list *prev;
-};
-
 /* Statistics available to the user. */
 struct mstats
 {
@@ -170,9 +173,6 @@ typedef struct {
  * if such a file exists.
  * */
 struct mdesc {
-  /** @brief Mutex locking the access to the heap */
-  pthread_mutex_t mutex;
-
   /** @brief Chained lists of mdescs */
   struct mdesc *next_mdesc;
 
@@ -257,19 +257,18 @@ XBT_PUBLIC_DATA struct mdesc* __mmalloc_default_mdp;
 
 XBT_PUBLIC void* mmorecore(struct mdesc* mdp, ssize_t size);
 
-/** Thread-safety (if the mutex is already created)
- *
- * This is mandatory in the case where the user runs a parallel simulation
- * in a model-checking enabled tree. Without this protection, our malloc
- * implementation will not like multi-threading AT ALL.
- */
-#define LOCK(mdp) pthread_mutex_lock(&(mdp)->mutex)
-#define UNLOCK(mdp) pthread_mutex_unlock(&(mdp)->mutex)
-
-XBT_PRIVATE int malloc_use_mmalloc(void);
-
 XBT_PRIVATE size_t mmalloc_get_bytes_used_remote(size_t heaplimit, const malloc_info* heapinfo);
 
+/* We call dlsym during mmalloc initialization, but dlsym uses malloc.
+ * So during mmalloc initialization, any call to malloc is diverted to a private static buffer.
+ */
+extern uint64_t* mmalloc_preinit_buffer;
+#ifdef __FreeBSD__ /* FreeBSD require more memory, other might */
+#define mmalloc_preinit_buffer_size 256
+#else /* Valid on: Linux */
+#define mmalloc_preinit_buffer_size 32
+#endif
+
 SG_END_DECL
 
 #endif
index a3cdcb9..550b89b 100644 (file)
@@ -1,5 +1,4 @@
-/* Copyright (c) 2004-2022. The SimGrid Team.
- * All rights reserved.                                                     */
+/* Copyright (c) 2004-2022. 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. */
@@ -11,7 +10,7 @@
 /* This type should be added to a type that is to be used in such a swag */
 
 #include "swag.h"
-#include "xbt/asserts.h"
+#include "mmprivate.h" // mmalloc_assert
 
 typedef s_xbt_swag_hookup_t *xbt_swag_hookup_t;
 typedef struct xbt_swag* xbt_swag_t;
@@ -63,11 +62,12 @@ static inline void xbt_swag_init(xbt_swag_t swag, size_t offset)
  */
 static inline void xbt_swag_insert(void *obj, xbt_swag_t swag)
 {
-  xbt_assert(!xbt_swag_belongs(obj, swag) || swag->tail,
-             "This object belongs to an empty swag! Did you correctly initialize the object's hookup?");
+
+  mmalloc_assert(!xbt_swag_belongs(obj, swag) || swag->tail,
+                 "This object belongs to an empty swag! Did you correctly initialize the object's hookup?");
 
   if (!swag->head) {
-    xbt_assert(!(swag->tail), "Inconsistent swag.");
+    mmalloc_assert(!(swag->tail), "Inconsistent swag.");
     swag->head = obj;
     swag->tail = obj;
     swag->count++;
index c88a996..032c741 100644 (file)
@@ -9,8 +9,6 @@
 #ifndef XBT_SWAG_H
 #define XBT_SWAG_H
 
-#include "xbt/sysdep.h" /* size_t */
-
 /*
  * XBT_swag: a O(1) set based on linked lists
  *
index 8ee72a4..15a5959 100644 (file)
@@ -115,9 +115,6 @@ static void xbt_postexit()
   xbt_initialized--;
   xbt_dict_postexit();
   xbt_log_postexit();
-#if SIMGRID_HAVE_MC
-  mmalloc_postexit();
-#endif
 }
 
 /** @brief Initialize the xbt mechanisms. */
index 8ed3273..fee5b7b 100644 (file)
@@ -149,7 +149,7 @@ static void test_deref(simgrid::dwarf::ExpressionContext const& state)
 int main()
 {
   auto* process = new simgrid::mc::RemoteProcess(getpid());
-  process->init(nullptr, nullptr, nullptr);
+  process->init(nullptr, nullptr);
 
   simgrid::dwarf::ExpressionContext state;
   state.address_space = (simgrid::mc::AddressSpace*) process;
index 0a1e41e..352a73b 100644 (file)
@@ -123,7 +123,7 @@ int main(int argc, char** argv)
   simgrid::mc::Type* type;
 
   simgrid::mc::RemoteProcess process(getpid());
-  process.init(nullptr, nullptr, nullptr);
+  process.init(nullptr, nullptr);
 
   test_global_variable(process, process.binary_info.get(), "some_local_variable", &some_local_variable, sizeof(int));
 
index 623f4c5..e2dcf82 100644 (file)
@@ -1,8 +1,8 @@
 #!/usr/bin/env tesh
 ! expect return 1
 $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random-bug assert ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=xbt_cfg.thresh:warning
-> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (0:maestro@) Behavior: assert
+> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (0:maestro@) **************************
 > [  0.000000] (0:maestro@) *** PROPERTY NOT VALID ***
 > [  0.000000] (0:maestro@) **************************
@@ -13,7 +13,7 @@ $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random-bug assert ${platfdir
 > [  0.000000] (0:maestro@) DFS exploration ended. 27 unique states visited; 22 backtracks (68 transition replays, 19 states visited overall)
 
 $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random-bug printf ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=xbt_cfg.thresh:warning
-> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (0:maestro@) Behavior: printf
+> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (1:app@Fafard) Error reached
 > [  0.000000] (0:maestro@) DFS exploration ended. 43 unique states visited; 36 backtracks (108 transition replays, 30 states visited overall)
index f73d665..3b6ffa2 100644 (file)
@@ -1,8 +1,8 @@
 #!/usr/bin/env tesh
 ! expect return 1
 $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random-bug assert ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=xbt_cfg.thresh:warning
-> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (0:maestro@) Behavior: assert
+> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (0:maestro@) **************************
 > [  0.000000] (0:maestro@) *** PROPERTY NOT VALID ***
 > [  0.000000] (0:maestro@) **************************
@@ -15,8 +15,8 @@ $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random-bug assert ${platfdir
 ! expect return 6
 # because SIMGRID_MC_EXIT_PROGRAM_CRASH = 6
 $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random-bug abort ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=xbt_cfg.thresh:warning --log=no_loc
-> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (0:maestro@) Behavior: abort
+> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (0:maestro@) **************************
 > [  0.000000] (0:maestro@) ** CRASH IN THE PROGRAM **
 > [  0.000000] (0:maestro@) **************************
@@ -29,16 +29,16 @@ $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random-bug abort ${platfdir}
 > [  0.000000] (0:maestro@) Stack trace not displayed because you passed --log=no_loc
 
 $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random-bug printf ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=xbt_cfg.thresh:warning
-> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (0:maestro@) Behavior: printf
+> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (1:app@Fafard) Error reached
 > [  0.000000] (0:maestro@) DFS exploration ended. 43 unique states visited; 36 backtracks (108 transition replays, 30 states visited overall)
 
 ! expect return 6
 # because SIMGRID_MC_EXIT_PROGRAM_CRASH = 6
 $ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random-bug segv ${platfdir}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=xbt_cfg.thresh:warning --log=no_loc
-> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > [  0.000000] (0:maestro@) Behavior: segv
+> [  0.000000] (0:maestro@) Start a DFS exploration. Reduction is: dpor.
 > Segmentation fault.
 > [  0.000000] (0:maestro@) **************************
 > [  0.000000] (0:maestro@) ** CRASH IN THE PROGRAM **
index 7c8deab..8b7373e 100644 (file)
@@ -1333,10 +1333,10 @@ $ ${bindir:=.}/flatifier ./cluster_fat_tree_noncontiguous_rad.xml "--log=root.fm
 >   <link_ctn id="bob_cluster_link_0_limiter"/><link_ctn id="link_from_0_7_0_UP"/><link_ctn id="link_from_1_7_1_DOWN"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="bob_cluster_link_1_limiter"/>
 >   </route>
 >   <route src="node-100.simgrid.org" dst="node-119.simgrid.org">
->   <link_ctn id="bob_cluster_link_0_limiter"/><link_ctn id="link_from_0_7_0_UP"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="link_from_7_5_4_UP"/><link_ctn id="link_from_6_5_8_DOWN"/><link_ctn id="bob_cluster_link_5_limiter"/><link_ctn id="link_from_2_6_2_DOWN"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="bob_cluster_link_2_limiter"/>
+>   <link_ctn id="bob_cluster_link_0_limiter"/><link_ctn id="link_from_0_7_0_UP"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="link_from_7_5_5_UP"/><link_ctn id="link_from_6_5_8_DOWN"/><link_ctn id="bob_cluster_link_5_limiter"/><link_ctn id="link_from_2_6_2_DOWN"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="bob_cluster_link_2_limiter"/>
 >   </route>
 >   <route src="node-100.simgrid.org" dst="node-120.simgrid.org">
->   <link_ctn id="bob_cluster_link_0_limiter"/><link_ctn id="link_from_0_7_0_UP"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="link_from_7_4_6_UP"/><link_ctn id="link_from_6_4_10_DOWN"/><link_ctn id="bob_cluster_link_4_limiter"/><link_ctn id="link_from_3_6_3_DOWN"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="bob_cluster_link_3_limiter"/>
+>   <link_ctn id="bob_cluster_link_0_limiter"/><link_ctn id="link_from_0_7_0_UP"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="link_from_7_4_7_UP"/><link_ctn id="link_from_6_4_10_DOWN"/><link_ctn id="bob_cluster_link_4_limiter"/><link_ctn id="link_from_3_6_3_DOWN"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="bob_cluster_link_3_limiter"/>
 >   </route>
 >   <route src="node-101.simgrid.org" dst="node-100.simgrid.org">
 >   <link_ctn id="bob_cluster_link_1_limiter"/><link_ctn id="link_from_1_7_1_UP"/><link_ctn id="link_from_0_7_0_DOWN"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="bob_cluster_link_0_limiter"/>
@@ -1345,10 +1345,10 @@ $ ${bindir:=.}/flatifier ./cluster_fat_tree_noncontiguous_rad.xml "--log=root.fm
 >   <link_ctn id="bob_cluster_link_101_loopback"/>
 >   </route>
 >   <route src="node-101.simgrid.org" dst="node-119.simgrid.org">
->   <link_ctn id="bob_cluster_link_1_limiter"/><link_ctn id="link_from_1_7_1_UP"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="link_from_7_5_4_UP"/><link_ctn id="link_from_6_5_8_DOWN"/><link_ctn id="bob_cluster_link_5_limiter"/><link_ctn id="link_from_2_6_2_DOWN"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="bob_cluster_link_2_limiter"/>
+>   <link_ctn id="bob_cluster_link_1_limiter"/><link_ctn id="link_from_1_7_1_UP"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="link_from_7_5_5_UP"/><link_ctn id="link_from_6_5_9_DOWN"/><link_ctn id="bob_cluster_link_5_limiter"/><link_ctn id="link_from_2_6_2_DOWN"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="bob_cluster_link_2_limiter"/>
 >   </route>
 >   <route src="node-101.simgrid.org" dst="node-120.simgrid.org">
->   <link_ctn id="bob_cluster_link_1_limiter"/><link_ctn id="link_from_1_7_1_UP"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="link_from_7_4_6_UP"/><link_ctn id="link_from_6_4_10_DOWN"/><link_ctn id="bob_cluster_link_4_limiter"/><link_ctn id="link_from_3_6_3_DOWN"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="bob_cluster_link_3_limiter"/>
+>   <link_ctn id="bob_cluster_link_1_limiter"/><link_ctn id="link_from_1_7_1_UP"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="link_from_7_4_7_UP"/><link_ctn id="link_from_6_4_11_DOWN"/><link_ctn id="bob_cluster_link_4_limiter"/><link_ctn id="link_from_3_6_3_DOWN"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="bob_cluster_link_3_limiter"/>
 >   </route>
 >   <route src="node-119.simgrid.org" dst="node-100.simgrid.org">
 >   <link_ctn id="bob_cluster_link_2_limiter"/><link_ctn id="link_from_2_6_2_UP"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="link_from_6_5_8_UP"/><link_ctn id="link_from_7_5_4_DOWN"/><link_ctn id="bob_cluster_link_5_limiter"/><link_ctn id="link_from_0_7_0_DOWN"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="bob_cluster_link_0_limiter"/>
@@ -1363,10 +1363,10 @@ $ ${bindir:=.}/flatifier ./cluster_fat_tree_noncontiguous_rad.xml "--log=root.fm
 >   <link_ctn id="bob_cluster_link_2_limiter"/><link_ctn id="link_from_2_6_2_UP"/><link_ctn id="link_from_3_6_3_DOWN"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="bob_cluster_link_3_limiter"/>
 >   </route>
 >   <route src="node-120.simgrid.org" dst="node-100.simgrid.org">
->   <link_ctn id="bob_cluster_link_3_limiter"/><link_ctn id="link_from_3_6_3_UP"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="link_from_6_5_8_UP"/><link_ctn id="link_from_7_5_4_DOWN"/><link_ctn id="bob_cluster_link_5_limiter"/><link_ctn id="link_from_0_7_0_DOWN"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="bob_cluster_link_0_limiter"/>
+>   <link_ctn id="bob_cluster_link_3_limiter"/><link_ctn id="link_from_3_6_3_UP"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="link_from_6_5_8_UP"/><link_ctn id="link_from_7_5_5_DOWN"/><link_ctn id="bob_cluster_link_5_limiter"/><link_ctn id="link_from_0_7_0_DOWN"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="bob_cluster_link_0_limiter"/>
 >   </route>
 >   <route src="node-120.simgrid.org" dst="node-101.simgrid.org">
->   <link_ctn id="bob_cluster_link_3_limiter"/><link_ctn id="link_from_3_6_3_UP"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="link_from_6_4_10_UP"/><link_ctn id="link_from_7_4_6_DOWN"/><link_ctn id="bob_cluster_link_4_limiter"/><link_ctn id="link_from_1_7_1_DOWN"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="bob_cluster_link_1_limiter"/>
+>   <link_ctn id="bob_cluster_link_3_limiter"/><link_ctn id="link_from_3_6_3_UP"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="link_from_6_4_10_UP"/><link_ctn id="link_from_7_4_7_DOWN"/><link_ctn id="bob_cluster_link_4_limiter"/><link_ctn id="link_from_1_7_1_DOWN"/><link_ctn id="bob_cluster_link_7_limiter"/><link_ctn id="bob_cluster_link_1_limiter"/>
 >   </route>
 >   <route src="node-120.simgrid.org" dst="node-119.simgrid.org">
 >   <link_ctn id="bob_cluster_link_3_limiter"/><link_ctn id="link_from_3_6_3_UP"/><link_ctn id="link_from_2_6_2_DOWN"/><link_ctn id="bob_cluster_link_6_limiter"/><link_ctn id="bob_cluster_link_2_limiter"/>
index 0b5bab8..8edee11 100644 (file)
@@ -50,7 +50,6 @@ set(tesh_files    ${tesh_files}     ${CMAKE_CURRENT_SOURCE_DIR}/coll-allreduce/c
                                     ${CMAKE_CURRENT_SOURCE_DIR}/coll-allreduce/coll-allreduce-papi.tesh
                                     ${CMAKE_CURRENT_SOURCE_DIR}/coll-allreduce-with-leaks/mc-coll-allreduce-with-leaks.tesh
                                     ${CMAKE_CURRENT_SOURCE_DIR}/coll-alltoall/clusters.tesh
-                                    ${CMAKE_CURRENT_SOURCE_DIR}/coll-alltoall/griffon.tesh
                                     ${CMAKE_CURRENT_SOURCE_DIR}/pt2pt-pingpong/broken_hostfiles.tesh
                                     ${CMAKE_CURRENT_SOURCE_DIR}/pt2pt-pingpong/TI_output.tesh
                                     ${CMAKE_CURRENT_SOURCE_DIR}/fort_args/fort_args.tesh  PARENT_SCOPE)
index 4ffce51..2010817 100644 (file)
@@ -2,11 +2,11 @@
 
 p Test allreduce
 $ $VALGRIND_NO_LEAK_CHECK ${bindir:=.}/../../../smpi_script/bin/smpirun -wrapper "${bindir:=.}/../../../bin/simgrid-mc" -map -hostfile ../hostfile_coll -platform  ${platfdir:=.}/small_platform.xml -np&